brut 0.19.2 → 0.20.1
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/lib/brut/cli/apps/build_assets.rb +2 -2
- data/lib/brut/cli/apps/db.rb +3 -3
- data/lib/brut/cli/apps/deploy.rb +30 -40
- data/lib/brut/cli/apps/new/app.rb +7 -7
- data/lib/brut/cli/apps/new/ops/insert_code_in_method.rb +5 -0
- data/lib/brut/cli/apps/new/segments/heroku.rb +0 -3
- data/lib/brut/cli/apps/new/segments/sidekiq.rb +6 -3
- data/lib/brut/cli/apps/scaffold.rb +14 -9
- data/lib/brut/cli/apps/test.rb +12 -5
- data/lib/brut/cli/commands/help_in_markdown.rb +109 -0
- data/lib/brut/cli/commands.rb +1 -0
- data/lib/brut/cli/logger.rb +5 -2
- data/lib/brut/cli/parsed_command_line.rb +15 -7
- data/lib/brut/framework/mcp.rb +1 -0
- data/lib/brut/front_end/asset_metadata.rb +0 -1
- data/lib/brut/front_end/forms/input_declarations.rb +30 -1
- data/lib/brut/front_end/handler.rb +4 -4
- data/lib/brut/rubocop_config.rb +3 -3
- data/lib/brut/spec_support/e2e_test_server.rb +5 -4
- data/lib/brut/spec_support/matchers/have_constraint_violation.rb +3 -0
- data/lib/brut/tui/event_loop.rb +5 -1
- data/lib/brut/tui/script/exec_step.rb +1 -1
- data/lib/brut/version.rb +1 -1
- data/templates/Base/app/src/back_end/data_models/db/README.md +8 -0
- data/templates/Base/bin/console +1 -1
- data/templates/Base/bin/release +1 -1
- data/templates/Base/dx/bash_customizations.local +1 -4
- data/templates/Base/dx/build +2 -2
- data/templates/Base/specs/spec_helper.rb +3 -0
- metadata +8 -7
- data/templates/Base/.env.development.local +0 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: de61901270558680112b8b90f787067add7f777204219016020adcc90c15564d
|
|
4
|
+
data.tar.gz: 4437fee31bc132bd93fe419ac72df5bc1b1e7bb67f506a4e36ab126dc7395b85
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fcc0ef80b40ea5703298cdbaa71f86f3ec8d22b96f8bc4e9cea336f41b09bbca109b211eea365b202759f8bca4c07ace5c35d2a6f638a7d2231f5d0534090556
|
|
7
|
+
data.tar.gz: c4bb547d99089ca6d567e744c39539fda20ff85b21c45dd2419ab7d0bcfc0e265a9004006973e7bb4f96be35f41d21354efd71502f77e2276140dbd8badf29a3
|
|
@@ -91,9 +91,9 @@ This is to ensure that any images your code references will end up in the public
|
|
|
91
91
|
def description = "Builds a single CSS file suitable for sending to the browser"
|
|
92
92
|
|
|
93
93
|
def detailed_description = %{
|
|
94
|
-
This produces a hashed file in every environment, in order to keep environments consistent and reduce differences. If your CSS file references images, fonts, or other assets via url() or other CSS functions, those files will be hashed and copied into the output directory where CSS is served.
|
|
94
|
+
This produces a hashed file in every environment, in order to keep environments consistent and reduce differences. If your CSS file references images, fonts, or other assets via `url()` or other CSS functions, those files will be hashed and copied into the output directory where CSS is served.
|
|
95
95
|
|
|
96
|
-
To ensure this happens correctly, your url() or other function must reference the file as a relative file from where your actual source CSS file is located. For example, a font named some-font.ttf would be in app/src/front_end/fonts
|
|
96
|
+
To ensure this happens correctly, your `url()` or other function must reference the file as a relative file from where your actual source CSS file is located. For example, a font named `some-font.ttf` would be in `app/src/front_end/fonts`. To reference this from `app/src/front_end/css/index.css` you'd use `url("../fonts/some-font.ttf")`
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
def run
|
data/lib/brut/cli/apps/db.rb
CHANGED
|
@@ -51,20 +51,20 @@ class Brut::CLI::Apps::DB < Brut::CLI::Commands::BaseCommand
|
|
|
51
51
|
rows = [
|
|
52
52
|
[
|
|
53
53
|
"Database Server",
|
|
54
|
-
server_up ? theme.success.render("✅ UP") : theme.error.render("❌ DOWN")
|
|
54
|
+
server_up ? theme.success.render("✅ UP") : theme.error.render("❌ DOWN"),
|
|
55
55
|
],
|
|
56
56
|
]
|
|
57
57
|
if server_up
|
|
58
58
|
rows << [
|
|
59
59
|
"Database #{theme.code.render(database_name)}",
|
|
60
|
-
database_exists ? theme.success.render("✅ Exists") : theme.error.render("❌ DOES NOT EXIST")
|
|
60
|
+
database_exists ? theme.success.render("✅ Exists") : theme.error.render("❌ DOES NOT EXIST"),
|
|
61
61
|
]
|
|
62
62
|
end
|
|
63
63
|
if database_exists
|
|
64
64
|
if migration_files.empty? && migrations_run.empty?
|
|
65
65
|
rows << [
|
|
66
66
|
"Migrations",
|
|
67
|
-
"✅ NO MIGRATION FILES TO RUN"
|
|
67
|
+
"✅ NO MIGRATION FILES TO RUN",
|
|
68
68
|
]
|
|
69
69
|
else
|
|
70
70
|
migration_files.each do |filename|
|
data/lib/brut/cli/apps/deploy.rb
CHANGED
|
@@ -19,8 +19,16 @@ class Brut::CLI::Apps::Deploy < Brut::CLI::Commands::BaseCommand
|
|
|
19
19
|
def default_rack_env = "development"
|
|
20
20
|
|
|
21
21
|
def run
|
|
22
|
+
options.set_default(:deploy, true)
|
|
23
|
+
puts "Logging in to Heroku Container Registry"
|
|
24
|
+
command = %{heroku container:login}
|
|
25
|
+
system!(command)
|
|
22
26
|
execute_result = Brut::CLI::ExecuteResult.new do
|
|
23
|
-
delegate_to_command(
|
|
27
|
+
delegate_to_command(
|
|
28
|
+
Brut::CLI::Apps::Deploy::Build.new(
|
|
29
|
+
push: options.deploy? ? "registry.heroku.com/#{Brut.container.app_id}/%{name}": false
|
|
30
|
+
)
|
|
31
|
+
)
|
|
24
32
|
end
|
|
25
33
|
if execute_result.failed?
|
|
26
34
|
puts theme.error.render("Build failed.")
|
|
@@ -28,47 +36,17 @@ class Brut::CLI::Apps::Deploy < Brut::CLI::Commands::BaseCommand
|
|
|
28
36
|
puts theme.error.render("Error message from build: #{error_message}")
|
|
29
37
|
end
|
|
30
38
|
end
|
|
31
|
-
|
|
32
|
-
version = ""
|
|
33
|
-
git_guess = %{git rev-parse HEAD}
|
|
34
|
-
system!(git_guess) do |output|
|
|
35
|
-
version << output
|
|
36
|
-
end
|
|
37
|
-
version.strip!.chomp!
|
|
38
|
-
if version == ""
|
|
39
|
-
error "Attempt to use git via command '#{git_guess}' to figure out the version failed"
|
|
40
|
-
return 1
|
|
41
|
-
end
|
|
42
|
-
short_version = version[0..7]
|
|
39
|
+
names = []
|
|
43
40
|
app_docker_files = AppDockerImages.new(
|
|
44
41
|
project_root: Brut.container.project_root,
|
|
45
42
|
organization: Brut.container.app_organization,
|
|
46
43
|
app_id: Brut.container.app_id,
|
|
47
|
-
short_version:
|
|
44
|
+
short_version: "NA"
|
|
48
45
|
)
|
|
49
|
-
|
|
50
|
-
puts "Logging in to Heroku Container Registry"
|
|
51
|
-
command = %{heroku container:login}
|
|
52
|
-
system!(command)
|
|
53
|
-
app_docker_files.each do |name:, image_name:|
|
|
54
|
-
heroku_image_name = "registry.heroku.com/#{Brut.container.app_id}/#{name}"
|
|
55
|
-
puts "Tagging '#{image_name}' with '#{heroku_image_name}' for Heroku"
|
|
56
|
-
command = %{docker tag #{image_name} #{heroku_image_name}}
|
|
57
|
-
system!(command)
|
|
58
|
-
begin
|
|
59
|
-
puts "Pushing '#{heroku_image_name}'"
|
|
60
|
-
command = %{docker push #{heroku_image_name}}
|
|
61
|
-
system!(command)
|
|
62
|
-
rescue Brut::CLI::SystemExecError => ex
|
|
63
|
-
error "Failed to push image '#{heroku_image_name}' to Heroku"
|
|
64
|
-
if options.log_level != "debug"
|
|
65
|
-
error "Could be you must re-authenticate to Heroku."
|
|
66
|
-
error "Try re-running with --log-level=debug to see more details"
|
|
67
|
-
end
|
|
68
|
-
return 1
|
|
69
|
-
end
|
|
46
|
+
app_docker_files.each do |name:, cmd:, dockerfile:|
|
|
70
47
|
names << name
|
|
71
48
|
end
|
|
49
|
+
|
|
72
50
|
deploy_command = "heroku container:release #{names.join(' ')} -a #{Brut.container.app_id}"
|
|
73
51
|
if options.deploy?
|
|
74
52
|
puts "Deploying images to Heroku"
|
|
@@ -142,7 +120,13 @@ class Brut::CLI::Apps::Deploy < Brut::CLI::Commands::BaseCommand
|
|
|
142
120
|
def description = Docker.new.description
|
|
143
121
|
def opts = Docker.new.opts
|
|
144
122
|
def default_rack_env = Docker.new.default_rack_env
|
|
145
|
-
|
|
123
|
+
|
|
124
|
+
def initialize(push: false)
|
|
125
|
+
@push = push
|
|
126
|
+
end
|
|
127
|
+
def run
|
|
128
|
+
delegate_to_command(Docker.new(push: @push))
|
|
129
|
+
end
|
|
146
130
|
|
|
147
131
|
def commands = []
|
|
148
132
|
|
|
@@ -155,6 +139,10 @@ class Brut::CLI::Apps::Deploy < Brut::CLI::Commands::BaseCommand
|
|
|
155
139
|
]
|
|
156
140
|
def default_rack_env = "development"
|
|
157
141
|
|
|
142
|
+
def initialize(push: false)
|
|
143
|
+
@push = push
|
|
144
|
+
end
|
|
145
|
+
|
|
158
146
|
def run
|
|
159
147
|
if !options.skip_checks?
|
|
160
148
|
execute_result = Brut::CLI::ExecuteResult.new do
|
|
@@ -177,8 +165,6 @@ class Brut::CLI::Apps::Deploy < Brut::CLI::Commands::BaseCommand
|
|
|
177
165
|
error "Attempt to use git via command '#{git_guess}' to figure out the version failed"
|
|
178
166
|
return 1
|
|
179
167
|
end
|
|
180
|
-
short_version = version[0..7]
|
|
181
|
-
|
|
182
168
|
short_version = version[0..7]
|
|
183
169
|
app_docker_files = AppDockerImages.new(
|
|
184
170
|
project_root: Brut.container.project_root,
|
|
@@ -219,12 +205,16 @@ class Brut::CLI::Apps::Deploy < Brut::CLI::Commands::BaseCommand
|
|
|
219
205
|
puts
|
|
220
206
|
rows = []
|
|
221
207
|
items = []
|
|
208
|
+
push_or_load = @push ? "--push" : "--load"
|
|
222
209
|
app_docker_files.each do |name:, image_name:, dockerfile:|
|
|
210
|
+
if @push && @push.kind_of?(String)
|
|
211
|
+
image_name = @push % { name: name }
|
|
212
|
+
end
|
|
223
213
|
rows << [ name, theme.code.render(image_name) ]
|
|
224
|
-
command = %{docker build --build-arg app_git_sha1=#{version} --file #{Brut.container.project_root}/#{dockerfile} --platform #{options.platform} --tag #{image_name} . 2>&1}
|
|
214
|
+
command = %{docker buildx build --provenance=false --build-arg app_git_sha1=#{version} --file #{Brut.container.project_root}/#{dockerfile} --platform #{options.platform} #{push_or_load} --tag #{image_name} . 2>&1}
|
|
225
215
|
items << theme.code.render(theme.wrap(command, first_indent: false, indent: 7, newline: " \\\n"))
|
|
226
216
|
if !options.dry_run?
|
|
227
|
-
puts theme.subheader.render("Building '#{name}' image")
|
|
217
|
+
puts theme.subheader.render("Building #{@push ? 'and pushing' : '' } '#{name}' image")
|
|
228
218
|
system!(command)
|
|
229
219
|
end
|
|
230
220
|
end
|
|
@@ -53,12 +53,12 @@ class Brut::CLI::Apps::New::App < Brut::CLI::Commands::BaseCommand
|
|
|
53
53
|
[
|
|
54
54
|
"--app-id=ID",
|
|
55
55
|
Brut::CLI::Apps::New::AppId,
|
|
56
|
-
"App identifier, which must be able to be used as a hostname or other Internet identifier. Derived from your app name, if omitted"
|
|
56
|
+
"App identifier, which must be able to be used as a hostname or other Internet identifier. Derived from your app name, if omitted",
|
|
57
57
|
],
|
|
58
58
|
[
|
|
59
59
|
"--organization=ORG",
|
|
60
60
|
Brut::CLI::Apps::New::Organization,
|
|
61
|
-
"Organization name, e.g. what you'd use for GitHub. Defaults to the app-id value"
|
|
61
|
+
"Organization name, e.g. what you'd use for GitHub. Defaults to the app-id value",
|
|
62
62
|
],
|
|
63
63
|
[
|
|
64
64
|
"--[no-]interactive",
|
|
@@ -67,7 +67,7 @@ class Brut::CLI::Apps::New::App < Brut::CLI::Commands::BaseCommand
|
|
|
67
67
|
[
|
|
68
68
|
"--prefix=PREFIX",
|
|
69
69
|
Brut::CLI::Apps::New::Prefix,
|
|
70
|
-
"Two-character prefix for external IDs and autonomous custom elements. Derived from your app-id, if omitted."
|
|
70
|
+
"Two-character prefix for external IDs and autonomous custom elements. Derived from your app-id, if omitted.",
|
|
71
71
|
],
|
|
72
72
|
[
|
|
73
73
|
"--segments=SEGMENTS",
|
|
@@ -76,11 +76,11 @@ class Brut::CLI::Apps::New::App < Brut::CLI::Commands::BaseCommand
|
|
|
76
76
|
],
|
|
77
77
|
[
|
|
78
78
|
"--dry-run",
|
|
79
|
-
"Only show what would happen, don't actually do anything"
|
|
79
|
+
"Only show what would happen, don't actually do anything",
|
|
80
80
|
],
|
|
81
81
|
[
|
|
82
82
|
"--[no-]demo",
|
|
83
|
-
"Include, or not, additional files that demonstrate Brut's features (default is true for now)"
|
|
83
|
+
"Include, or not, additional files that demonstrate Brut's features (default is true for now)",
|
|
84
84
|
],
|
|
85
85
|
]
|
|
86
86
|
|
|
@@ -272,7 +272,7 @@ class Brut::CLI::Apps::New::App < Brut::CLI::Commands::BaseCommand
|
|
|
272
272
|
],
|
|
273
273
|
[
|
|
274
274
|
"--dry-run",
|
|
275
|
-
"Only show what would happen, don't actually do anything"
|
|
275
|
+
"Only show what would happen, don't actually do anything",
|
|
276
276
|
],
|
|
277
277
|
]
|
|
278
278
|
|
|
@@ -319,7 +319,7 @@ class Brut::CLI::Apps::New::App < Brut::CLI::Commands::BaseCommand
|
|
|
319
319
|
|
|
320
320
|
puts "Adding #{segment_name} to this app"
|
|
321
321
|
segment.add!
|
|
322
|
-
segment.output_post_add_messaging(stdout:)
|
|
322
|
+
segment.output_post_add_messaging(stdout: execution_context.stdout)
|
|
323
323
|
0
|
|
324
324
|
end
|
|
325
325
|
end
|
|
@@ -19,6 +19,11 @@ class Brut::CLI::Apps::New::Ops::InsertCodeInMethod < Brut::CLI::Apps::New::Ops:
|
|
|
19
19
|
if !@file.exist? && @ignore_if_file_not_found
|
|
20
20
|
return
|
|
21
21
|
end
|
|
22
|
+
if dry_run?
|
|
23
|
+
op = @class_method ? "::" : "#"
|
|
24
|
+
puts "Would add this code to #{@class_name}#{op}#{@method_name} in #{@file}:\n\n#{@code}\n\n"
|
|
25
|
+
return
|
|
26
|
+
end
|
|
22
27
|
method_node = find_method(class_name: @class_name, method_name: @method_name, class_method: @class_method)
|
|
23
28
|
|
|
24
29
|
insertion_point = if @where == :start
|
|
@@ -75,6 +75,10 @@ class Brut::CLI::Apps::New::Segments::Sidekiq < Brut::CLI::Apps::New::Base
|
|
|
75
75
|
file: @project_root / "Gemfile",
|
|
76
76
|
content: "# Sidekiq is used for background jobs\ngem \"sidekiq\"\n"
|
|
77
77
|
),
|
|
78
|
+
Brut::CLI::Apps::New::Ops::AppendToFile.new(
|
|
79
|
+
file: @project_root / "Gemfile",
|
|
80
|
+
content: "# Sets up OTel middelware for Sidekiq \ngem \"opentelemetry-instrumentation-sidekiq\"\n"
|
|
81
|
+
),
|
|
78
82
|
Brut::CLI::Apps::New::Ops::AppendToFile.new(
|
|
79
83
|
file: @project_root / ".env.development",
|
|
80
84
|
content: %{
|
|
@@ -110,7 +114,7 @@ SIDEKIQ_BASIC_AUTH_PASSWORD=password
|
|
|
110
114
|
Brut::CLI::Apps::New::Ops::InsertIntoFile.new(
|
|
111
115
|
file: @project_root / "specs" / "spec_helper.rb",
|
|
112
116
|
before_line: "require \"brut/spec_support\"",
|
|
113
|
-
content: "
|
|
117
|
+
content: "Sidekiq.testing!(:fake)"
|
|
114
118
|
),
|
|
115
119
|
Brut::CLI::Apps::New::Ops::InsertIntoFile.new(
|
|
116
120
|
file: @project_root / "config.ru",
|
|
@@ -142,10 +146,9 @@ SIDEKIQ_BASIC_AUTH_PASSWORD=password
|
|
|
142
146
|
code: "@sidekiq_segment.boot!"
|
|
143
147
|
),
|
|
144
148
|
Brut::CLI::Apps::New::Ops::InsertCodeInMethod.new(
|
|
145
|
-
file: project_root / "deploy" / "
|
|
149
|
+
file: project_root / "deploy" / "docker_config.rb",
|
|
146
150
|
class_name: "HerokuConfig",
|
|
147
151
|
method_name: "additional_images",
|
|
148
|
-
class_method: true,
|
|
149
152
|
ignore_if_file_not_found: true,
|
|
150
153
|
code: %{
|
|
151
154
|
{
|
|
@@ -4,6 +4,10 @@ require "brut/cli"
|
|
|
4
4
|
class Brut::CLI::Apps::Scaffold < Brut::CLI::Commands::BaseCommand
|
|
5
5
|
def description = "Create scaffolds of various files to help develop more quckly"
|
|
6
6
|
|
|
7
|
+
def commands
|
|
8
|
+
super - [ Brut::CLI::Apps::Scaffold::BaseCommand ]
|
|
9
|
+
end
|
|
10
|
+
|
|
7
11
|
class BaseCommand < Brut::CLI::Commands::BaseCommand
|
|
8
12
|
def bootstrap? = false
|
|
9
13
|
def default_rack_env = "development"
|
|
@@ -111,7 +115,7 @@ end}
|
|
|
111
115
|
def args_description = "test_name"
|
|
112
116
|
def name = "e2e_test"
|
|
113
117
|
|
|
114
|
-
def opts = [
|
|
118
|
+
def opts = super + [
|
|
115
119
|
["--path PATH","Path within the e2e tests to create the file"],
|
|
116
120
|
]
|
|
117
121
|
|
|
@@ -193,7 +197,7 @@ end}
|
|
|
193
197
|
def args_description = "ComponentName"
|
|
194
198
|
def detailed_description = "New components go in the `components/` folder of your app, however using --page will create a 'page private' component. To do that, the component name must be an inner class of an existing page, for example HomePage::Welcome. This component goes in a sub-folder inside the `pages/` area of your app"
|
|
195
199
|
|
|
196
|
-
def opts = [
|
|
200
|
+
def opts = super + [
|
|
197
201
|
[ "--page","If set, this component is for a specific page and won't go with the other components"],
|
|
198
202
|
]
|
|
199
203
|
|
|
@@ -384,7 +388,7 @@ end}
|
|
|
384
388
|
error " The page may not render properly the first time you load it"
|
|
385
389
|
end
|
|
386
390
|
|
|
387
|
-
routes_editor = RoutesEditor.new(app_path:,
|
|
391
|
+
routes_editor = RoutesEditor.new(app_path:,stdout: execution_context.stdout)
|
|
388
392
|
routes_editor.add_route!(route_code:)
|
|
389
393
|
|
|
390
394
|
if !routes_editor.found_routes?
|
|
@@ -419,7 +423,7 @@ end}
|
|
|
419
423
|
end
|
|
420
424
|
def description = "Create a handler for an action"
|
|
421
425
|
def args_description = "action_route"
|
|
422
|
-
def opts = [
|
|
426
|
+
def opts = super + [
|
|
423
427
|
[ "--http-method=METHOD", "If present, the action will be a path available on the given route and this HTTP method. If omitted, this will create an action available via POST" ],
|
|
424
428
|
]
|
|
425
429
|
|
|
@@ -528,7 +532,7 @@ end}
|
|
|
528
532
|
execution_context.stdout.printf printf_string,handler_class_name, handler_source_path.relative_path_from(Brut.container.project_root)
|
|
529
533
|
execution_context.stdout.printf printf_string,"Spec", handler_spec_path.relative_path_from(Brut.container.project_root)
|
|
530
534
|
|
|
531
|
-
routes_editor = RoutesEditor.new(app_path:,
|
|
535
|
+
routes_editor = RoutesEditor.new(app_path:,stdout: execution_context.stdout)
|
|
532
536
|
routes_editor.add_route!(route_code:)
|
|
533
537
|
|
|
534
538
|
if form
|
|
@@ -633,7 +637,8 @@ describe("#{description}", () => {
|
|
|
633
637
|
|
|
634
638
|
def run
|
|
635
639
|
if argv.length == 0
|
|
636
|
-
|
|
640
|
+
puts "You must provide one or more model names"
|
|
641
|
+
return 1
|
|
637
642
|
end
|
|
638
643
|
db_module = ModuleName.from_string("DB")
|
|
639
644
|
actions = argv.map { |arg|
|
|
@@ -703,9 +708,9 @@ end
|
|
|
703
708
|
end
|
|
704
709
|
|
|
705
710
|
class RoutesEditor
|
|
706
|
-
def initialize(app_path:,
|
|
711
|
+
def initialize(app_path:,stdout:)
|
|
707
712
|
@app_path = app_path
|
|
708
|
-
@
|
|
713
|
+
@stdout = stdout
|
|
709
714
|
@found_routes = false
|
|
710
715
|
@routes_existed = false
|
|
711
716
|
end
|
|
@@ -726,7 +731,7 @@ end
|
|
|
726
731
|
end
|
|
727
732
|
if in_routes && line =~ /^ end\s*$/
|
|
728
733
|
if !@routes_existed
|
|
729
|
-
@
|
|
734
|
+
@stdout.puts "Inserted route into #{@app_path.relative_path_from(Brut.container.project_root)}"
|
|
730
735
|
file.puts " #{route_code}"
|
|
731
736
|
end
|
|
732
737
|
@found_routes = true
|
data/lib/brut/cli/apps/test.rb
CHANGED
|
@@ -90,6 +90,7 @@ Runs all non end-to-end tests for the app, or runs a subset of non-end-to-end te
|
|
|
90
90
|
[ "E2E_RECORD_VIDEOS","If set to 'true', videos of each test run are saved in `./tmp/e2e-videos`" ],
|
|
91
91
|
[ "E2E_SLOW_MO","If set to, will attempt to slow operations down by this many milliseconds" ],
|
|
92
92
|
[ "E2E_TIMEOUT_MS","ms to wait for any browser activity before failing the test. And here you didn't think you'd get away without using sleep in browse-based tests?" ],
|
|
93
|
+
[ "E2E_STARTUP_TIMEOUT_SEC","seconds to wait for the test server to start before assuming something went wrong" ],
|
|
93
94
|
]
|
|
94
95
|
|
|
95
96
|
def rspec_cli_args = "--tag e2e"
|
|
@@ -102,11 +103,17 @@ Runs all end-to-end tests for the app, or runs a subset of end-to-end tests usin
|
|
|
102
103
|
private
|
|
103
104
|
|
|
104
105
|
def run_tests
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
test_server = Brut::SpecSupport::E2ETestServer.new(
|
|
107
|
+
bin_dir: Brut.container.project_root / "bin",
|
|
108
|
+
start_timeout_seconds: ENV["E2E_STARTUP_TIMEOUT_SEC"]
|
|
109
|
+
)
|
|
110
|
+
begin
|
|
111
|
+
require "brut/spec_support/e2e_test_server"
|
|
112
|
+
test_server.start
|
|
113
|
+
super
|
|
114
|
+
ensure
|
|
115
|
+
test_server.stop
|
|
116
|
+
end
|
|
110
117
|
end
|
|
111
118
|
end
|
|
112
119
|
class Js < Brut::CLI::Commands::BaseCommand
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
class Brut::CLI::Commands::HelpInMarkdown < Brut::CLI::Commands::BaseCommand
|
|
2
|
+
def description = "Get help for the app or a command, in Markdown"
|
|
3
|
+
attr_accessor :option_parser
|
|
4
|
+
|
|
5
|
+
def initialize(command,option_parser)
|
|
6
|
+
@command = command
|
|
7
|
+
@option_parser = option_parser
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def commands = []
|
|
11
|
+
|
|
12
|
+
def run
|
|
13
|
+
if env["BRUT_HELP_IN_MARKDOWN_COMMANDS_ONLY"]
|
|
14
|
+
@command.commands.sort_by(&:name).each do |command|
|
|
15
|
+
puts command.name
|
|
16
|
+
end
|
|
17
|
+
return 0
|
|
18
|
+
end
|
|
19
|
+
cli = [@command.name ]
|
|
20
|
+
cmd = @command
|
|
21
|
+
while cmd.parent_command
|
|
22
|
+
cmd = cmd.parent_command
|
|
23
|
+
cli.unshift cmd.name
|
|
24
|
+
end
|
|
25
|
+
invocation = cli.join(" ")
|
|
26
|
+
puts "# `#{invocation}`"
|
|
27
|
+
puts
|
|
28
|
+
puts @command.description
|
|
29
|
+
puts
|
|
30
|
+
|
|
31
|
+
usage = invocation
|
|
32
|
+
|
|
33
|
+
options = @option_parser.top.list
|
|
34
|
+
if options.size > 0
|
|
35
|
+
usage << theme.weak.render(" [options]")
|
|
36
|
+
end
|
|
37
|
+
if @command.commands.any?
|
|
38
|
+
usage << theme.code.render(" command")
|
|
39
|
+
end
|
|
40
|
+
if @command.args_description
|
|
41
|
+
usage << " #{@command.args_description}"
|
|
42
|
+
end
|
|
43
|
+
puts
|
|
44
|
+
puts "## USAGE"
|
|
45
|
+
puts
|
|
46
|
+
puts " " + usage
|
|
47
|
+
puts
|
|
48
|
+
if @command.detailed_description
|
|
49
|
+
puts
|
|
50
|
+
puts "## DESCRIPTION"
|
|
51
|
+
puts
|
|
52
|
+
puts @command.detailed_description.gsub(/ +/," ").strip
|
|
53
|
+
puts
|
|
54
|
+
end
|
|
55
|
+
if options.size > 0
|
|
56
|
+
puts
|
|
57
|
+
puts "## OPTIONS"
|
|
58
|
+
puts
|
|
59
|
+
|
|
60
|
+
options.each do |option|
|
|
61
|
+
switches = option.long.map { |switch|
|
|
62
|
+
if option.arg
|
|
63
|
+
if option.arg[0] == "="
|
|
64
|
+
"#{switch.strip}#{theme.weak.render(option.arg.strip)}"
|
|
65
|
+
else
|
|
66
|
+
"#{switch.strip}=#{theme.weak.render(option.arg.strip)}"
|
|
67
|
+
end
|
|
68
|
+
else
|
|
69
|
+
switch
|
|
70
|
+
end
|
|
71
|
+
} + option.short.map { |switch|
|
|
72
|
+
if option.arg
|
|
73
|
+
"#{switch} #{theme.weak.render(option.arg)}"
|
|
74
|
+
else
|
|
75
|
+
switch
|
|
76
|
+
end
|
|
77
|
+
}
|
|
78
|
+
puts "* `#{switches.join(", ")}` - #{option.desc.join(" ")}"
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
if @command.env_vars.any?
|
|
82
|
+
puts
|
|
83
|
+
puts "## ENVIRONMENT VARIABLES"
|
|
84
|
+
puts
|
|
85
|
+
@command.env_vars.sort_by(&:first).each do |env_var|
|
|
86
|
+
puts "* `#{env_var[0]}` - #{env_var[1]}"
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
if @command.commands.any?
|
|
90
|
+
commands_subpath = env["BRUT_HELP_IN_MARKDOWN_COMMAND_PATH"] || "commands"
|
|
91
|
+
puts
|
|
92
|
+
puts "## COMMANDS"
|
|
93
|
+
puts
|
|
94
|
+
@command.commands.sort_by(&:name).each do |command|
|
|
95
|
+
puts "### [`#{command.name}`](./#{commands_subpath}/#{command.name})"
|
|
96
|
+
puts
|
|
97
|
+
puts "#{command.description}"
|
|
98
|
+
if command.detailed_description
|
|
99
|
+
puts
|
|
100
|
+
puts command.detailed_description.gsub(/ +/," ").strip
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
0
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def bootstrap? = false
|
|
108
|
+
def default_rack_env = nil
|
|
109
|
+
end
|
data/lib/brut/cli/commands.rb
CHANGED
|
@@ -2,6 +2,7 @@ module Brut::CLI::Commands
|
|
|
2
2
|
autoload(:BaseCommand, "brut/cli/commands/base_command")
|
|
3
3
|
autoload(:CompoundCommand, "brut/cli/commands/compound_command")
|
|
4
4
|
autoload(:Help, "brut/cli/commands/help")
|
|
5
|
+
autoload(:HelpInMarkdown, "brut/cli/commands/help_in_markdown")
|
|
5
6
|
autoload(:OutputError, "brut/cli/commands/output_error")
|
|
6
7
|
autoload(:RaiseError, "brut/cli/commands/raise_error")
|
|
7
8
|
autoload(:ExecutionContext, "brut/cli/commands/execution_context")
|
data/lib/brut/cli/logger.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require "logger"
|
|
2
2
|
require "fileutils"
|
|
3
|
+
require "pathname"
|
|
3
4
|
require "delegate"
|
|
4
5
|
|
|
5
6
|
class Brut::CLI::Logger < SimpleDelegator
|
|
@@ -58,9 +59,9 @@ class Brut::CLI::Logger < SimpleDelegator
|
|
|
58
59
|
end
|
|
59
60
|
|
|
60
61
|
def log_file=(log_file)
|
|
61
|
-
@log_file = log_file
|
|
62
62
|
if log_file
|
|
63
|
-
|
|
63
|
+
@log_file = Pathname(log_file)
|
|
64
|
+
log_dir = @log_file.dirname
|
|
64
65
|
if !log_dir.exist?
|
|
65
66
|
FileUtils.mkdir_p(log_dir)
|
|
66
67
|
end
|
|
@@ -69,6 +70,8 @@ class Brut::CLI::Logger < SimpleDelegator
|
|
|
69
70
|
if @logger.level == ::Logger::DEBUG
|
|
70
71
|
@stdout.puts "Logging to file #{@log_file}"
|
|
71
72
|
end
|
|
73
|
+
else
|
|
74
|
+
@log_file = nil
|
|
72
75
|
end
|
|
73
76
|
end
|
|
74
77
|
|
|
@@ -30,6 +30,11 @@ class Brut::CLI::ParsedCommandLine
|
|
|
30
30
|
# This should always succeed, however depending on the contents of the parameters, the value
|
|
31
31
|
# for `#command` may be a command that outputs an error.
|
|
32
32
|
def initialize(app_command:, argv:, env:)
|
|
33
|
+
help_command_class = if env["BRUT_HELP_IN_MARKDOWN"] == "true"
|
|
34
|
+
Brut::CLI::Commands::HelpInMarkdown
|
|
35
|
+
else
|
|
36
|
+
Brut::CLI::Commands::Help
|
|
37
|
+
end
|
|
33
38
|
brut_provided_help_requested = false
|
|
34
39
|
app_option_parser = new_option_parser(app_command.name) do |opts|
|
|
35
40
|
opts.banner = app_command.description
|
|
@@ -51,7 +56,7 @@ class Brut::CLI::ParsedCommandLine
|
|
|
51
56
|
end
|
|
52
57
|
|
|
53
58
|
help_command = if brut_provided_help_requested
|
|
54
|
-
|
|
59
|
+
help_command_class.new(app_command,app_option_parser)
|
|
55
60
|
end
|
|
56
61
|
|
|
57
62
|
command = app_command
|
|
@@ -83,7 +88,7 @@ class Brut::CLI::ParsedCommandLine
|
|
|
83
88
|
end
|
|
84
89
|
remaining_argv = command_option_parser.parse!(remaining_argv, into: options)
|
|
85
90
|
if brut_provided_help_requested
|
|
86
|
-
help_command =
|
|
91
|
+
help_command = help_command_class.new(command,command_option_parser)
|
|
87
92
|
elsif help_command
|
|
88
93
|
help_command.option_parser = command_option_parser
|
|
89
94
|
end
|
|
@@ -112,12 +117,16 @@ class Brut::CLI::ParsedCommandLine
|
|
|
112
117
|
if !@options[:'log-file']
|
|
113
118
|
log_file_path = if env["XDG_STATE_HOME"]
|
|
114
119
|
Pathname(env["XDG_STATE_HOME"]) / "brut"
|
|
115
|
-
elsif env["HOME"]
|
|
120
|
+
elsif env["HOME"] && File.writable?(env["HOME"])
|
|
116
121
|
Pathname("#{env['HOME']}/.local/state/") / "brut"
|
|
117
122
|
else
|
|
118
|
-
|
|
123
|
+
nil
|
|
119
124
|
end
|
|
120
|
-
|
|
125
|
+
if log_file_path
|
|
126
|
+
@options[:'log-file'] = log_file_path / (app_command.name + ".log")
|
|
127
|
+
end
|
|
128
|
+
else
|
|
129
|
+
@options[:'log-file'] = Pathname(@options[:'log-file'])
|
|
121
130
|
end
|
|
122
131
|
if @options[:'log-stdout'].nil?
|
|
123
132
|
@options[:'log-stdout'] = @options.verbose? || @options.debug?
|
|
@@ -143,8 +152,7 @@ private
|
|
|
143
152
|
"Project environment, e.g. test, development, production. Default depends on the command")
|
|
144
153
|
opts.on("--log-level=LOG_LEVEL", [ "debug", "info", "warn", "error", "fatal" ],
|
|
145
154
|
"Log level, which should be debug, info, warn, error, or fatal. Defaults to error")
|
|
146
|
-
opts.on("--verbose", "Set log level to debug, and show log messages on stdout")
|
|
147
|
-
opts.on("--debug", "Set log level to debug, and show log messages on stdout")
|
|
155
|
+
opts.on("--debug", "--verbose", "Set log level to debug, and show log messages on stdout")
|
|
148
156
|
opts.on("--quiet", "Set log level to error")
|
|
149
157
|
opts.on("--log-file=FILE",
|
|
150
158
|
"Path to a file where log messages are written. Defaults to $XDG_CACHE_HOME/brut/logs/#{app_name}.log")
|
data/lib/brut/framework/mcp.rb
CHANGED
|
@@ -439,6 +439,7 @@ private
|
|
|
439
439
|
if defined?(OpenTelemetry::Instrumentation::Sidekiq)
|
|
440
440
|
c.use 'OpenTelemetry::Instrumentation::Sidekiq', {
|
|
441
441
|
span_naming: :job_class,
|
|
442
|
+
propagation_style: :child, # XXX: Configurable?
|
|
442
443
|
}
|
|
443
444
|
else
|
|
444
445
|
SemanticLogger[self.class].info "OpenTelemetry::Instrumentation::Sidekiq is not loaded, so Sidekiq traces will not be captured"
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
class Brut::FrontEnd::AssetMetadata
|
|
5
5
|
|
|
6
6
|
# @param [String] asset_metadata_file to the asset metadata file
|
|
7
|
-
# @param [IO] out IO on which to write messaging
|
|
8
7
|
def initialize(asset_metadata_file:,logger: :use_default)
|
|
9
8
|
@asset_metadata_file = asset_metadata_file
|
|
10
9
|
@logger = if logger == :use_default
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
# Extended by {Brut::FrontEnd::Form} to allow declaring inputs.
|
|
1
|
+
# Extended by {Brut::FrontEnd::Form} to allow declaring inputs. This module creates methods per input on the form passed to your handlers. For example, if you have an `input :book_title`, then `form.book_title` will be available to access the value of the "book_title" input.
|
|
2
|
+
#
|
|
3
|
+
# There are two methods that could be created, per input. Examples below use
|
|
4
|
+
# `book_title` as the attribute name
|
|
5
|
+
#
|
|
6
|
+
# * `#book_title` - returns {Brut::FrontEnd::Forms::Input#value}, which is always a string.
|
|
7
|
+
# * `#book_title_coerced` - returns {Brut::FrontEnd::Forms::Input#typed_value}, which is always the correct type for the input **or `nil` if type coercion failed**. Only call this once you have checked for constraint violations
|
|
8
|
+
#
|
|
9
|
+
# For indexed parameters, the above methods require the index to be passed,
|
|
10
|
+
# e.g. `form.book_title_coerced(4)`. For non-indexed parameters, the index may
|
|
11
|
+
# not be passed.
|
|
12
|
+
#
|
|
13
|
+
# Do not use this module directly. Instead, call {#input} or {#select}
|
|
2
14
|
# from within your form's class definition.
|
|
3
15
|
module Brut::FrontEnd::Forms::InputDeclarations
|
|
4
16
|
# Declares an input for this form, to be modeled via an HTML `<INPUT>` tag.
|
|
@@ -59,11 +71,22 @@ module Brut::FrontEnd::Forms::InputDeclarations
|
|
|
59
71
|
end
|
|
60
72
|
self.input(input_definition.name, index:).value
|
|
61
73
|
end
|
|
74
|
+
define_method "#{input_definition.name}_coerced" do |index=nil|
|
|
75
|
+
if index.nil?
|
|
76
|
+
raise ArgumentError,"#{input_definition.name} is an array - you must provide an index to access one of its values"
|
|
77
|
+
end
|
|
78
|
+
self.input(input_definition.name, index:).typed_value
|
|
79
|
+
end
|
|
62
80
|
define_method "#{input_definition.name}_each" do |&block|
|
|
63
81
|
self.inputs(input_definition.name).each_with_index do |input,i|
|
|
64
82
|
block.(input.value,i)
|
|
65
83
|
end
|
|
66
84
|
end
|
|
85
|
+
define_method "#{input_definition.name}_each_coerced" do |&block|
|
|
86
|
+
self.inputs(input_definition.name).each_with_index do |input,i|
|
|
87
|
+
block.(input.typed_value,i)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
67
90
|
else
|
|
68
91
|
define_method input_definition.name do |index_that_should_be_omitted=nil|
|
|
69
92
|
if !index_that_should_be_omitted.nil?
|
|
@@ -71,6 +94,12 @@ module Brut::FrontEnd::Forms::InputDeclarations
|
|
|
71
94
|
end
|
|
72
95
|
self.input(input_definition.name, index: 0).value
|
|
73
96
|
end
|
|
97
|
+
define_method "#{input_definition.name}_coerced" do |index_that_should_be_omitted=nil|
|
|
98
|
+
if !index_that_should_be_omitted.nil?
|
|
99
|
+
raise ArgumentError,"#{input_definition.name} is not an array - do not provide an index when accessing its value"
|
|
100
|
+
end
|
|
101
|
+
self.input(input_definition.name, index: 0).typed_value
|
|
102
|
+
end
|
|
74
103
|
end
|
|
75
104
|
end
|
|
76
105
|
|
|
@@ -23,7 +23,8 @@ module Brut::FrontEnd
|
|
|
23
23
|
include Brut::FrontEnd::HandlingResults
|
|
24
24
|
include Brut::Framework::Errors
|
|
25
25
|
|
|
26
|
-
# You must implement this to
|
|
26
|
+
# You must implement this to perform whatever action your handler must perform. Any information from the request would've been given to your initializer. See {Brut::FrontEnd::RequestContext} for how that works.
|
|
27
|
+
#
|
|
27
28
|
# The type of the return value determines what will happen:
|
|
28
29
|
#
|
|
29
30
|
# * Instance of `URI` - browser will redirect to this URI. Typically, you would do this by calling {Brut::FrontEnd::HandlingResults#redirect_to}.
|
|
@@ -39,7 +40,7 @@ module Brut::FrontEnd
|
|
|
39
40
|
abstract_method!
|
|
40
41
|
end
|
|
41
42
|
|
|
42
|
-
# Override this to
|
|
43
|
+
# Override this to perform any checks before {#handle} is called. This should
|
|
43
44
|
# return `nil` if {#handle} should proceed to be called. Generally, you don't need to override
|
|
44
45
|
# this as {#handle} can include the logic. Where this is useful is to share cross-cutting logic
|
|
45
46
|
# across other handlers.
|
|
@@ -48,8 +49,7 @@ module Brut::FrontEnd
|
|
|
48
49
|
# {#handle} for what each return value means.
|
|
49
50
|
def before_handle = nil
|
|
50
51
|
|
|
51
|
-
# Called by Brut to handle the request. Do not override this. If
|
|
52
|
-
# same args as you have defined for {#handle}. If `before_handle` returns anything other than `nil`, that value is returned and
|
|
52
|
+
# Called by Brut to handle the request. Do not override this. If `before_handle` returns anything other than `nil`, that value is returned and
|
|
53
53
|
# should be one of the values documented in {#handle}. If `before_handle` returns `nil`, {#handle} is called and whatever it
|
|
54
54
|
# returns is returned here.
|
|
55
55
|
def handle!(**args)
|
data/lib/brut/rubocop_config.rb
CHANGED
|
@@ -46,9 +46,9 @@ module Brut
|
|
|
46
46
|
"member?" => "include?",
|
|
47
47
|
},
|
|
48
48
|
},
|
|
49
|
-
"Style/EndlessMethod" => {
|
|
50
|
-
|
|
51
|
-
},
|
|
49
|
+
#"Style/EndlessMethod" => {
|
|
50
|
+
# "EnforcedStyle" => "allow_single_line",
|
|
51
|
+
#},
|
|
52
52
|
"Style/For" => {
|
|
53
53
|
"EnforcedStyle" => "each",
|
|
54
54
|
},
|
|
@@ -15,9 +15,10 @@ class Brut::SpecSupport::E2ETestServer
|
|
|
15
15
|
# from the given bin dir
|
|
16
16
|
#
|
|
17
17
|
# @param [Pathname] bin_dir path to where the app's Brut-provide CLI apps are installed
|
|
18
|
-
def initialize(bin_dir:)
|
|
19
|
-
@bin_dir
|
|
20
|
-
@pid
|
|
18
|
+
def initialize(bin_dir:, start_timeout_seconds: nil)
|
|
19
|
+
@bin_dir = bin_dir
|
|
20
|
+
@pid = nil
|
|
21
|
+
@start_timeout_seconds = start_timeout_seconds || 5
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
# Starts the server. Returns when the server has started
|
|
@@ -66,7 +67,7 @@ private
|
|
|
66
67
|
|
|
67
68
|
def is_port_open?(ip, port)
|
|
68
69
|
begin
|
|
69
|
-
Timeout::timeout(
|
|
70
|
+
Timeout::timeout(@start_timeout_seconds) do
|
|
70
71
|
loop do
|
|
71
72
|
begin
|
|
72
73
|
logger.debug "Attemping to conenct to '#{ip}' on port '#{port}'"
|
|
@@ -47,6 +47,9 @@ class Brut::SpecSupport::Matchers::HaveConstraintViolation
|
|
|
47
47
|
if !form.kind_of?(Brut::FrontEnd::Form)
|
|
48
48
|
raise "#{self.class} only works with forms, not #{form.class}"
|
|
49
49
|
end
|
|
50
|
+
if field.to_s == ""
|
|
51
|
+
raise "field is required"
|
|
52
|
+
end
|
|
50
53
|
@form = form
|
|
51
54
|
@field = field.to_s
|
|
52
55
|
@key = key.to_s
|
data/lib/brut/tui/event_loop.rb
CHANGED
|
@@ -112,7 +112,11 @@ private
|
|
|
112
112
|
errors.each do
|
|
113
113
|
$stderr.puts("FATAL Exception: #{it.exception.class}: #{it.exception.message}\n #{it.exception.backtrace.join("\n ")}")
|
|
114
114
|
end
|
|
115
|
-
|
|
115
|
+
if errors.any?
|
|
116
|
+
exit 1
|
|
117
|
+
else
|
|
118
|
+
exit 0
|
|
119
|
+
end
|
|
116
120
|
else
|
|
117
121
|
errors.each { @queue.unshift(Brut::TUI::Events::Exception.new(it)) }
|
|
118
122
|
end
|
data/lib/brut/version.rb
CHANGED
data/templates/Base/bin/console
CHANGED
data/templates/Base/bin/release
CHANGED
|
@@ -19,7 +19,7 @@ echo "[ bin/release ] started"
|
|
|
19
19
|
echo "[ bin/release ] Creating DB if needed"
|
|
20
20
|
BRUT_CLI_RAISE_ON_ERROR=true bundle exec brut db create --env=production
|
|
21
21
|
echo "[ bin/release ] Migrating DB if needed"
|
|
22
|
-
BRUT_CLI_RAISE_ON_ERROR=true bundle exec
|
|
22
|
+
BRUT_CLI_RAISE_ON_ERROR=true bundle exec brut db migrate --env=production
|
|
23
23
|
|
|
24
24
|
# Add additional commands here as needed
|
|
25
25
|
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
# Insert developer-specifilc Bash customizations here.
|
|
2
|
-
# This file is not checked into version control
|
|
3
|
-
# are safe to export EDITOR=vim and avoid any guff from
|
|
4
|
-
# co-workers.
|
|
5
|
-
|
|
2
|
+
# This file is not checked into version control
|
|
6
3
|
# Sets up a multi-line prompt since the working directory
|
|
7
4
|
# may be very deep. Customize or change at your leisure.
|
|
8
5
|
PS1='\[\e[35m\]docker-container\[\e[0m\] - \[\e[37m\]\w\n\[\e[0m\]> '
|
data/templates/Base/dx/build
CHANGED
|
@@ -48,7 +48,7 @@ setup_playright_build_args() {
|
|
|
48
48
|
require_command "grep"
|
|
49
49
|
require_command "sed"
|
|
50
50
|
|
|
51
|
-
if [ ! -e "${SCRIPT_DIR}"
|
|
51
|
+
if [ ! -e "${SCRIPT_DIR}"/../Gemfile.lock ]; then
|
|
52
52
|
log "Could not find Gemfile.lock, which is needed to determine the playwright-ruby-client version"
|
|
53
53
|
log "Assuming your app is brand-new, this should be OK"
|
|
54
54
|
echo "# When this file was created, there was no Gemfile.lock, so" >> "${SCRIPT_DIR}"/build.args
|
|
@@ -57,7 +57,7 @@ setup_playright_build_args() {
|
|
|
57
57
|
echo "# encouraged to re-run \`dx/build\` to address this issue." >> "${SCRIPT_DIR}"/build.args
|
|
58
58
|
echo PLAYWRIGHT_VERSION=latest >> "${SCRIPT_DIR}"/build.args
|
|
59
59
|
else
|
|
60
|
-
PLAYWRIGHT_VERSION=$(grep playwright-ruby-client Gemfile.lock | grep '(' | sed 's/^.*(//' | sed 's/).*$//' | grep -v ^=)
|
|
60
|
+
PLAYWRIGHT_VERSION=$(grep playwright-ruby-client $SCRIPT_DIR/../Gemfile.lock | grep '(' | sed 's/^.*(//' | sed 's/).*$//' | grep -v ^=)
|
|
61
61
|
if [ -z "${PLAYWRIGHT_VERSION}" ]; then
|
|
62
62
|
log "Could not find precise version of playwright-ruby-client from Gemfile.lock"
|
|
63
63
|
log "This means that your playwright-ruby-client version and playwright NPM modules may be out of sync and may not work"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: brut
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.20.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Bryant Copeland
|
|
@@ -475,16 +475,16 @@ dependencies:
|
|
|
475
475
|
name: yard
|
|
476
476
|
requirement: !ruby/object:Gem::Requirement
|
|
477
477
|
requirements:
|
|
478
|
-
- -
|
|
478
|
+
- - '='
|
|
479
479
|
- !ruby/object:Gem::Version
|
|
480
|
-
version:
|
|
480
|
+
version: 0.9.37
|
|
481
481
|
type: :development
|
|
482
482
|
prerelease: false
|
|
483
483
|
version_requirements: !ruby/object:Gem::Requirement
|
|
484
484
|
requirements:
|
|
485
|
-
- -
|
|
485
|
+
- - '='
|
|
486
486
|
- !ruby/object:Gem::Version
|
|
487
|
-
version:
|
|
487
|
+
version: 0.9.37
|
|
488
488
|
description: An opinionated web framework build on web standards
|
|
489
489
|
email:
|
|
490
490
|
- davec@thirdtank.com
|
|
@@ -548,6 +548,7 @@ files:
|
|
|
548
548
|
- lib/brut/cli/commands/compound_command.rb
|
|
549
549
|
- lib/brut/cli/commands/execution_context.rb
|
|
550
550
|
- lib/brut/cli/commands/help.rb
|
|
551
|
+
- lib/brut/cli/commands/help_in_markdown.rb
|
|
551
552
|
- lib/brut/cli/commands/output_error.rb
|
|
552
553
|
- lib/brut/cli/commands/raise_error.rb
|
|
553
554
|
- lib/brut/cli/error.rb
|
|
@@ -719,7 +720,6 @@ files:
|
|
|
719
720
|
- lib/sequel/plugins/find_bang.rb
|
|
720
721
|
- templates/Base/.dockerignore
|
|
721
722
|
- templates/Base/.env.development.erb
|
|
722
|
-
- templates/Base/.env.development.local
|
|
723
723
|
- templates/Base/.env.test.erb
|
|
724
724
|
- templates/Base/.gitignore
|
|
725
725
|
- templates/Base/.projections.json
|
|
@@ -736,6 +736,7 @@ files:
|
|
|
736
736
|
- templates/Base/app/src/app.rb.erb
|
|
737
737
|
- templates/Base/app/src/back_end/data_models/app_data_model.rb
|
|
738
738
|
- templates/Base/app/src/back_end/data_models/db.rb
|
|
739
|
+
- templates/Base/app/src/back_end/data_models/db/README.md
|
|
739
740
|
- templates/Base/app/src/back_end/data_models/migrations/20240101130000_citext.rb
|
|
740
741
|
- templates/Base/app/src/back_end/data_models/seed/seed_data.rb
|
|
741
742
|
- templates/Base/app/src/front_end/components/app_component.rb
|
|
@@ -851,7 +852,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
851
852
|
- !ruby/object:Gem::Version
|
|
852
853
|
version: '0'
|
|
853
854
|
requirements: []
|
|
854
|
-
rubygems_version:
|
|
855
|
+
rubygems_version: 4.0.8
|
|
855
856
|
specification_version: 4
|
|
856
857
|
summary: Web Framework Built around Ruby, Web Standards, Simplicity, and Object-Orientation
|
|
857
858
|
test_files: []
|