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 +4 -4
- data/README.md +2 -1
- data/lib/pliny/db_support.rb +154 -8
- data/lib/pliny/helpers/params.rb +6 -2
- data/lib/pliny/log.rb +12 -9
- data/lib/pliny/middleware/canonical_log_line.rb +2 -2
- data/lib/pliny/tasks/db.rake +17 -0
- data/lib/pliny/version.rb +1 -1
- data/lib/template/Gemfile +1 -1
- data/spec/db_support_spec.rb +266 -1
- data/spec/helpers/params_spec.rb +8 -0
- data/spec/integration_spec.rb +96 -15
- data/spec/log_spec.rb +6 -0
- metadata +34 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8de7550e51b73562d5fbf52d648945f5f07925cc5df89b5526faba9fc5b27075
|
4
|
+
data.tar.gz: 46f1ed81d71d0b9b70332085bc6dc61038a98d8f66ba2645db6651f355f85fd4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 90130887007a82d06b841e6e4ca27f0f242f24eb782f273037a50a849d8a8a19ce73b7d4fb42ee75bc983b8cdfac57f02057e6322d11ab00678ef5c51b2d8d13
|
7
|
+
data.tar.gz: a77f028909da4a10a07db20f96e3fa872c351114395adbbbe500a1106bc0b3882676bdd94fbb52ec91a23676ba92cce2b84a76277a385321f29c16c64ede2fc1
|
data/README.md
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# Pliny
|
2
2
|
|
3
3
|
[](https://rubygems.org/gems/pliny)
|
4
|
-
[](https://github.com/interagent/pliny/actions)
|
5
|
+
|
5
6
|
|
6
7
|
Pliny helps Ruby developers write and maintain excellent APIs.
|
7
8
|
|
data/lib/pliny/db_support.rb
CHANGED
@@ -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,
|
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
|
-
|
55
|
-
return
|
194
|
+
current_version = version
|
195
|
+
return if current_version.zero?
|
56
196
|
|
57
|
-
migrations = Dir["
|
58
|
-
|
59
|
-
|
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,
|
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
|
data/lib/pliny/helpers/params.rb
CHANGED
@@ -8,9 +8,13 @@ module Pliny::Helpers
|
|
8
8
|
|
9
9
|
def parse_body_params
|
10
10
|
if request.media_type == "application/json"
|
11
|
-
|
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
|
-
|
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
|
126
|
+
def replace_newlines(v)
|
127
|
+
v.gsub("\n", "\\n")
|
128
|
+
end
|
129
|
+
|
130
|
+
def quote_string(v)
|
127
131
|
if !v.include?('"')
|
128
|
-
%{
|
132
|
+
%{"#{v}"}
|
129
133
|
elsif !v.include?("'")
|
130
|
-
%{
|
134
|
+
%{'#{v}'}
|
131
135
|
else
|
132
|
-
%{
|
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
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
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
|
data/lib/pliny/tasks/db.rake
CHANGED
@@ -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
data/lib/template/Gemfile
CHANGED
data/spec/db_support_spec.rb
CHANGED
@@ -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
|
data/spec/helpers/params_spec.rb
CHANGED
@@ -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
|
data/spec/integration_spec.rb
CHANGED
@@ -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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
13
|
-
bash "bin/setup"
|
14
|
-
end
|
12
|
+
bash "pliny-new myapp"
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
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.
|
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:
|
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
|
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
|
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
|
277
|
-
- - "
|
276
|
+
version: '1.0'
|
277
|
+
- - "<"
|
278
278
|
- !ruby/object:Gem::Version
|
279
|
-
version: 0
|
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
|
287
|
-
- - "
|
286
|
+
version: '1.0'
|
287
|
+
- - "<"
|
288
288
|
- !ruby/object:Gem::Version
|
289
|
-
version: 0
|
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
|
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
|
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
|
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
|
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.
|
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: []
|