pliny 0.29.0 → 0.32.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: e47d761bd19ec78a4558b81ab7018a268bea25545895a67c07f21623699c21ba
4
- data.tar.gz: ee9b112e0a31a4e9646d3e60b02f8c8538440c770dae8c6376031bbad285b7dd
3
+ metadata.gz: 8de7550e51b73562d5fbf52d648945f5f07925cc5df89b5526faba9fc5b27075
4
+ data.tar.gz: 46f1ed81d71d0b9b70332085bc6dc61038a98d8f66ba2645db6651f355f85fd4
5
5
  SHA512:
6
- metadata.gz: 3e5682954ac33fa5b7231c50cc59101c4fe811611e21cdc9ffc0eb06d586281692d5bc6c9231f0d553cc4b3cc275640b953cd239d219c46576d2425725f92f72
7
- data.tar.gz: 0be3d40932b255ca70c0101cfd20a5680d5bc01fd61d8d448d27ca9f4c52043d25ec48af172122f30ab28ef4a37315c37f28358feec36edebcf7bf068a24560d
6
+ metadata.gz: 90130887007a82d06b841e6e4ca27f0f242f24eb782f273037a50a849d8a8a19ce73b7d4fb42ee75bc983b8cdfac57f02057e6322d11ab00678ef5c51b2d8d13
7
+ data.tar.gz: a77f028909da4a10a07db20f96e3fa872c351114395adbbbe500a1106bc0b3882676bdd94fbb52ec91a23676ba92cce2b84a76277a385321f29c16c64ede2fc1
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # Pliny
2
2
 
3
3
  [![Gem version](http://img.shields.io/gem/v/pliny.svg)](https://rubygems.org/gems/pliny)
4
- [![Build Status](https://travis-ci.org/interagent/pliny.svg?branch=master)](https://travis-ci.org/interagent/pliny)
4
+ [![Github Actions CI](https://github.com/interagent/pliny/actions/workflows/ruby.yml/badge.svg)](https://github.com/interagent/pliny/actions)
5
+
5
6
 
6
7
  Pliny helps Ruby developers write and maintain excellent APIs.
7
8
 
@@ -46,25 +46,171 @@ module Pliny
46
46
  db.run(%{CREATE DATABASE "#{name}"})
47
47
  end
48
48
 
49
- def migrate(target=nil)
50
- Sequel::Migrator.apply(db, "./db/migrate", target)
49
+ def migrate(target = nil)
50
+ Sequel::Migrator.apply(db, MIGRATION_DIR, target)
51
+ end
52
+
53
+ def version
54
+ return 0 unless db.table_exists?(:schema_migrations)
55
+
56
+ current = db[:schema_migrations].order(Sequel.desc(:filename)).first
57
+
58
+ return 0 unless current
59
+
60
+ version = current[:filename].match(Sequel::Migrator::MIGRATION_FILE_PATTERN).captures.first
61
+ version ||= 0
62
+ Integer(version)
63
+ end
64
+
65
+ class MigrationStatus
66
+ attr_reader :filename
67
+ attr_accessor :present_on_disk, :present_in_database
68
+
69
+ def initialize(filename:)
70
+ @filename = filename
71
+ @present_on_disk = false
72
+ @present_in_database = false
73
+ end
74
+
75
+ def status
76
+ if present_on_disk
77
+ if present_in_database
78
+ :up
79
+ else
80
+ :down
81
+ end
82
+ else
83
+ if present_in_database
84
+ :file_missing
85
+ else
86
+ raise "error" # FIXME: better message
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ class MigrationStatusPresenter
93
+ PADDING = 2
94
+ UP = "UP".freeze
95
+ DOWN = "DOWN".freeze
96
+ FILE_MISSING = "FILE MISSING".freeze
97
+
98
+ STATUS_MAP = {
99
+ up: UP,
100
+ down: DOWN,
101
+ file_missing: FILE_MISSING
102
+ }.freeze
103
+
104
+ STATUS_OPTIONS = [
105
+ UP,
106
+ DOWN,
107
+ FILE_MISSING
108
+ ].freeze
109
+
110
+ attr_reader :migration_statuses
111
+
112
+ def initialize(migration_statuses:)
113
+ @migration_statuses = migration_statuses
114
+ end
115
+
116
+ def to_s
117
+ rows.join("\n")
118
+ end
119
+
120
+ def rows
121
+ header + statuses + footer
122
+ end
123
+
124
+ def header
125
+ [
126
+ barrier_row,
127
+ header_row,
128
+ barrier_row
129
+ ]
130
+ end
131
+
132
+ def statuses
133
+ migration_statuses.map { |status|
134
+ status_row(status)
135
+ }
136
+ end
137
+
138
+ def footer
139
+ [
140
+ barrier_row
141
+ ]
142
+ end
143
+
144
+ def barrier_row
145
+ "+#{'-' * (longest_status + PADDING)}+#{'-' * (longest_migration_name + PADDING)}+"
146
+ end
147
+
148
+ def header_row
149
+ "|#{'STATUS'.center(longest_status + PADDING)}|#{'MIGRATION'.center(longest_migration_name + PADDING)}|"
150
+ end
151
+
152
+ def status_row(migration_status)
153
+ "|#{STATUS_MAP[migration_status.status].center(longest_status + PADDING)}|#{' ' * (PADDING / 2)}#{migration_status.filename.ljust(longest_migration_name)}#{' ' * (PADDING / 2)}|"
154
+ end
155
+
156
+ private
157
+
158
+ def longest_migration_name
159
+ @longest_migration_name ||= migration_statuses.map(&:filename).max_by(&:length).length
160
+ end
161
+
162
+ def longest_status
163
+ STATUS_OPTIONS.max_by(&:length).length
164
+ end
165
+ end
166
+
167
+ def status
168
+ migrations_in_database = get_migrations_from_database
169
+ migrations_on_disk = Dir["#{MIGRATION_DIR}/*.rb"].map { |f| File.basename(f) }
170
+ total_set_of_migrations = (migrations_in_database | migrations_on_disk).sort_by(&:to_i)
171
+
172
+ migration_statuses = total_set_of_migrations.map { |filename|
173
+ status = MigrationStatus.new(filename: filename)
174
+ if migrations_on_disk.include?(filename)
175
+ status.present_on_disk = true
176
+ end
177
+
178
+ if migrations_in_database.include?(filename)
179
+ status.present_in_database = true
180
+ end
181
+ status
182
+ }
183
+
184
+ MigrationStatusPresenter.new(migration_statuses: migration_statuses).to_s
185
+ end
186
+
187
+ def get_migrations_from_database
188
+ return [] unless db.table_exists?(:schema_migrations)
189
+
190
+ db[:schema_migrations].order(Sequel.asc(:filename)).select_map(:filename)
51
191
  end
52
192
 
53
193
  def rollback
54
- return unless db.tables.include?(:schema_migrations)
55
- return unless current = db[:schema_migrations].order(Sequel.desc(:filename)).first
194
+ current_version = version
195
+ return if current_version.zero?
56
196
 
57
- migrations = Dir["./db/migrate/*.rb"].map { |f| File.basename(f).to_i }.sort
58
- target = 0 # by default, rollback everything
59
- index = migrations.index(current[:filename].to_i)
197
+ migrations = Dir["#{MIGRATION_DIR}/*.rb"].map { |f| File.basename(f).to_i }.sort
198
+
199
+ target = 0 # by default, rollback everything
200
+ index = migrations.index(current_version)
60
201
  if index > 0
61
202
  target = migrations[index - 1]
62
203
  end
63
- Sequel::Migrator.apply(db, "./db/migrate", target)
204
+ Sequel::Migrator.apply(db, MIGRATION_DIR, target)
64
205
  end
65
206
 
66
207
  def disconnect
67
208
  @db.disconnect
68
209
  end
210
+
211
+ private
212
+
213
+ MIGRATION_DIR = "./db/migrate".freeze
214
+ private_constant :MIGRATION_DIR
69
215
  end
70
216
  end
@@ -8,9 +8,13 @@ module Pliny::Helpers
8
8
 
9
9
  def parse_body_params
10
10
  if request.media_type == "application/json"
11
- p = load_params(MultiJson.decode(request.body.read))
11
+ begin
12
+ decoded = MultiJson.decode(request.body.read)
13
+ rescue MultiJson::ParseError => e
14
+ raise Pliny::Errors::BadRequest, e.message
15
+ end
12
16
  request.body.rewind
13
- p
17
+ load_params(decoded)
14
18
  elsif request.form_data?
15
19
  load_params(request.POST)
16
20
  else
data/lib/pliny/log.rb CHANGED
@@ -123,13 +123,17 @@ module Pliny
123
123
  end
124
124
  end
125
125
 
126
- def quote_string(k, v)
126
+ def replace_newlines(v)
127
+ v.gsub("\n", "\\n")
128
+ end
129
+
130
+ def quote_string(v)
127
131
  if !v.include?('"')
128
- %{#{k}="#{v}"}
132
+ %{"#{v}"}
129
133
  elsif !v.include?("'")
130
- %{#{k}='#{v}'}
134
+ %{'#{v}'}
131
135
  else
132
- %{#{k}="#{v.gsub(/"/, '\\"')}"}
136
+ %{"#{v.gsub(/"/, '\\"')}"}
133
137
  end
134
138
  end
135
139
 
@@ -150,11 +154,10 @@ module Pliny
150
154
  "#{k}=#{v.iso8601}"
151
155
  else
152
156
  v = "#{v}"
153
- if v =~ /\s/
154
- quote_string(k, v)
155
- else
156
- "#{k}=#{v}"
157
- end
157
+ v = replace_newlines(v)
158
+ v = quote_string(v) if v =~ /\s/
159
+
160
+ "#{k}=#{v}"
158
161
  end
159
162
  end
160
163
  end
@@ -58,9 +58,9 @@ module Pliny::Middleware
58
58
  log_field :timing_serializer, Float
59
59
  end
60
60
 
61
- def initialize(app, emitter:)
61
+ def initialize(app, options)
62
62
  @app = app
63
- @emitter = emitter
63
+ @emitter = options.fetch(:emitter)
64
64
  end
65
65
 
66
66
  def call(env)
@@ -8,6 +8,23 @@ begin
8
8
  require "pliny/db_support"
9
9
 
10
10
  namespace :db do
11
+ desc "Get current schema version"
12
+ task :version do
13
+ Pliny::DbSupport.run(database_urls.first, $stdout) do |helper|
14
+ puts "Current version: #{helper.version}"
15
+ end
16
+ end
17
+
18
+ namespace :migrate do
19
+ desc "Get the status of migrations"
20
+ task :status do
21
+ # TODO: figure out how to handle multiple databases. Also why do we support multiple databases this way?
22
+ Pliny::DbSupport.run(database_urls.first, $stdout) do |helper|
23
+ puts helper.status
24
+ end
25
+ end
26
+ end
27
+
11
28
  desc "Run database migrations"
12
29
  task :migrate do
13
30
  next if Dir["./db/migrate/*.rb"].empty?
data/lib/pliny/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Pliny
2
- VERSION = "0.29.0"
2
+ VERSION = "0.32.0"
3
3
  end
data/lib/template/Gemfile CHANGED
@@ -4,7 +4,7 @@ ruby "2.4.0"
4
4
  gem "multi_json"
5
5
  gem "oj"
6
6
  gem "pg"
7
- gem "pliny", "~> 0.28"
7
+ gem "pliny", "~> 0.32"
8
8
  gem "pry"
9
9
  gem "puma", "~> 3"
10
10
  gem "rack-ssl"
@@ -2,9 +2,9 @@ require "spec_helper"
2
2
  require "pliny/db_support"
3
3
 
4
4
  describe Pliny::DbSupport do
5
+ subject(:support) { Pliny::DbSupport.new(url, logger) }
5
6
  let(:url) { ENV["TEST_DATABASE_URL"] }
6
7
  let(:logger) { Logger.new(StringIO.new) }
7
- let(:support) { Pliny::DbSupport.new(url, logger) }
8
8
 
9
9
  around do |example|
10
10
  Dir.mktmpdir("plinytest-") do |dir|
@@ -88,4 +88,269 @@ describe Pliny::DbSupport do
88
88
  support.rollback # should noop
89
89
  end
90
90
  end
91
+
92
+ describe "#version" do
93
+ it "is zero if the migrations table doesn't exist" do
94
+ assert_equal 0, support.version
95
+ end
96
+
97
+ context "with migrations table" do
98
+ before do
99
+ DB.create_table(:schema_migrations) do
100
+ text :filename
101
+ end
102
+ end
103
+
104
+ it "is zero if the migrations table is empty" do
105
+ assert_equal 0, support.version
106
+ end
107
+
108
+ it "is the highest timestamp from a filename in the migrations table" do
109
+ migrations = DB[:schema_migrations]
110
+ migrations.insert(filename: "1630551344_latest_change.rb")
111
+ migrations.insert(filename: "1524000760_earlier_change.rb")
112
+
113
+ assert_equal 1630551344, support.version
114
+ end
115
+ end
116
+ end
117
+
118
+ describe "MigrationStatus" do
119
+ let(:filename) { "1630551344_latest_change.rb" }
120
+ let(:migration_status) { described_class::MigrationStatus.new(filename: filename) }
121
+
122
+ describe "#status" do
123
+ context "given a migration present on disk" do
124
+ before do
125
+ migration_status.present_on_disk = true
126
+ end
127
+
128
+ context "and present in the database" do
129
+ before do
130
+ migration_status.present_in_database = true
131
+ end
132
+
133
+ it "is :up" do
134
+ assert_equal :up, migration_status.status
135
+ end
136
+ end
137
+
138
+ context "and is absent from the database" do
139
+ before do
140
+ migration_status.present_in_database = false
141
+ end
142
+
143
+ it "is :down" do
144
+ assert_equal :down, migration_status.status
145
+ end
146
+ end
147
+ end
148
+
149
+ context "given a migration absent from disk" do
150
+ before do
151
+ migration_status.present_on_disk = false
152
+ end
153
+
154
+ context "and present in the database" do
155
+ before do
156
+ migration_status.present_in_database = true
157
+ end
158
+
159
+ it "is :file_missing" do
160
+ assert_equal :file_missing, migration_status.status
161
+ end
162
+ end
163
+
164
+ context "and is absent from the database" do
165
+ before do
166
+ migration_status.present_in_database = false
167
+ end
168
+
169
+ it "is an error case" do
170
+ assert_raises RuntimeError do
171
+ migration_status.status
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
178
+
179
+ describe 'MigrationStatusPresenter' do
180
+ let(:filename) { '1630551344_latest_change.rb' }
181
+ let(:up_migration) { described_class::MigrationStatus.new(filename: "00#{filename}") }
182
+ let(:down_migration) { described_class::MigrationStatus.new(filename: "0#{filename}") }
183
+ let(:file_missing_migration) { described_class::MigrationStatus.new(filename: "000#{filename}") }
184
+ let(:migration_statuses) { [up_migration, down_migration, file_missing_migration] }
185
+ let(:presenter) { described_class::MigrationStatusPresenter.new(migration_statuses: migration_statuses) }
186
+
187
+ before do
188
+ up_migration.present_in_database = true
189
+ up_migration.present_on_disk = true
190
+ down_migration.present_in_database = false
191
+ down_migration.present_on_disk = true
192
+ file_missing_migration.present_in_database = true
193
+ file_missing_migration.present_on_disk = false
194
+ end
195
+
196
+ describe '#barrier_row' do
197
+ it 'pads to the longest_migration name' do
198
+ expectation = '+--------------+--------------------------------+'
199
+ assert_equal expectation, presenter.barrier_row
200
+ end
201
+ end
202
+
203
+ describe '#header_row' do
204
+ it 'pads to the longest migration name' do
205
+ expectation = '| STATUS | MIGRATION |'
206
+ assert_equal expectation, presenter.header_row
207
+ end
208
+ end
209
+
210
+ describe '#header' do
211
+ let(:barrier) { '+--------------+--------------------------------+' }
212
+ let(:header) { '| STATUS | MIGRATION |' }
213
+
214
+ it 'wraps the title in barriers' do
215
+ assert_equal [barrier, header, barrier], presenter.header
216
+ end
217
+ end
218
+
219
+ describe '#footer' do
220
+ let(:barrier) { '+--------------+--------------------------------+' }
221
+
222
+ it 'just a barrier' do
223
+ assert_equal [barrier], presenter.footer
224
+ end
225
+ end
226
+
227
+ describe '#status_row' do
228
+ context 'an up migration' do
229
+ it 'shows the correct details' do
230
+ expectation = '| UP | 001630551344_latest_change.rb |'
231
+ assert_equal expectation, presenter.status_row(up_migration)
232
+ end
233
+ end
234
+
235
+ context 'a down migration' do
236
+ it 'shows the correct details' do
237
+ expectation = '| DOWN | 01630551344_latest_change.rb |'
238
+ assert_equal expectation, presenter.status_row(down_migration)
239
+ end
240
+ end
241
+
242
+ context 'a file missing migration' do
243
+ it 'shows the correct details' do
244
+ expectation = '| FILE MISSING | 0001630551344_latest_change.rb |'
245
+ assert_equal expectation, presenter.status_row(file_missing_migration)
246
+ end
247
+ end
248
+ end
249
+
250
+ describe '#statuses' do
251
+ let(:up_expectation) { '| UP | 001630551344_latest_change.rb |' }
252
+ let(:down_expectation) { '| DOWN | 01630551344_latest_change.rb |' }
253
+ let(:file_missing_expectation) { '| FILE MISSING | 0001630551344_latest_change.rb |' }
254
+
255
+ it 'returns strings' do
256
+ assert_equal [up_expectation, down_expectation, file_missing_expectation], presenter.statuses
257
+ end
258
+ end
259
+
260
+ describe '#rows' do
261
+ let(:barrier) { '+--------------+--------------------------------+' }
262
+ let(:header) { '| STATUS | MIGRATION |' }
263
+ let(:up_expectation) { '| UP | 001630551344_latest_change.rb |' }
264
+ let(:down_expectation) { '| DOWN | 01630551344_latest_change.rb |' }
265
+ let(:file_missing_expectation) { '| FILE MISSING | 0001630551344_latest_change.rb |' }
266
+ let(:footer) { '+--------------+--------------------------------+' }
267
+
268
+ it 'is the table as an array' do
269
+ expectation = [
270
+ barrier,
271
+ header,
272
+ barrier,
273
+ up_expectation,
274
+ down_expectation,
275
+ file_missing_expectation,
276
+ footer
277
+ ]
278
+
279
+ assert_equal expectation, presenter.rows
280
+ end
281
+ end
282
+
283
+ describe '#to_s' do
284
+ it 'is the table as a string' do
285
+ expectation = <<~OUTPUT.chomp
286
+ +--------------+--------------------------------+
287
+ | STATUS | MIGRATION |
288
+ +--------------+--------------------------------+
289
+ | UP | 001630551344_latest_change.rb |
290
+ | DOWN | 01630551344_latest_change.rb |
291
+ | FILE MISSING | 0001630551344_latest_change.rb |
292
+ +--------------+--------------------------------+
293
+ OUTPUT
294
+
295
+ assert_equal expectation, presenter.to_s
296
+ end
297
+ end
298
+ end
299
+
300
+ describe '#status' do
301
+ let(:filename) { '1630551344_latest_change.rb' }
302
+ let(:up_migration) { "00#{filename}" }
303
+ let(:down_migration) { "0#{filename}" }
304
+ let(:file_missing_migration) { "000#{filename}" }
305
+
306
+ before do
307
+ DB.create_table(:schema_migrations) do
308
+ text :filename
309
+ end
310
+
311
+ migrations = DB[:schema_migrations]
312
+ migrations.insert(filename: up_migration)
313
+ migrations.insert(filename: file_missing_migration)
314
+
315
+ File.open("./db/migrate/#{up_migration}", "w") do |f|
316
+ f.puts "
317
+ Sequel.migration do
318
+ change do
319
+ create_table(:foo) do
320
+ primary_key :id
321
+ text :bar
322
+ end
323
+ end
324
+ end
325
+ "
326
+ end
327
+
328
+ File.open("./db/migrate/#{down_migration}", "w") do |f|
329
+ f.puts "
330
+ Sequel.migration do
331
+ change do
332
+ create_table(:foo) do
333
+ primary_key :id
334
+ text :bar
335
+ end
336
+ end
337
+ end
338
+ "
339
+ end
340
+ end
341
+
342
+ it 'returns a table string' do
343
+ expectation = <<~OUTPUT.chomp
344
+ +--------------+--------------------------------+
345
+ | STATUS | MIGRATION |
346
+ +--------------+--------------------------------+
347
+ | FILE MISSING | 0001630551344_latest_change.rb |
348
+ | UP | 001630551344_latest_change.rb |
349
+ | DOWN | 01630551344_latest_change.rb |
350
+ +--------------+--------------------------------+
351
+ OUTPUT
352
+
353
+ assert_equal expectation, support.status
354
+ end
355
+ end
91
356
  end
@@ -34,4 +34,12 @@ describe Pliny::Helpers::Params do
34
34
  post "/", "<hello>world</hello>", {"CONTENT_TYPE" => "application/xml"}
35
35
  assert_equal "{}", last_response.body
36
36
  end
37
+
38
+ it "should throw bad request when receiving invalid json via post" do
39
+ err = assert_raises(Pliny::Errors::BadRequest) do
40
+ post "/", "{\"foo\"}", {"CONTENT_TYPE" => "application/json"}
41
+ end
42
+
43
+ assert_match /unexpected token/, err.message
44
+ end
37
45
  end
@@ -1,30 +1,46 @@
1
1
  require "spec_helper"
2
+ require "open3"
3
+ require 'active_support/core_ext/object/blank'
2
4
 
3
5
  describe "Pliny integration test" do
4
- before(:all) do
5
- @original_dir = Dir.pwd
6
-
7
- test_dir = Dir.mktmpdir("plinytest-")
8
- Dir.chdir(test_dir)
9
-
10
- bash "pliny-new myapp"
6
+ describe "bin/setup" do
7
+ around do |example|
8
+ original_dir = Dir.pwd
9
+ test_dir = Dir.mktmpdir("plinytest-")
10
+ Dir.chdir(test_dir)
11
11
 
12
- Dir.chdir("myapp")
13
- bash "bin/setup"
14
- end
12
+ bash "pliny-new myapp"
15
13
 
16
- after(:all) do
17
- Dir.chdir(@original_dir)
18
- end
14
+ Dir.chdir("myapp")
15
+ example.run
16
+ Dir.chdir(original_dir)
17
+ end
19
18
 
20
- describe "bin/setup" do
21
19
  it "generates .env" do
20
+ bash "bin/setup"
21
+
22
22
  assert File.exist?("./.env")
23
23
  end
24
24
  end
25
25
 
26
26
  describe "pliny-generate scaffold" do
27
- before(:all) do
27
+ around do |example|
28
+ DB.tables.each { |t| DB.drop_table(t) }
29
+
30
+ original_dir = Dir.pwd
31
+ test_dir = Dir.mktmpdir("plinytest-")
32
+ Dir.chdir(test_dir)
33
+
34
+ bash "pliny-new myapp"
35
+
36
+ Dir.chdir("myapp")
37
+ bash "bin/setup"
38
+
39
+ example.run
40
+ Dir.chdir(original_dir)
41
+ end
42
+
43
+ before do
28
44
  bash "pliny-generate scaffold artist"
29
45
  end
30
46
 
@@ -45,6 +61,71 @@ describe "Pliny integration test" do
45
61
  end
46
62
  end
47
63
 
64
+ describe "rake db:migrate:status" do
65
+ around do |example|
66
+ DB.tables.each { |t| DB.drop_table(t) }
67
+
68
+ original_dir = Dir.pwd
69
+ test_dir = Dir.mktmpdir("plinytest-")
70
+ Dir.chdir(test_dir)
71
+
72
+ bash "pliny-new myapp"
73
+
74
+ Dir.chdir("myapp")
75
+ bash "bin/setup"
76
+
77
+ example.run
78
+ Dir.chdir(original_dir)
79
+ end
80
+
81
+ it "returns a migration in the DOWN state when not migrated" do
82
+ bash "pliny-generate model artist"
83
+ migration_file = Dir.glob('db/migrate/*').first
84
+
85
+ stdout, stderr = bash_with_output("rake db:migrate:status")
86
+
87
+ statuses = Hash[stdout.to_s.split(/\+[-]+\+[-]+\+/)[2..-1].map { |s| s.tr("\n", "") }.select(&:present?).map { |s| s.split("|").map { |s| s.tr(" ", "") }.select(&:present?).reverse }]
88
+ assert statuses[migration_file.split("/").last] == "DOWN"
89
+ end
90
+
91
+ it "returns a migration in the UP state when not migrated" do
92
+ bash "pliny-generate model artist"
93
+ migration_file = Dir.glob('db/migrate/*').first
94
+ bash "rake db:migrate"
95
+
96
+ stdout, stderr = bash_with_output("rake db:migrate:status")
97
+
98
+ statuses = Hash[stdout.to_s.split(/\+[-]+\+[-]+\+/)[2..-1].map { |s| s.tr("\n", "") }.select(&:present?).map { |s| s.split("|").map { |s| s.tr(" ", "") }.select(&:present?).reverse }]
99
+ assert statuses[migration_file.split("/").last] == "UP"
100
+ end
101
+
102
+ it "returns a migration in the FILE MISSING state when the file is missing" do
103
+ bash "pliny-generate model artist"
104
+ migration_file = Dir.glob('db/migrate/*').first
105
+ bash "rake db:migrate"
106
+
107
+ FileUtils.rm_f(migration_file)
108
+
109
+ stdout, stderr = bash_with_output("rake db:migrate:status")
110
+
111
+ statuses = Hash[stdout.to_s.split(/\+[-]+\+[-]+\+/)[2..-1].map { |s| s.tr("\n", "") }.select(&:present?).map { |s| s.split("|").map { |s| s.gsub(/(^[ ]+|[ ]+$)/, "") }.select(&:present?).reverse }]
112
+ assert statuses[migration_file.split("/").last] == "FILE MISSING"
113
+ end
114
+ end
115
+
116
+ def bash_with_output(cmd)
117
+ bin = File.expand_path('../bin', File.dirname(__FILE__))
118
+ path = "#{bin}:#{ENV["PATH"]}"
119
+ env = { "PATH" => path }
120
+ stdout, stderr, status = Open3.capture3(env, cmd)
121
+
122
+ unless status.success?
123
+ raise "Failed to run #{cmd}, error was #{stderr}"
124
+ end
125
+
126
+ return stdout, stderr
127
+ end
128
+
48
129
  def bash(cmd)
49
130
  bin = File.expand_path('../bin', File.dirname(__FILE__))
50
131
  path = "#{bin}:#{ENV["PATH"]}"
data/spec/log_spec.rb CHANGED
@@ -161,6 +161,12 @@ describe Pliny::Log do
161
161
  Pliny.log(foo: "string with spaces")
162
162
  end
163
163
 
164
+ it "replaces newlines in strings" do
165
+ expect(@io).to receive(:print).with("foo=\"string\\nwith newlines\\n\"\n")
166
+
167
+ Pliny.log(foo: "string\nwith newlines\n")
168
+ end
169
+
164
170
  it "by default interpolates objects into strings" do
165
171
  expect(@io).to receive(:print).with("foo=message\n")
166
172
  expect(@io).to receive(:print).with("foo=42\n")
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pliny
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.29.0
4
+ version: 0.32.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandur Leach
8
8
  - Pedro Belo
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-09-30 00:00:00.000000000 Z
12
+ date: 2022-02-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -135,22 +135,22 @@ dependencies:
135
135
  name: thor
136
136
  requirement: !ruby/object:Gem::Requirement
137
137
  requirements:
138
- - - "~>"
138
+ - - ">="
139
139
  - !ruby/object:Gem::Version
140
140
  version: '0.19'
141
- - - ">="
141
+ - - "<"
142
142
  - !ruby/object:Gem::Version
143
- version: 0.19.1
143
+ version: '2.0'
144
144
  type: :runtime
145
145
  prerelease: false
146
146
  version_requirements: !ruby/object:Gem::Requirement
147
147
  requirements:
148
- - - "~>"
148
+ - - ">="
149
149
  - !ruby/object:Gem::Version
150
150
  version: '0.19'
151
- - - ">="
151
+ - - "<"
152
152
  - !ruby/object:Gem::Version
153
- version: 0.19.1
153
+ version: '2.0'
154
154
  - !ruby/object:Gem::Dependency
155
155
  name: rake
156
156
  requirement: !ruby/object:Gem::Requirement
@@ -183,22 +183,22 @@ dependencies:
183
183
  name: rspec
184
184
  requirement: !ruby/object:Gem::Requirement
185
185
  requirements:
186
- - - ">="
187
- - !ruby/object:Gem::Version
188
- version: 3.1.0
189
186
  - - "~>"
190
187
  - !ruby/object:Gem::Version
191
188
  version: '3.1'
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ version: 3.1.0
192
192
  type: :development
193
193
  prerelease: false
194
194
  version_requirements: !ruby/object:Gem::Requirement
195
195
  requirements:
196
- - - ">="
197
- - !ruby/object:Gem::Version
198
- version: 3.1.0
199
196
  - - "~>"
200
197
  - !ruby/object:Gem::Version
201
198
  version: '3.1'
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: 3.1.0
202
202
  - !ruby/object:Gem::Dependency
203
203
  name: sinatra-contrib
204
204
  requirement: !ruby/object:Gem::Requirement
@@ -273,60 +273,54 @@ dependencies:
273
273
  requirements:
274
274
  - - "~>"
275
275
  - !ruby/object:Gem::Version
276
- version: '0.17'
277
- - - ">="
276
+ version: '1.0'
277
+ - - "<"
278
278
  - !ruby/object:Gem::Version
279
- version: 0.17.1
279
+ version: '2.0'
280
280
  type: :development
281
281
  prerelease: false
282
282
  version_requirements: !ruby/object:Gem::Requirement
283
283
  requirements:
284
284
  - - "~>"
285
285
  - !ruby/object:Gem::Version
286
- version: '0.17'
287
- - - ">="
286
+ version: '1.0'
287
+ - - "<"
288
288
  - !ruby/object:Gem::Version
289
- version: 0.17.1
289
+ version: '2.0'
290
290
  - !ruby/object:Gem::Dependency
291
291
  name: rollbar
292
292
  requirement: !ruby/object:Gem::Requirement
293
293
  requirements:
294
- - - ">="
295
- - !ruby/object:Gem::Version
296
- version: 2.11.0
297
294
  - - "~>"
298
295
  - !ruby/object:Gem::Version
299
- version: '2.11'
296
+ version: '3.2'
300
297
  type: :development
301
298
  prerelease: false
302
299
  version_requirements: !ruby/object:Gem::Requirement
303
300
  requirements:
304
- - - ">="
305
- - !ruby/object:Gem::Version
306
- version: 2.11.0
307
301
  - - "~>"
308
302
  - !ruby/object:Gem::Version
309
- version: '2.11'
303
+ version: '3.2'
310
304
  - !ruby/object:Gem::Dependency
311
305
  name: sequel
312
306
  requirement: !ruby/object:Gem::Requirement
313
307
  requirements:
314
- - - ">="
315
- - !ruby/object:Gem::Version
316
- version: 4.9.0
317
308
  - - "~>"
318
309
  - !ruby/object:Gem::Version
319
- version: '4.9'
310
+ version: '5.4'
311
+ - - "<"
312
+ - !ruby/object:Gem::Version
313
+ version: '6.0'
320
314
  type: :development
321
315
  prerelease: false
322
316
  version_requirements: !ruby/object:Gem::Requirement
323
317
  requirements:
324
- - - ">="
325
- - !ruby/object:Gem::Version
326
- version: 4.9.0
327
318
  - - "~>"
328
319
  - !ruby/object:Gem::Version
329
- version: '4.9'
320
+ version: '5.4'
321
+ - - "<"
322
+ - !ruby/object:Gem::Version
323
+ version: '6.0'
330
324
  - !ruby/object:Gem::Dependency
331
325
  name: rubocop
332
326
  requirement: !ruby/object:Gem::Requirement
@@ -503,7 +497,7 @@ homepage: https://github.com/interagent/pliny
503
497
  licenses:
504
498
  - MIT
505
499
  metadata: {}
506
- post_install_message:
500
+ post_install_message:
507
501
  rdoc_options: []
508
502
  require_paths:
509
503
  - lib
@@ -518,8 +512,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
518
512
  - !ruby/object:Gem::Version
519
513
  version: '0'
520
514
  requirements: []
521
- rubygems_version: 3.0.3
522
- signing_key:
515
+ rubygems_version: 3.1.2
516
+ signing_key:
523
517
  specification_version: 4
524
518
  summary: Basic tooling to support API apps in Sinatra
525
519
  test_files: []