asgard 0.3.1 → 0.3.3
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/.envrc +5 -0
- data/.loki +14 -1
- data/.reek.yml +115 -0
- data/.rubocop.yml +6 -0
- data/Archspec.rb +24 -0
- data/CHANGELOG.md +72 -1
- data/CLAUDE.md +4 -7
- data/README.md +51 -1
- data/bin/asgard +1 -1
- data/doc_tasks.loki +21 -0
- data/docs/api.md +125 -6
- data/docs/changelog.md +23 -1
- data/docs/dependencies.md +94 -2
- data/docs/getting-started.md +4 -2
- data/docs/index.md +3 -3
- data/docs/options.md +16 -6
- data/docs/shell.md +30 -1
- data/docs/tasks.md +40 -0
- data/examples/bad.loki +63 -0
- data/examples/depends_on_block/bad/.loki +51 -0
- data/examples/depends_on_block/good/.loki +83 -0
- data/examples/kitchen_sink.loki +13 -0
- data/gem_tasks.loki +17 -1
- data/git.loki +13 -0
- data/lib/asgard/base/dependency_graph.rb +160 -0
- data/lib/asgard/base/dispatch.rb +160 -0
- data/lib/asgard/base/registry.rb +38 -0
- data/lib/asgard/base/task_dsl.rb +64 -0
- data/lib/asgard/base.rb +36 -250
- data/lib/asgard/doctor/report.rb +73 -0
- data/lib/asgard/doctor/task_sections.rb +67 -0
- data/lib/asgard/doctor.rb +150 -0
- data/lib/asgard/kernel_methods.rb +6 -2
- data/lib/asgard/shell.rb +21 -8
- data/lib/asgard/tasks.rb +6 -0
- data/lib/asgard/version.rb +1 -1
- data/lib/asgard.rb +9 -1
- data/quality.loki +218 -32
- data/quality_rails.loki +47 -0
- data/xyzzy.loki +12 -0
- metadata +18 -16
data/lib/asgard/version.rb
CHANGED
data/lib/asgard.rb
CHANGED
|
@@ -5,6 +5,7 @@ require_relative "asgard/kernel_methods"
|
|
|
5
5
|
require_relative "asgard/shell"
|
|
6
6
|
require_relative "asgard/base"
|
|
7
7
|
require_relative "asgard/tasks"
|
|
8
|
+
require_relative "asgard/doctor"
|
|
8
9
|
|
|
9
10
|
module Asgard
|
|
10
11
|
class Error < StandardError; end
|
|
@@ -18,11 +19,16 @@ module Asgard
|
|
|
18
19
|
|
|
19
20
|
# Main entry point invoked by the asgard executable.
|
|
20
21
|
def self.run!(argv)
|
|
21
|
-
|
|
22
|
+
first = argv.first
|
|
23
|
+
abort "asgard: unknown command '#{first}'" if first&.start_with?("_")
|
|
22
24
|
if argv.include?("--version")
|
|
23
25
|
puts Asgard::VERSION
|
|
24
26
|
exit
|
|
25
27
|
end
|
|
28
|
+
if argv.include?("--doctor")
|
|
29
|
+
Asgard::Doctor.new.run
|
|
30
|
+
exit
|
|
31
|
+
end
|
|
26
32
|
task_file = find_task_file or abort "asgard: no .loki file found in #{Dir.pwd}"
|
|
27
33
|
before = Asgard::Base.subclasses.dup
|
|
28
34
|
load task_file
|
|
@@ -34,5 +40,7 @@ module Asgard
|
|
|
34
40
|
abort "asgard: circular dependency — #{e.message}"
|
|
35
41
|
rescue Error => e
|
|
36
42
|
abort "asgard: #{e.message}"
|
|
43
|
+
rescue Interrupt
|
|
44
|
+
exit(130)
|
|
37
45
|
end
|
|
38
46
|
end
|
data/quality.loki
CHANGED
|
@@ -3,44 +3,41 @@
|
|
|
3
3
|
|
|
4
4
|
class Tasks
|
|
5
5
|
desc "Run the test suite"
|
|
6
|
-
def
|
|
6
|
+
def test_check
|
|
7
7
|
output = `bundle exec ruby -Ilib:test test/test_asgard.rb 2>&1`
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
print lines[start..finish].join
|
|
14
|
-
end
|
|
8
|
+
result = $?.success? ? :pass : :fail
|
|
9
|
+
File.write("test_output.txt", output)
|
|
10
|
+
summary = output.lines.reverse.find { |l| l =~ /\d+ runs,/ }&.strip || result.to_s
|
|
11
|
+
puts "Tests: #{summary} (see test_output.txt)"
|
|
12
|
+
result
|
|
15
13
|
end
|
|
16
14
|
|
|
17
|
-
desc "Run
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
desc "Run the test suite with verbose output"
|
|
16
|
+
def test_verbose
|
|
17
|
+
sh "bundle exec ruby -Ilib:test test/test_asgard.rb -v"
|
|
18
|
+
end
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
desc "Run every *_check quality gate task in parallel"
|
|
21
|
+
# A Proc defers resolution to validate_deps!, after every .loki file has
|
|
22
|
+
# loaded — so a *_check task from another file (e.g. quality_rails.loki's
|
|
23
|
+
# brakeman_check) is picked up too, with no need to redeclare anything here.
|
|
24
|
+
depends_on -> { [all_commands.keys.grep(/_check\z/).sort.map(&:to_sym)] }
|
|
25
|
+
def quality
|
|
26
|
+
check_tasks = self.class._deps.fetch(:quality, []).flatten.map(&:to_s)
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
puts "Quality Summary"
|
|
29
|
-
puts "=" * 60
|
|
30
|
-
results.each { |gate, status| puts " [#{status == :pass ? "PASS" : "FAIL"}] #{gate}" }
|
|
31
|
-
puts "=" * 60
|
|
28
|
+
results = check_tasks.to_h { |name| [quality_gate_label(name), dep_result(name)] }
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
puts "\nAll quality gates passed."
|
|
30
|
+
print_quality_summary(results)
|
|
35
31
|
end
|
|
36
32
|
|
|
37
33
|
desc "Check code style with RuboCop"
|
|
38
|
-
def
|
|
34
|
+
def rubocop_check
|
|
39
35
|
output = `RUBOCOP_CACHE_ROOT=tmp/rubocop_cache bundle exec rubocop 2>&1`
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
result = $?.success? ? :pass : :fail
|
|
37
|
+
File.write("rubocop_output.txt", output)
|
|
38
|
+
summary = output.lines.find { |l| l =~ /files inspected/ }&.strip || result.to_s
|
|
39
|
+
puts "RuboCop: #{summary} (see rubocop_output.txt)"
|
|
40
|
+
result
|
|
44
41
|
end
|
|
45
42
|
|
|
46
43
|
desc "Auto-correct RuboCop offenses"
|
|
@@ -58,18 +55,207 @@ class Tasks
|
|
|
58
55
|
flogger = Flog.new(all: true)
|
|
59
56
|
flogger.flog(*Dir.glob("lib/**/*.rb"))
|
|
60
57
|
|
|
61
|
-
warnings
|
|
62
|
-
|
|
58
|
+
warnings = []
|
|
59
|
+
failures = []
|
|
63
60
|
|
|
64
61
|
flogger.each_by_score do |method_name, score|
|
|
65
62
|
next if method_name.end_with?("#none")
|
|
66
63
|
if score > method_fail
|
|
67
|
-
|
|
64
|
+
failures << "#{"%.1f" % score}: #{method_name}"
|
|
68
65
|
elsif score > method_warn
|
|
69
66
|
warnings << "#{"%.1f" % score}: #{method_name}"
|
|
70
67
|
end
|
|
71
68
|
end
|
|
72
69
|
|
|
73
|
-
|
|
70
|
+
result = failures.empty? ? :pass : :fail
|
|
71
|
+
|
|
72
|
+
lines = ["Flog warnings (#{method_warn}–#{method_fail}):"]
|
|
73
|
+
lines.concat(warnings.empty? ? [" (none)"] : warnings.map { |w| " #{w}" })
|
|
74
|
+
lines << ""
|
|
75
|
+
lines << "Flog failures (>= #{method_fail}):"
|
|
76
|
+
lines.concat(failures.empty? ? [" (none)"] : failures.map { |f| " #{f}" })
|
|
77
|
+
File.write("flog_output.txt", "#{lines.join("\n")}\n")
|
|
78
|
+
|
|
79
|
+
puts "Flog: #{failures.size} failure(s), #{warnings.size} warning(s) (see flog_output.txt)"
|
|
80
|
+
result
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
desc "Check for structural code duplication with Flay (mass >= 150)"
|
|
84
|
+
def flay_check
|
|
85
|
+
require "flay"
|
|
86
|
+
|
|
87
|
+
mass_threshold = 150
|
|
88
|
+
|
|
89
|
+
flay = Flay.new(mass: mass_threshold, diff: false, verbose: false, summary: false, timeout: 60)
|
|
90
|
+
flay.process(*Dir.glob("lib/**/*.rb"))
|
|
91
|
+
flay.analyze
|
|
92
|
+
|
|
93
|
+
result = flay.hashes.empty? ? :pass : :fail
|
|
94
|
+
|
|
95
|
+
File.open("flay_output.txt", "w") do |f|
|
|
96
|
+
if result == :pass
|
|
97
|
+
f.puts "Flay: no structural duplication detected (mass >= #{mass_threshold})"
|
|
98
|
+
else
|
|
99
|
+
flay.report(f)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
puts "Flay: #{flay.hashes.size} duplication pattern(s) found (mass >= #{mass_threshold}) (see flay_output.txt)"
|
|
103
|
+
result
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
desc "Check code smells with Reek"
|
|
107
|
+
def reek_check
|
|
108
|
+
output = `bundle exec reek lib 2>&1`
|
|
109
|
+
result = $?.success? ? :pass : :fail
|
|
110
|
+
File.write("reek_output.txt", output)
|
|
111
|
+
summary = output.lines.reverse.find { |l| l =~ /total warnings?/ }&.strip || result.to_s
|
|
112
|
+
puts "Reek: #{summary} (see reek_output.txt)"
|
|
113
|
+
result
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
desc "Check spelling with typos"
|
|
117
|
+
def typos_check
|
|
118
|
+
return skip_typos unless command_available?("typos")
|
|
119
|
+
|
|
120
|
+
output = `typos 2>&1`
|
|
121
|
+
result = $?.success? ? :pass : :fail
|
|
122
|
+
File.write("typos_output.txt", output)
|
|
123
|
+
count = output.lines.count { |l| l.start_with?("error:") }
|
|
124
|
+
summary = result == :pass ? "no typos found" : "#{count} typo(s) found"
|
|
125
|
+
puts "Typos: #{summary} (see typos_output.txt)"
|
|
126
|
+
result
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
desc "Auto-correct typos"
|
|
130
|
+
def typos_fix
|
|
131
|
+
return skip_typos unless command_available?("typos")
|
|
132
|
+
|
|
133
|
+
sh "typos -w"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
desc "Check ERB templates for style and safety issues with ERBLint"
|
|
137
|
+
def erb_lint_check
|
|
138
|
+
return skip_erb_lint if Dir.glob("**/*.erb").empty?
|
|
139
|
+
|
|
140
|
+
output = `bundle exec erb_lint --lint-all --enable-all-linters 2>&1`
|
|
141
|
+
result = $?.success? ? :pass : :fail
|
|
142
|
+
File.write("erb_lint_output.txt", output)
|
|
143
|
+
summary = output.lines.reverse.find { |l| l =~ /error\(s\)|no errors were found/i }&.strip || result.to_s
|
|
144
|
+
puts "ERBLint: #{summary} (see erb_lint_output.txt)"
|
|
145
|
+
result
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
desc "Check for performance suggestions with Fasterer"
|
|
149
|
+
def fasterer_check
|
|
150
|
+
output = `bundle exec fasterer lib 2>&1`.gsub(/\e\[\d+m/, "")
|
|
151
|
+
result = $?.success? ? :pass : :warn
|
|
152
|
+
File.write("fasterer_output.txt", output)
|
|
153
|
+
summary = output.lines.find { |l| l =~ /files? inspected/ }&.strip || result.to_s
|
|
154
|
+
puts "Fasterer: #{summary} (see fasterer_output.txt)"
|
|
155
|
+
result
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
desc "Check Gemfile.lock for known vulnerabilities with bundler-audit"
|
|
159
|
+
def bundler_audit_check
|
|
160
|
+
output = `bundle exec bundle-audit check --update 2>&1`
|
|
161
|
+
result = $?.success? ? :pass : :fail
|
|
162
|
+
File.write("bundler_audit_output.txt", output)
|
|
163
|
+
summary = output.lines.reverse.find { |l| l =~ /vulnerabilit/i }&.strip || result.to_s
|
|
164
|
+
puts "Bundler Audit: #{summary} (see bundler_audit_output.txt)"
|
|
165
|
+
result
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
desc "Check architecture boundaries with ArchSpec"
|
|
169
|
+
def archspec_check
|
|
170
|
+
return skip_archspec unless command_available?("archspec") && File.exist?("Archspec.rb")
|
|
171
|
+
|
|
172
|
+
output = `archspec check 2>&1`
|
|
173
|
+
result = $?.success? ? :pass : :fail
|
|
174
|
+
File.write("archspec_output.txt", output)
|
|
175
|
+
summary = output.lines.reverse.find { |l| l =~ /architecture violations? found|ArchSpec passed/i }&.strip ||
|
|
176
|
+
result.to_s
|
|
177
|
+
puts "ArchSpec: #{summary} (see archspec_output.txt)"
|
|
178
|
+
result
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Curated display labels for the *_check tasks defined in this file. A
|
|
182
|
+
# *_check task from elsewhere (e.g. quality_rails.loki's brakeman_check,
|
|
183
|
+
# loaded automatically once Rails is defined) isn't listed here — it just
|
|
184
|
+
# falls back to a titleized version of its own name in quality_gate_label.
|
|
185
|
+
QUALITY_GATE_LABELS = {
|
|
186
|
+
"test_check" => "Tests + Coverage",
|
|
187
|
+
"rubocop_check" => "RuboCop",
|
|
188
|
+
"flog_check" => "Flog Complexity",
|
|
189
|
+
"flay_check" => "Flay Duplication",
|
|
190
|
+
"reek_check" => "Reek Smells",
|
|
191
|
+
"erb_lint_check" => "ERBLint",
|
|
192
|
+
"archspec_check" => "ArchSpec",
|
|
193
|
+
}.freeze
|
|
194
|
+
|
|
195
|
+
no_commands do
|
|
196
|
+
# true if +name+ resolves to an executable file somewhere on PATH.
|
|
197
|
+
def command_available?(name)
|
|
198
|
+
ENV.fetch("PATH", "").split(File::PATH_SEPARATOR).any? do |dir|
|
|
199
|
+
File.executable?(File.join(dir, name))
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def quality_gate_label(check_name)
|
|
204
|
+
QUALITY_GATE_LABELS.fetch(check_name) do
|
|
205
|
+
check_name.delete_suffix("_check").split("_").map(&:capitalize).join(" ")
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def skip_typos
|
|
210
|
+
puts "Typos: SKIPPED — `typos` command not found. Install it with `brew install typos-cli`."
|
|
211
|
+
:skip
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def skip_erb_lint
|
|
215
|
+
puts "ERBLint: SKIPPED — no .erb files found."
|
|
216
|
+
:skip
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def skip_archspec
|
|
220
|
+
reason = command_available?("archspec") ? "no Archspec.rb found" : "`archspec` command not found"
|
|
221
|
+
puts "ArchSpec: SKIPPED — #{reason}. Install it with `gem install archspec` " \
|
|
222
|
+
"and run `archspec init` to generate one."
|
|
223
|
+
:skip
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Status badges. Only :fail is blocking (aborts the quality task);
|
|
227
|
+
# :skip (a required tool isn't installed) and :warn (the check ran but
|
|
228
|
+
# has non-blocking suggestions, e.g. a performance-hint gate) are not.
|
|
229
|
+
STATUS_BADGES = {
|
|
230
|
+
pass: ["PASS", 32], # green
|
|
231
|
+
fail: ["FAIL", 31], # red
|
|
232
|
+
warn: ["WARN", 33], # yellow
|
|
233
|
+
skip: ["SKIP", 36], # cyan
|
|
234
|
+
}.freeze
|
|
235
|
+
|
|
236
|
+
# Colorized status badges plus a pass/fail/warn/skip tally; aborts only
|
|
237
|
+
# if any gate failed — skip and warn are informational, not blocking.
|
|
238
|
+
def print_quality_summary(results)
|
|
239
|
+
colorize_badge = ->(code, text) { "\e[#{code}m#{text}\e[0m" }
|
|
240
|
+
width = results.keys.map(&:length).max
|
|
241
|
+
|
|
242
|
+
puts "\n#{"=" * 60}"
|
|
243
|
+
puts "Quality Gate Summary"
|
|
244
|
+
puts "=" * 60
|
|
245
|
+
results.each do |label, status|
|
|
246
|
+
text, code = STATUS_BADGES.fetch(status)
|
|
247
|
+
puts " [#{colorize_badge.call(code, text)}] #{label.ljust(width)}"
|
|
248
|
+
end
|
|
249
|
+
puts "-" * 60
|
|
250
|
+
|
|
251
|
+
counts = results.values.tally
|
|
252
|
+
failed = counts[:fail] || 0
|
|
253
|
+
tally = STATUS_BADGES.keys.filter_map { |s| "#{counts[s]} #{s}" if counts[s]&.positive? }.join(", ")
|
|
254
|
+
puts " #{colorize_badge.call(failed.zero? ? 32 : 31, tally)}"
|
|
255
|
+
puts "=" * 60
|
|
256
|
+
|
|
257
|
+
abort "\n#{colorize_badge.call(31, "Quality gate failed.")}" unless failed.zero?
|
|
258
|
+
puts "\n#{colorize_badge.call(32, "All quality gates passed.")}"
|
|
259
|
+
end
|
|
74
260
|
end
|
|
75
261
|
end
|
data/quality_rails.loki
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Rails-specific quality gate tasks — imported by .loki only when RAILS_ROOT
|
|
3
|
+
# is set. asgard runs as a separate process outside the app it's checking,
|
|
4
|
+
# so `defined?(Rails)` never sees the app's Rails constant.
|
|
5
|
+
#
|
|
6
|
+
# `quality` (in quality.loki) discovers every *_check task at run time by
|
|
7
|
+
# introspecting Tasks.all_commands, rather than a fixed depends_on list — so
|
|
8
|
+
# any *_check task defined here is automatically picked up by `asgard
|
|
9
|
+
# quality` too, with no need to redeclare or extend anything.
|
|
10
|
+
#
|
|
11
|
+
# Note on rubocop-rails: it's a RuboCop plugin, not a standalone CLI, so it
|
|
12
|
+
# has no *_check task of its own here. Add the gem to the app's Gemfile and
|
|
13
|
+
# `require: rubocop-rails` in its .rubocop.yml — the existing rubocop_check
|
|
14
|
+
# (quality.loki) picks up the added Rails cops automatically.
|
|
15
|
+
|
|
16
|
+
class Tasks
|
|
17
|
+
desc "Check for Rails security vulnerabilities with Brakeman"
|
|
18
|
+
def brakeman_check
|
|
19
|
+
output = `bundle exec brakeman -q 2>&1`
|
|
20
|
+
result = $?.success? ? :pass : :fail
|
|
21
|
+
File.write("brakeman_output.txt", output)
|
|
22
|
+
summary = output.lines.reverse.find { |l| l =~ /warnings? found/i }&.strip || result.to_s
|
|
23
|
+
puts "Brakeman: #{summary} (see brakeman_output.txt)"
|
|
24
|
+
result
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
desc "Check for Rails anti-patterns with RailsBestPractices"
|
|
28
|
+
def rails_best_practices_check
|
|
29
|
+
output = `bundle exec rails_best_practices --silent --without-color . 2>&1`
|
|
30
|
+
result = $?.success? ? :pass : :fail
|
|
31
|
+
File.write("rails_best_practices_output.txt", output)
|
|
32
|
+
summary = output.lines.reverse.find { |l| l =~ /warning/i }&.strip || result.to_s
|
|
33
|
+
puts "RailsBestPractices: #{summary} (see rails_best_practices_output.txt)"
|
|
34
|
+
result
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
desc "Check for database schema issues with ActiveRecordDoctor"
|
|
38
|
+
def active_record_doctor_check
|
|
39
|
+
output = `bundle exec rake active_record_doctor 2>&1`
|
|
40
|
+
result = $?.success? ? :pass : :fail
|
|
41
|
+
File.write("active_record_doctor_output.txt", output)
|
|
42
|
+
issue_count = output.lines.count { |l| l.strip != "" }
|
|
43
|
+
summary = result == :pass ? "no issues found" : "#{issue_count} issue line(s) found"
|
|
44
|
+
puts "ActiveRecordDoctor: #{summary} (see active_record_doctor_output.txt)"
|
|
45
|
+
result
|
|
46
|
+
end
|
|
47
|
+
end
|
data/xyzzy.loki
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# example of an overwritten task detected by (--doctor) — imported by .loki
|
|
3
|
+
|
|
4
|
+
class Tasks
|
|
5
|
+
desc "Push the current branch to its remote"
|
|
6
|
+
def xyzzy = puts <<~MAGIC
|
|
7
|
+
You are at a fork in the yellow brick road to AI.
|
|
8
|
+
To the left is python, the favorite programming language of snake charmers.
|
|
9
|
+
To the right is Ruby, the best computer programming language of all time.
|
|
10
|
+
Which way do you go?
|
|
11
|
+
MAGIC
|
|
12
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: asgard
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dewayne VanHoozer
|
|
@@ -23,20 +23,6 @@ dependencies:
|
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '1.0'
|
|
26
|
-
- !ruby/object:Gem::Dependency
|
|
27
|
-
name: dagwood
|
|
28
|
-
requirement: !ruby/object:Gem::Requirement
|
|
29
|
-
requirements:
|
|
30
|
-
- - "~>"
|
|
31
|
-
- !ruby/object:Gem::Version
|
|
32
|
-
version: '1.0'
|
|
33
|
-
type: :runtime
|
|
34
|
-
prerelease: false
|
|
35
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
-
requirements:
|
|
37
|
-
- - "~>"
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: '1.0'
|
|
40
26
|
- !ruby/object:Gem::Dependency
|
|
41
27
|
name: dotenv
|
|
42
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -65,7 +51,9 @@ files:
|
|
|
65
51
|
- ".envrc"
|
|
66
52
|
- ".github/workflows/deploy-github-pages.yml"
|
|
67
53
|
- ".loki"
|
|
54
|
+
- ".reek.yml"
|
|
68
55
|
- ".rubocop.yml"
|
|
56
|
+
- Archspec.rb
|
|
69
57
|
- CHANGELOG.md
|
|
70
58
|
- CLAUDE.md
|
|
71
59
|
- COMMITS.md
|
|
@@ -74,6 +62,7 @@ files:
|
|
|
74
62
|
- bin/asgard
|
|
75
63
|
- bin/console
|
|
76
64
|
- bin/setup
|
|
65
|
+
- doc_tasks.loki
|
|
77
66
|
- docs/api.md
|
|
78
67
|
- docs/assets/css/custom.css
|
|
79
68
|
- docs/assets/images/asgard.jpg
|
|
@@ -92,8 +81,11 @@ files:
|
|
|
92
81
|
- docs/variables.md
|
|
93
82
|
- examples/.env
|
|
94
83
|
- examples/.loki
|
|
84
|
+
- examples/bad.loki
|
|
95
85
|
- examples/concurrent.loki
|
|
96
86
|
- examples/db_subcommands.loki
|
|
87
|
+
- examples/depends_on_block/bad/.loki
|
|
88
|
+
- examples/depends_on_block/good/.loki
|
|
97
89
|
- examples/env_usage.loki
|
|
98
90
|
- examples/kitchen_sink.loki
|
|
99
91
|
- examples/server_subcommands.loki
|
|
@@ -101,15 +93,25 @@ files:
|
|
|
101
93
|
- examples/subdir/import_demo.loki
|
|
102
94
|
- examples/subdir/import_up_demo.loki
|
|
103
95
|
- gem_tasks.loki
|
|
96
|
+
- git.loki
|
|
104
97
|
- lib/asgard.rb
|
|
105
98
|
- lib/asgard/base.rb
|
|
99
|
+
- lib/asgard/base/dependency_graph.rb
|
|
100
|
+
- lib/asgard/base/dispatch.rb
|
|
101
|
+
- lib/asgard/base/registry.rb
|
|
102
|
+
- lib/asgard/base/task_dsl.rb
|
|
103
|
+
- lib/asgard/doctor.rb
|
|
104
|
+
- lib/asgard/doctor/report.rb
|
|
105
|
+
- lib/asgard/doctor/task_sections.rb
|
|
106
106
|
- lib/asgard/kernel_methods.rb
|
|
107
107
|
- lib/asgard/shell.rb
|
|
108
108
|
- lib/asgard/tasks.rb
|
|
109
109
|
- lib/asgard/version.rb
|
|
110
110
|
- mkdocs.yml
|
|
111
111
|
- quality.loki
|
|
112
|
+
- quality_rails.loki
|
|
112
113
|
- sig/asgard.rbs
|
|
114
|
+
- xyzzy.loki
|
|
113
115
|
homepage: https://github.com/madbomber/asgard
|
|
114
116
|
licenses:
|
|
115
117
|
- MIT
|
|
@@ -132,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
132
134
|
- !ruby/object:Gem::Version
|
|
133
135
|
version: '0'
|
|
134
136
|
requirements: []
|
|
135
|
-
rubygems_version: 4.0.
|
|
137
|
+
rubygems_version: 4.0.19
|
|
136
138
|
specification_version: 4
|
|
137
139
|
summary: A powerful Ruby-based task runner
|
|
138
140
|
test_files: []
|