pheme 3.4.0 → 4.0.5

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: 04243d79c91d1f19e0e2e2e9d04290a3a9dafa5acd907eec7e2dc0d80c99e21c
4
- data.tar.gz: 9229a8eb9e453971f4b780954b7be9e770e784ffc6a129fbf331c232e9471247
3
+ metadata.gz: 2800b7391329c041eb8ab2e0253e3708f18cacb21458bbc210aa83e9b886685d
4
+ data.tar.gz: c3115082962233b0ae03a3b9f1ed6d67dd82e18d52417d1959b615f8ad074569
5
5
  SHA512:
6
- metadata.gz: bf5242abbfcc3b4ae522cbc0479c597d59a69835c33a1de2afe5e0a0eb70ef2afec4d73765367bb28c9c765ed702137f1d35117c5837e4eb3858a036ce5d6b5f
7
- data.tar.gz: 773072b1e6c9ab9ae6437ae5ff61effca1ac3a3a389c933df8970acc35dc7bae26af6af9e030d5ab371080f12c4d140ad5ce1e161d4bd98d6e71015449dc3781
6
+ metadata.gz: 185617f33efa34f653fd9aa203ebf83d2f68ec5e9ce30d841eff1e47b5a7ae001af60a8b686b1793cebcb456e4630d566b55a6f6f3ed2cc79e5d292ffc8404b7
7
+ data.tar.gz: 7c86ed02c4efd79e1fac0464eaffe1b7ac891d9d5b842b8ae38a0e8b17ca8934acf9ff12a8cb53ff156999c83dd63ce55bdf71c70d384bc9312f726782e29ea4
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: Pipeline
3
+ on:
4
+ push:
5
+ jobs:
6
+ build:
7
+ name: Build
8
+ runs-on: ubuntu-20.04
9
+ steps:
10
+ - uses: actions/checkout@v2
11
+ - uses: ruby/setup-ruby@v1
12
+ with:
13
+ bundler-cache: true
14
+ - name: Lint
15
+ run: bundle exec rubocop
16
+ - name: Test
17
+ run: bundle exec rspec
18
+ - name: Release the gem
19
+ if: ${{ github.ref == 'refs/heads/main' }}
20
+ run: |
21
+ mkdir -p ~/.gem
22
+ cat << EOF > ~/.gem/credentials
23
+ ---
24
+ :github: Bearer ${GITHUB_TOKEN}
25
+ :rubygems_api_key: ${RUBYGEMS_API_KEY}
26
+ EOF
27
+ chmod 0600 ~/.gem/credentials
28
+ git config user.email "noreply@wealthsimple.com"
29
+ git config user.name "Wolfbot"
30
+ bundle exec rake release
31
+ env:
32
+ RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
data/.gitignore CHANGED
@@ -28,7 +28,6 @@ build/
28
28
 
29
29
  # for a library or gem, you might want to ignore these files since the code is
30
30
  # intended to run in multiple environments; otherwise, check them in:
31
- Gemfile.lock
32
31
  .ruby-version
33
32
  .ruby-gemset
34
33
 
data/.rubocop.yml CHANGED
@@ -6,4 +6,4 @@ inherit_gem:
6
6
 
7
7
  AllCops:
8
8
  # Specify your target Ruby version here (only major/minor versions):
9
- TargetRubyVersion: 2.4
9
+ TargetRubyVersion: 2.7
data/.rubocop_todo.yml CHANGED
@@ -1,42 +1,42 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2019-07-09 13:48:32 -0400 using RuboCop version 0.72.0.
3
+ # on 2021-01-07 16:23:09 UTC using RuboCop version 1.6.1.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
+ # Offense count: 19
10
+ # Cop supports --auto-correct.
11
+ # Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
12
+ # URISchemes: http, https
13
+ Layout/LineLength:
14
+ Max: 147
15
+
9
16
  # Offense count: 2
17
+ # Configuration parameters: IgnoredMethods, CountRepeatedAttributes.
10
18
  Metrics/AbcSize:
11
19
  Max: 22
12
20
 
13
21
  # Offense count: 1
14
- # Configuration parameters: CountComments.
15
- Metrics/ClassLength:
16
- Max: 164
17
-
18
- # Offense count: 1
22
+ # Configuration parameters: IgnoredMethods.
19
23
  Metrics/CyclomaticComplexity:
20
24
  Max: 10
21
25
 
22
- # Offense count: 17
23
- # Cop supports --auto-correct.
24
- # Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
25
- # URISchemes: http, https
26
- Metrics/LineLength:
27
- Max: 147
28
-
29
26
  # Offense count: 3
30
- # Configuration parameters: CountComments, ExcludedMethods.
27
+ # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods.
28
+ # IgnoredMethods: extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended, extended
31
29
  Metrics/MethodLength:
32
30
  Max: 28
33
31
 
34
32
  # Offense count: 1
33
+ # Configuration parameters: IgnoredMethods.
35
34
  Metrics/PerceivedComplexity:
36
35
  Max: 11
37
36
 
38
- # Offense count: 5
39
- # Configuration parameters: CustomTransform, IgnoreMethods.
37
+ # Offense count: 9
38
+ # Configuration parameters: Include, CustomTransform, IgnoreMethods, SpecSuffixOnly.
39
+ # Include: **/*_spec*rb*, **/spec/**/*
40
40
  RSpec/FilePath:
41
41
  Exclude:
42
42
  - 'spec/configuration_spec.rb'
@@ -45,8 +45,8 @@ RSpec/FilePath:
45
45
  - 'spec/message_type/aws_event_spec.rb'
46
46
  - 'spec/message_type/sns_message_spec.rb'
47
47
  - 'spec/queue_poller_spec.rb'
48
- - 'spec/topic_publisher_spec.rb'
49
48
  - 'spec/rollbar_spec.rb'
49
+ - 'spec/topic_publisher_spec.rb'
50
50
  - 'spec/version_spec.rb'
51
51
 
52
52
  # Offense count: 14
@@ -70,3 +70,10 @@ RSpec/VerifiedDoubles:
70
70
  Style/GuardClause:
71
71
  Exclude:
72
72
  - 'lib/pheme/queue_poller.rb'
73
+
74
+ # Offense count: 2
75
+ # Cop supports --auto-correct.
76
+ Style/IfUnlessModifier:
77
+ Exclude:
78
+ - 'lib/pheme/queue_poller.rb'
79
+ - 'pheme.gemspec'
data/CHANGELOG.md CHANGED
@@ -4,6 +4,30 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## 4.0.5 - 2021-04-20
8
+ ### Changed
9
+ - Update dependencies
10
+
11
+ ## 4.0.4 - 2021-04-16
12
+ ### Changed
13
+ - Migrate CI from CircleCI to GitHub Actions
14
+
15
+ ## 4.0.3 - 2021-03-08
16
+ - Update documentation to include instructions on directly publishing to SQS
17
+
18
+ ## 4.0.2 - 2020-12-17
19
+ - Bump local dev version, rubocop fixes, add backstage catalog file + sonarqube project settings
20
+
21
+ ## 4.0.1 - 2020-03-23
22
+ ### Fixes
23
+ - Fixes 4.0.0. Instead of expecting message attributes in the message from `poll`, retrieves them from the right place.
24
+
25
+ ## 4.0.0 - 2020-03-18
26
+ ### Breaking Changes
27
+ - Add the ability for SQS to receive message attributes
28
+ - `handle` function of `QueuePoller` now takes a third parameter `message_attributes`
29
+ - blocks or `MessageHandler`s passed to `QueuePoller` can use this `message_attributes`
30
+
7
31
  ## 3.4.0 - 2020-03-17
8
32
  ### Added
9
33
  - Add the ability to pass message attributes to SNS
data/Gemfile.lock ADDED
@@ -0,0 +1,138 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ pheme (4.0.5)
5
+ activesupport (>= 4)
6
+ aws-sdk-sns (~> 1.1)
7
+ aws-sdk-sqs (~> 1.3)
8
+ recursive-open-struct (~> 1)
9
+ smarter_csv (~> 1)
10
+
11
+ GEM
12
+ remote: https://rubygems.org/
13
+ specs:
14
+ activesupport (6.1.3.1)
15
+ concurrent-ruby (~> 1.0, >= 1.0.2)
16
+ i18n (>= 1.6, < 2)
17
+ minitest (>= 5.1)
18
+ tzinfo (~> 2.0)
19
+ zeitwerk (~> 2.3)
20
+ ast (2.4.2)
21
+ aws-eventstream (1.1.1)
22
+ aws-partitions (1.446.0)
23
+ aws-sdk-core (3.114.0)
24
+ aws-eventstream (~> 1, >= 1.0.2)
25
+ aws-partitions (~> 1, >= 1.239.0)
26
+ aws-sigv4 (~> 1.1)
27
+ jmespath (~> 1.0)
28
+ aws-sdk-sns (1.39.0)
29
+ aws-sdk-core (~> 3, >= 3.112.0)
30
+ aws-sigv4 (~> 1.1)
31
+ aws-sdk-sqs (1.38.0)
32
+ aws-sdk-core (~> 3, >= 3.112.0)
33
+ aws-sigv4 (~> 1.1)
34
+ aws-sigv4 (1.2.3)
35
+ aws-eventstream (~> 1, >= 1.0.2)
36
+ bundler-audit (0.8.0)
37
+ bundler (>= 1.2.0, < 3)
38
+ thor (~> 1.0)
39
+ concurrent-ruby (1.1.8)
40
+ diff-lcs (1.4.4)
41
+ docile (1.3.5)
42
+ git (1.8.1)
43
+ rchardet (~> 1.8)
44
+ i18n (1.8.10)
45
+ concurrent-ruby (~> 1.0)
46
+ jmespath (1.4.0)
47
+ json (2.5.1)
48
+ minitest (5.14.4)
49
+ parallel (1.20.1)
50
+ parser (3.0.1.0)
51
+ ast (~> 2.4.1)
52
+ rack (2.2.3)
53
+ rainbow (3.0.0)
54
+ rake (13.0.3)
55
+ rchardet (1.8.0)
56
+ recursive-open-struct (1.1.3)
57
+ regexp_parser (2.1.1)
58
+ rexml (3.2.5)
59
+ rspec (3.10.0)
60
+ rspec-core (~> 3.10.0)
61
+ rspec-expectations (~> 3.10.0)
62
+ rspec-mocks (~> 3.10.0)
63
+ rspec-collection_matchers (1.2.0)
64
+ rspec-expectations (>= 2.99.0.beta1)
65
+ rspec-core (3.10.1)
66
+ rspec-support (~> 3.10.0)
67
+ rspec-expectations (3.10.1)
68
+ diff-lcs (>= 1.2.0, < 2.0)
69
+ rspec-support (~> 3.10.0)
70
+ rspec-its (1.3.0)
71
+ rspec-core (>= 3.0.0)
72
+ rspec-expectations (>= 3.0.0)
73
+ rspec-mocks (3.10.2)
74
+ diff-lcs (>= 1.2.0, < 2.0)
75
+ rspec-support (~> 3.10.0)
76
+ rspec-support (3.10.2)
77
+ rspec_junit_formatter (0.4.1)
78
+ rspec-core (>= 2, < 4, != 2.12.0)
79
+ rubocop (1.12.1)
80
+ parallel (~> 1.10)
81
+ parser (>= 3.0.0.0)
82
+ rainbow (>= 2.2.2, < 4.0)
83
+ regexp_parser (>= 1.8, < 3.0)
84
+ rexml
85
+ rubocop-ast (>= 1.2.0, < 2.0)
86
+ ruby-progressbar (~> 1.7)
87
+ unicode-display_width (>= 1.4.0, < 3.0)
88
+ rubocop-ast (1.4.1)
89
+ parser (>= 2.7.1.5)
90
+ rubocop-performance (1.10.2)
91
+ rubocop (>= 0.90.0, < 2.0)
92
+ rubocop-ast (>= 0.4.0)
93
+ rubocop-rails (2.9.1)
94
+ activesupport (>= 4.2.0)
95
+ rack (>= 1.1)
96
+ rubocop (>= 0.90.0, < 2.0)
97
+ rubocop-rspec (2.2.0)
98
+ rubocop (~> 1.0)
99
+ rubocop-ast (>= 1.1.0)
100
+ rubocop-vendor (0.6.0)
101
+ rubocop (>= 0.53.0)
102
+ ruby-progressbar (1.11.0)
103
+ simplecov (0.16.1)
104
+ docile (~> 1.1)
105
+ json (>= 1.8, < 3)
106
+ simplecov-html (~> 0.10.0)
107
+ simplecov-html (0.10.2)
108
+ smarter_csv (1.2.8)
109
+ thor (1.1.0)
110
+ tzinfo (2.0.4)
111
+ concurrent-ruby (~> 1.0)
112
+ unicode-display_width (2.0.0)
113
+ ws-style (6.9.0)
114
+ rubocop (>= 1.12.1)
115
+ rubocop-performance (>= 1.10.2)
116
+ rubocop-rails (>= 2.9.1)
117
+ rubocop-rspec (>= 2.2.0)
118
+ rubocop-vendor (>= 0.6.0)
119
+ zeitwerk (2.4.2)
120
+
121
+ PLATFORMS
122
+ ruby
123
+
124
+ DEPENDENCIES
125
+ bundler
126
+ bundler-audit
127
+ git
128
+ pheme!
129
+ rake
130
+ rspec
131
+ rspec-collection_matchers
132
+ rspec-its
133
+ rspec_junit_formatter (~> 0.2)
134
+ simplecov
135
+ ws-style
136
+
137
+ BUNDLED WITH
138
+ 2.2.16
data/README.md CHANGED
@@ -1,4 +1,7 @@
1
- # pheme [![CircleCI](https://circleci.com/gh/wealthsimple/pheme.svg?style=svg&circle-token=76942be0b1712ac066627be264886ee18039ad11)](https://circleci.com/gh/wealthsimple/pheme) [![Coverage Status](https://coveralls.io/repos/github/wealthsimple/pheme/badge.svg)](https://coveralls.io/github/wealthsimple/pheme)
1
+ # pheme
2
+ [![Github Actions Badge](https://github.com/wealthsimple/pheme/actions/workflows/main.yml/badge.svg)](https://github.com/wealthsimple/pheme/actions)
3
+
4
+ [![GitHub Actions Workflow Badge](https://github.com/wealthsimple/pheme/actions/workflows/master-workflow.yml/badge.svg)](https://github.com/wealthsimple/pheme/actions)
2
5
 
3
6
  Ruby SNS publisher + SQS poller & message handler
4
7
 
@@ -39,3 +42,9 @@ end
39
42
  See https://github.com/wealthsimple/pheme/tree/master/spec/support for example implementations of each class.
40
43
 
41
44
  TODO: write better usage instructions.
45
+
46
+ ### Handling SQS messages
47
+
48
+ Pheme expects that the SQS messages it is handling will have first been published to an SNS topic
49
+ before being sent to the SQS queue. This means if the service publishing messages is publishing them
50
+ **directly** to the SQS queue, that service must nest the message payload underneath a `Message` property.
data/catalog-info.yaml ADDED
@@ -0,0 +1,12 @@
1
+ ---
2
+ apiVersion: backstage.io/v1alpha1
3
+ kind: Component
4
+ metadata:
5
+ name: pheme
6
+ description: Ruby SNS publisher + SQS message handler
7
+ tags:
8
+ - ruby
9
+ - open-source
10
+ spec:
11
+ type: library
12
+ lifecycle: production
@@ -19,8 +19,7 @@ module Pheme
19
19
  ATTRIBUTES = %i[sns_client sqs_client logger].freeze
20
20
  OPTIONAL_ATTRIBUTES = %i[rollbar].freeze
21
21
 
22
- attr_accessor(*ATTRIBUTES)
23
- attr_accessor(*OPTIONAL_ATTRIBUTES)
22
+ attr_accessor(*ATTRIBUTES, *OPTIONAL_ATTRIBUTES)
24
23
 
25
24
  def initialize
26
25
  @logger ||= Logger.new(STDOUT) # rubocop:disable Lint/DisjunctiveAssignmentInConstructor
@@ -1,10 +1,11 @@
1
1
  module Pheme
2
2
  class MessageHandler
3
- attr_reader :message, :metadata, :timestamp
3
+ attr_reader :message, :metadata, :message_attributes, :timestamp
4
4
 
5
- def initialize(message:, metadata: {})
5
+ def initialize(message:, metadata: {}, message_attributes: {})
6
6
  @message = message
7
7
  @metadata = metadata
8
+ @message_attributes = message_attributes
8
9
  end
9
10
 
10
11
  def handle
@@ -1,6 +1,7 @@
1
1
  require_relative 'compression'
2
2
 
3
3
  module Pheme
4
+ # rubocop:disable Metrics/ClassLength
4
5
  class QueuePoller
5
6
  include Compression
6
7
 
@@ -51,28 +52,29 @@ module Pheme
51
52
  end
52
53
  end
53
54
 
55
+ # rubocop:disable Metrics/AbcSize
54
56
  def poll
55
57
  time_start = log_polling_start
56
58
  queue_poller.poll(poller_configuration) do |queue_message|
57
59
  @messages_received += 1
58
60
  Pheme.logger.tagged(queue_message.message_id) do
59
- begin
60
- content = parse_body(queue_message)
61
- metadata = parse_metadata(queue_message)
62
- with_optional_connection_pool_block { handle(content, metadata) }
63
- queue_poller.delete_message(queue_message)
64
- log_delete(queue_message)
65
- @messages_processed += 1
66
- rescue SignalException
67
- throw :stop_polling
68
- rescue StandardError => e
69
- Pheme.logger.error(e)
70
- Pheme.rollbar(e, "#{self.class} failed to process message", { message: content })
71
- end
61
+ content = parse_body(queue_message)
62
+ metadata = parse_metadata(queue_message)
63
+ message_attributes = parse_message_attributes(queue_message)
64
+ with_optional_connection_pool_block { handle(content, metadata, message_attributes) }
65
+ queue_poller.delete_message(queue_message)
66
+ log_delete(queue_message)
67
+ @messages_processed += 1
68
+ rescue SignalException
69
+ throw :stop_polling
70
+ rescue StandardError => e
71
+ Pheme.logger.error(e)
72
+ Pheme.rollbar(e, "#{self.class} failed to process message", { message: content })
72
73
  end
73
74
  end
74
75
  log_polling_end(time_start)
75
76
  end
77
+ # rubocop:enable Metrics/AbcSize
76
78
 
77
79
  # returns queue_message.body as hash,
78
80
  # stores and parses get_content to body[:content]
@@ -105,6 +107,16 @@ module Pheme
105
107
  { timestamp: message_body['Timestamp'], topic_arn: message_body['TopicArn'] }
106
108
  end
107
109
 
110
+ def parse_message_attributes(queue_message)
111
+ message_body = JSON.parse(queue_message.body)
112
+ message_attributes = {}
113
+ message_body['MessageAttributes']&.each do |key, value|
114
+ message_attributes[key.to_sym] = coerce_message_attribute(value)
115
+ end
116
+
117
+ message_attributes
118
+ end
119
+
108
120
  def get_metadata(message_body)
109
121
  message_body.except('Message', 'Records')
110
122
  end
@@ -123,11 +135,11 @@ module Pheme
123
135
  RecursiveOpenStruct.new({ wrapper: parsed_body }, recurse_over_arrays: true).wrapper
124
136
  end
125
137
 
126
- def handle(message, metadata)
138
+ def handle(message, metadata, message_attributes)
127
139
  if @message_handler
128
- @message_handler.new(message: message, metadata: metadata).handle
140
+ @message_handler.new(message: message, metadata: metadata, message_attributes: message_attributes).handle
129
141
  elsif @block_message_handler
130
- @block_message_handler.call(message, metadata)
142
+ @block_message_handler.call(message, metadata, message_attributes)
131
143
  else
132
144
  raise NotImplementedError
133
145
  end
@@ -135,9 +147,21 @@ module Pheme
135
147
 
136
148
  private
137
149
 
138
- def with_optional_connection_pool_block
150
+ def coerce_message_attribute(value)
151
+ case value['Type']
152
+ when 'Binary', 'String'
153
+ value['Value']
154
+ when 'Number', 'String.Array'
155
+ JSON.parse(value['Value'])
156
+ else
157
+ Pheme.logger.info("Unsupported custom data type")
158
+ value["Value"]
159
+ end
160
+ end
161
+
162
+ def with_optional_connection_pool_block(&block)
139
163
  if connection_pool_block
140
- ActiveRecord::Base.connection_pool.with_connection { yield }
164
+ ActiveRecord::Base.connection_pool.with_connection(&block)
141
165
  else
142
166
  yield
143
167
  end
@@ -192,4 +216,5 @@ module Pheme
192
216
  }.to_json)
193
217
  end
194
218
  end
219
+ # rubocop:enable Metrics/ClassLength
195
220
  end
data/lib/pheme/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Pheme
2
- VERSION = '3.4.0'.freeze
2
+ VERSION = '4.0.5'.freeze
3
3
  end
data/pheme.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.require_paths = ["lib"]
21
21
  s.license = "MIT"
22
22
 
23
- s.required_ruby_version = '>= 2.4'
23
+ s.required_ruby_version = '>= 2.7.3'
24
24
 
25
25
  s.add_dependency "activesupport", ">= 4"
26
26
  s.add_dependency "aws-sdk-sns", "~> 1.1"
@@ -29,7 +29,6 @@ Gem::Specification.new do |s|
29
29
  s.add_dependency "smarter_csv", "~> 1"
30
30
 
31
31
  s.add_development_dependency 'bundler'
32
- s.add_development_dependency 'coveralls'
33
32
  s.add_development_dependency 'git'
34
33
  s.add_development_dependency 'rake'
35
34
  s.add_development_dependency 'rspec'
@@ -0,0 +1,4 @@
1
+ sonar.projectKey=pheme
2
+ sonar.ruby.coverage.reportPaths=coverage/.resultset.json
3
+ sonar.sources=lib
4
+ sonar.tests=spec
@@ -14,7 +14,7 @@ describe Pheme::QueuePoller do
14
14
  let(:message_id) { SecureRandom.uuid }
15
15
 
16
16
  context 'base poller' do
17
- subject { described_class.new(queue_url: queue_url).handle(nil, nil) }
17
+ subject { described_class.new(queue_url: queue_url).handle(nil, nil, nil) }
18
18
 
19
19
  it 'does not implement handle' do
20
20
  expect { subject }.to raise_error(NotImplementedError)
@@ -90,13 +90,13 @@ describe Pheme::QueuePoller do
90
90
  context 'when handling messages' do
91
91
  context 'when doing it the old way, via the handle function' do
92
92
  it 'uses the handle function by default' do
93
- expect { described_class.new(queue_url: queue_url).handle(nil, nil) }.to raise_error(NotImplementedError)
93
+ expect { described_class.new(queue_url: queue_url).handle(nil, nil, nil) }.to raise_error(NotImplementedError)
94
94
  end
95
95
  end
96
96
 
97
97
  context 'when given a message_handler as parameter' do
98
98
  it 'uses default when given nil' do
99
- expect { described_class.new(queue_url: queue_url, message_handler: nil).handle(nil, nil) }.to raise_error(NotImplementedError)
99
+ expect { described_class.new(queue_url: queue_url, message_handler: nil).handle(nil, nil, nil) }.to raise_error(NotImplementedError)
100
100
  end
101
101
 
102
102
  it 'uses default when given invalid message_handler' do
@@ -106,9 +106,11 @@ describe Pheme::QueuePoller do
106
106
  it 'uses handler when given one' do
107
107
  mock_handler = double('MessageHandler')
108
108
  allow(mock_handler).to receive(:handle)
109
- allow(ExampleMessageHandler).to receive(:new).with(message: 'message', metadata: 'metadata').and_return(mock_handler)
109
+ allow(ExampleMessageHandler).to receive(:new).
110
+ with(message: 'message', metadata: 'metadata', message_attributes: 'message_attributes').
111
+ and_return(mock_handler)
110
112
 
111
- described_class.new(queue_url: queue_url, message_handler: ExampleMessageHandler).handle('message', 'metadata')
113
+ described_class.new(queue_url: queue_url, message_handler: ExampleMessageHandler).handle('message', 'metadata', 'message_attributes')
112
114
  expect(mock_handler).to have_received(:handle).once
113
115
  end
114
116
  end
@@ -117,12 +119,12 @@ describe Pheme::QueuePoller do
117
119
  it 'uses handler when given one' do
118
120
  mock_handler = spy('MessageHandler')
119
121
 
120
- poller = described_class.new(queue_url: queue_url) do |message, metadata|
121
- mock_handler.process(message, metadata)
122
+ poller = described_class.new(queue_url: queue_url) do |message, metadata, message_attributes|
123
+ mock_handler.process(message, metadata, message_attributes)
122
124
  end
123
- poller.handle('message', 'metadata')
125
+ poller.handle('message', 'metadata', 'message_attributes')
124
126
 
125
- expect(mock_handler).to have_received(:process).with('message', 'metadata').once
127
+ expect(mock_handler).to have_received(:process).with('message', 'metadata', 'message_attributes').once
126
128
  end
127
129
 
128
130
  it 'fails on invalid handler' do
@@ -134,6 +136,62 @@ describe Pheme::QueuePoller do
134
136
  end
135
137
  end
136
138
 
139
+ describe '#parse_message_attributes' do
140
+ subject { described_class.new(queue_url: queue_url).parse_message_attributes(queue_message) }
141
+
142
+ context 'when no message_attributes' do
143
+ it { is_expected.to eq({}) }
144
+ end
145
+
146
+ context 'when message attributes' do
147
+ let(:queue_message) do
148
+ OpenStruct.new(
149
+ body: {
150
+ Message: message,
151
+ MessageAttributes: {
152
+ key: { Type: data_type, Value: string_value },
153
+ },
154
+ }.to_json,
155
+ message_id: message_id,
156
+ )
157
+ end
158
+
159
+ context 'when data_type is String' do
160
+ let(:data_type) { 'String' }
161
+ let(:string_value) { 'some-string-value' }
162
+ let(:expected_value) { 'some-string-value' }
163
+
164
+ its([:key]) { is_expected.to eq(expected_value) }
165
+ end
166
+
167
+ context 'when data_type is Number' do
168
+ let(:data_type) { 'Number' }
169
+
170
+ context 'and it is an int' do
171
+ let(:string_value) { '1' }
172
+ let(:expected_value) { 1 }
173
+
174
+ its([:key]) { is_expected.to eq(expected_value) }
175
+ end
176
+
177
+ context 'and it is a float' do
178
+ let(:string_value) { '1.5' }
179
+ let(:expected_value) { 1.5 }
180
+
181
+ its([:key]) { is_expected.to eq(expected_value) }
182
+ end
183
+ end
184
+
185
+ context 'when data_type is String.array' do
186
+ let(:data_type) { 'String.Array' }
187
+ let(:string_value) { '["sdfsdf",1,2,null,true,false]' }
188
+ let(:expected_value) { ["sdfsdf", 1, 2, nil, true, false] }
189
+
190
+ its([:key]) { is_expected.to eq(expected_value) }
191
+ end
192
+ end
193
+ end
194
+
137
195
  describe "#parse_body" do
138
196
  subject { poller.parse_body(queue_message) }
139
197
 
@@ -305,6 +363,7 @@ describe Pheme::QueuePoller do
305
363
  expect(ExampleMessageHandler).to receive(:new).with(
306
364
  message: RecursiveOpenStruct.new(message),
307
365
  metadata: { timestamp: timestamp, topic_arn: topic_arn },
366
+ message_attributes: {},
308
367
  )
309
368
  subject.poll
310
369
  end
@@ -359,7 +418,7 @@ describe Pheme::QueuePoller do
359
418
 
360
419
  let(:queue_message) { OpenStruct.new(body: { 'Records' => records }.to_json) }
361
420
  let(:records) do
362
- [{ 'eventVersion' => '2.0', 'eventSource': 'aws:s3' }]
421
+ [{ 'eventVersion' => '2.0', eventSource: 'aws:s3' }]
363
422
  end
364
423
 
365
424
  before do
data/spec/spec_helper.rb CHANGED
@@ -1,10 +1,5 @@
1
1
  require 'simplecov'
2
- require 'coveralls'
3
2
 
4
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
5
- SimpleCov::Formatter::HTMLFormatter,
6
- Coveralls::SimpleCov::Formatter,
7
- ])
8
3
  SimpleCov.start do
9
4
  add_filter 'spec'
10
5
  end
@@ -3,10 +3,10 @@ class ExampleQueuePoller < Pheme::QueuePoller
3
3
  super(queue_url: queue_url, **kwargs)
4
4
  end
5
5
 
6
- def handle(message, metadata)
6
+ def handle(message, metadata, message_attributes)
7
7
  case message.status
8
8
  when 'complete', 'rejected'
9
- ExampleMessageHandler.new(message: message, metadata: metadata).handle
9
+ ExampleMessageHandler.new(message: message, metadata: metadata, message_attributes: message_attributes).handle
10
10
  else
11
11
  raise ArgumentError, "Unknown message status: #{message.status}"
12
12
  end
@@ -1,5 +1,6 @@
1
- Pheme::QueuePoller.new(queue_url: 'http://mock_url.test') do |message, metadata|
1
+ Pheme::QueuePoller.new(queue_url: 'http://mock_url.test') do |message, metadata, message_attributes|
2
2
  # handle the message
3
3
  pp message
4
4
  pp metadata
5
+ pp message_attributes
5
6
  end
data/spec/version_spec.rb CHANGED
@@ -4,7 +4,7 @@ describe Pheme do
4
4
  def get_version(git, branch = 'HEAD')
5
5
  git.grep('VERSION = ', 'lib/*/version.rb', { object: branch }).
6
6
  map { |_sha, matches| matches.first[1] }.
7
- map(&method(:parse_version)).
7
+ map { |version_string| parse_version(version_string) }.
8
8
  reject(&:nil?).
9
9
  first
10
10
  end
@@ -21,14 +21,12 @@ describe Pheme do
21
21
 
22
22
  it 'has a bumped version' do
23
23
  git = Git.open('.')
24
- skip('already on master branch, no need to compare versions') if git.current_branch == 'master'
24
+ main_version = get_version(git, 'origin/main')
25
+ skip('first time publishing, no need to compare versions') if main_version.nil?
25
26
 
26
- head_version = get_version(git, 'HEAD')
27
- master_version = get_version(git, 'origin/master')
28
-
29
- raise 'no version.rb file found on the current branch' if head_version.nil?
30
- raise 'no version.rb file found on the master branch' if master_version.nil?
27
+ is_main_branch = git.current_branch == 'main'
28
+ skip('already on main branch, no need to compare versions') if is_main_branch
31
29
 
32
- expect(Gem::Version.new(head_version)).to be > Gem::Version.new(master_version)
30
+ expect(Gem::Version.new(head_version)).to be > Gem::Version.new(main_version)
33
31
  end
34
32
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pheme
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.0
4
+ version: 4.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Graham
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-18 00:00:00.000000000 Z
11
+ date: 2021-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -94,20 +94,6 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: coveralls
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
97
  - !ruby/object:Gem::Dependency
112
98
  name: git
113
99
  requirement: !ruby/object:Gem::Requirement
@@ -227,9 +213,9 @@ executables: []
227
213
  extensions: []
228
214
  extra_rdoc_files: []
229
215
  files:
230
- - ".circleci/config.yml"
231
216
  - ".github/CODEOWNERS"
232
217
  - ".github/PULL_REQUEST_TEMPLATE.md"
218
+ - ".github/workflows/main.yml"
233
219
  - ".gitignore"
234
220
  - ".rspec"
235
221
  - ".rubocop.yml"
@@ -237,9 +223,11 @@ files:
237
223
  - ".ruby-version"
238
224
  - CHANGELOG.md
239
225
  - Gemfile
226
+ - Gemfile.lock
240
227
  - LICENSE
241
228
  - README.md
242
229
  - Rakefile
230
+ - catalog-info.yaml
243
231
  - lib/pheme.rb
244
232
  - lib/pheme/compression.rb
245
233
  - lib/pheme/configuration.rb
@@ -252,6 +240,7 @@ files:
252
240
  - lib/pheme/topic_publisher.rb
253
241
  - lib/pheme/version.rb
254
242
  - pheme.gemspec
243
+ - sonar-project.properties
255
244
  - spec/configuration_spec.rb
256
245
  - spec/logger_spec.rb
257
246
  - spec/message_handler_spec.rb
@@ -281,15 +270,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
281
270
  requirements:
282
271
  - - ">="
283
272
  - !ruby/object:Gem::Version
284
- version: '2.4'
273
+ version: 2.7.3
285
274
  required_rubygems_version: !ruby/object:Gem::Requirement
286
275
  requirements:
287
276
  - - ">="
288
277
  - !ruby/object:Gem::Version
289
278
  version: '0'
290
279
  requirements: []
291
- rubyforge_project:
292
- rubygems_version: 2.7.6
280
+ rubygems_version: 3.1.6
293
281
  signing_key:
294
282
  specification_version: 4
295
283
  summary: Ruby SNS publisher + SQS poller & message handler
data/.circleci/config.yml DELETED
@@ -1,149 +0,0 @@
1
- version: 2
2
-
3
- references:
4
- defaults:
5
- 2_4_5: &defaults_2_4_5
6
- working_directory: ~/wealthsimple
7
- docker:
8
- - image: circleci/ruby:2.4.5
9
- environment:
10
- RAILS_ENV: test
11
-
12
- 2_5_3: &defaults
13
- working_directory: ~/wealthsimple
14
- docker:
15
- - image: circleci/ruby:2.5.3
16
- environment:
17
- RAILS_ENV: test
18
-
19
- which_bundler: &which_bundler
20
- run:
21
- name: Which bundler?
22
- command: bundle -v
23
-
24
- bundle_install: &bundle_install
25
- run:
26
- name: Bundle Install
27
- command: bundle install --jobs=4 --retry=3 --path vendor/bundle
28
-
29
- attach_code_workspace: &attach_code_workspace
30
- attach_workspace:
31
- at: ~/wealthsimple
32
-
33
- restore_bundle_dependencies: &restore_bundle_dependencies
34
- run:
35
- name: Restore bundle dependencies from workspace
36
- command: bundle --path vendor/bundle
37
-
38
- run_rspec: &run_rspec
39
- run:
40
- name: Run rspec
41
- command: |
42
- bundle exec rspec \
43
- --require spec_helper \
44
- --format RspecJunitFormatter \
45
- --out test_results/rspec.xml \
46
- --format documentation
47
-
48
- jobs:
49
- checkout_and_bundle_2_4_5:
50
- <<: *defaults_2_4_5
51
- environment:
52
- COVERALLS_REPO_TOKEN: ''
53
- steps:
54
- - checkout
55
- - *which_bundler
56
- - *bundle_install
57
- - *run_rspec
58
- - store_test_results:
59
- path: test_results
60
-
61
- checkout_and_bundle:
62
- <<: *defaults
63
- steps:
64
- - checkout
65
- - *which_bundler
66
- - *bundle_install
67
- - persist_to_workspace:
68
- root: .
69
- paths: .
70
-
71
- rspec:
72
- <<: *defaults
73
- steps:
74
- - *attach_code_workspace
75
- - *restore_bundle_dependencies
76
- - *run_rspec
77
- - store_test_results:
78
- path: test_results
79
-
80
- lint_check:
81
- <<: *defaults
82
- steps:
83
- - *attach_code_workspace
84
- - *restore_bundle_dependencies
85
- - run: bundle exec rubocop
86
-
87
- vulnerability_check:
88
- <<: *defaults
89
- steps:
90
- - *attach_code_workspace
91
- - *restore_bundle_dependencies
92
- - run: bundle exec bundle-audit update && bundle exec bundle-audit check
93
-
94
- release:
95
- <<: *defaults
96
- steps:
97
- - checkout
98
- - *attach_code_workspace
99
- - *restore_bundle_dependencies
100
- - run:
101
- name: Release to rubygems.org
102
- command: |
103
- mkdir ~/.gem
104
- echo ":rubygems_api_key: ${RUBYGEMS_API_KEY}" >> ~/.gem/credentials
105
- chmod 600 ~/.gem/credentials
106
- bundle exec rake release
107
-
108
- workflows:
109
- version: 2
110
- build:
111
- jobs:
112
- - checkout_and_bundle_2_4_5:
113
- context: wealthsimple
114
- - checkout_and_bundle:
115
- context: wealthsimple
116
- - rspec:
117
- requires:
118
- - checkout_and_bundle
119
- - lint_check:
120
- requires:
121
- - checkout_and_bundle
122
- - vulnerability_check:
123
- requires:
124
- - checkout_and_bundle
125
- - release:
126
- context: wealthsimple
127
- filters:
128
- branches:
129
- only: master
130
- requires:
131
- - checkout_and_bundle_2_4_5
132
- - rspec
133
- - lint_check
134
- - vulnerability_check
135
-
136
- security-audit:
137
- triggers:
138
- - schedule:
139
- # 11:05 am UTC: 6:05 am EST / 7:05 am EDT
140
- cron: "5 11 * * *"
141
- filters:
142
- branches:
143
- only: master
144
- jobs:
145
- - checkout_and_bundle:
146
- context: wealthsimple
147
- - vulnerability_check:
148
- requires:
149
- - checkout_and_bundle