pliny 0.29.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []