asgard 0.3.1 → 0.3.2
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 +8 -1
- data/.reek.yml +112 -0
- data/.rubocop.yml +6 -0
- data/Archspec.rb +24 -0
- data/CHANGELOG.md +57 -1
- data/CLAUDE.md +4 -7
- data/README.md +10 -1
- data/bin/asgard +1 -1
- data/docs/api.md +122 -5
- data/docs/changelog.md +21 -1
- data/docs/dependencies.md +83 -2
- data/docs/getting-started.md +4 -2
- data/docs/index.md +3 -3
- data/docs/options.md +16 -6
- data/examples/bad.loki +63 -0
- data/gem_tasks.loki +17 -1
- data/git.loki +13 -0
- data/lib/asgard/base/dependency_graph.rb +124 -0
- data/lib/asgard/base/dispatch.rb +160 -0
- data/lib/asgard/base/registry.rb +38 -0
- data/lib/asgard/base/task_dsl.rb +65 -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/tasks.rb +6 -0
- data/lib/asgard/version.rb +1 -1
- data/lib/asgard.rb +7 -1
- data/quality.loki +218 -32
- data/quality_rails.loki +46 -0
- data/xyzzy.loki +12 -0
- metadata +15 -16
|
@@ -29,11 +29,15 @@ module Kernel
|
|
|
29
29
|
end
|
|
30
30
|
module_function :loki_up
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
# +from+ is the call-site location used to resolve a relative +path+. It
|
|
33
|
+
# defaults to the immediate caller, but is exposed as a keyword so a
|
|
34
|
+
# wrapper (e.g. Asgard::Doctor's import tracer, prepended via `super`)
|
|
35
|
+
# can thread through the *real* caller instead of its own frame.
|
|
36
|
+
def import(path, from: caller_locations(1, 1).first)
|
|
33
37
|
path = path.to_s
|
|
34
38
|
raise ArgumentError, "import: path must end with .loki (got #{path.inspect})" unless path.end_with?(".loki")
|
|
35
39
|
unless File.absolute_path?(path)
|
|
36
|
-
caller_dir = File.dirname(
|
|
40
|
+
caller_dir = File.dirname(from.absolute_path)
|
|
37
41
|
path = File.expand_path(path, caller_dir)
|
|
38
42
|
end
|
|
39
43
|
paths = path =~ /[*?\[{]/ ? Dir.glob(path) : [path]
|
data/lib/asgard/tasks.rb
CHANGED
|
@@ -26,4 +26,10 @@ class Tasks < Asgard::Base
|
|
|
26
26
|
default: false,
|
|
27
27
|
desc: "Show asgard version and exit"
|
|
28
28
|
no_negate :version
|
|
29
|
+
|
|
30
|
+
class_option :doctor,
|
|
31
|
+
type: :boolean,
|
|
32
|
+
default: false,
|
|
33
|
+
desc: "Diagnose .loki resolution, imports, and task definitions for the CWD, then exit"
|
|
34
|
+
no_negate :doctor
|
|
29
35
|
end
|
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
|
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,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Rails-specific quality gate tasks — imported by .loki only when the Rails
|
|
3
|
+
# constant is defined.
|
|
4
|
+
#
|
|
5
|
+
# `quality` (in quality.loki) discovers every *_check task at run time by
|
|
6
|
+
# introspecting Tasks.all_commands, rather than a fixed depends_on list — so
|
|
7
|
+
# any *_check task defined here is automatically picked up by `asgard
|
|
8
|
+
# quality` too, with no need to redeclare or extend anything.
|
|
9
|
+
#
|
|
10
|
+
# Note on rubocop-rails: it's a RuboCop plugin, not a standalone CLI, so it
|
|
11
|
+
# has no *_check task of its own here. Add the gem to the app's Gemfile and
|
|
12
|
+
# `require: rubocop-rails` in its .rubocop.yml — the existing rubocop_check
|
|
13
|
+
# (quality.loki) picks up the added Rails cops automatically.
|
|
14
|
+
|
|
15
|
+
class Tasks
|
|
16
|
+
desc "Check for Rails security vulnerabilities with Brakeman"
|
|
17
|
+
def brakeman_check
|
|
18
|
+
output = `bundle exec brakeman -q 2>&1`
|
|
19
|
+
result = $?.success? ? :pass : :fail
|
|
20
|
+
File.write("brakeman_output.txt", output)
|
|
21
|
+
summary = output.lines.reverse.find { |l| l =~ /warnings? found/i }&.strip || result.to_s
|
|
22
|
+
puts "Brakeman: #{summary} (see brakeman_output.txt)"
|
|
23
|
+
result
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
desc "Check for Rails anti-patterns with RailsBestPractices"
|
|
27
|
+
def rails_best_practices_check
|
|
28
|
+
output = `bundle exec rails_best_practices --silent --without-color . 2>&1`
|
|
29
|
+
result = $?.success? ? :pass : :fail
|
|
30
|
+
File.write("rails_best_practices_output.txt", output)
|
|
31
|
+
summary = output.lines.reverse.find { |l| l =~ /warning/i }&.strip || result.to_s
|
|
32
|
+
puts "RailsBestPractices: #{summary} (see rails_best_practices_output.txt)"
|
|
33
|
+
result
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
desc "Check for database schema issues with ActiveRecordDoctor"
|
|
37
|
+
def active_record_doctor_check
|
|
38
|
+
output = `bundle exec rake active_record_doctor 2>&1`
|
|
39
|
+
result = $?.success? ? :pass : :fail
|
|
40
|
+
File.write("active_record_doctor_output.txt", output)
|
|
41
|
+
issue_count = output.lines.count { |l| l.strip != "" }
|
|
42
|
+
summary = result == :pass ? "no issues found" : "#{issue_count} issue line(s) found"
|
|
43
|
+
puts "ActiveRecordDoctor: #{summary} (see active_record_doctor_output.txt)"
|
|
44
|
+
result
|
|
45
|
+
end
|
|
46
|
+
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.2
|
|
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
|
|
@@ -92,6 +80,7 @@ files:
|
|
|
92
80
|
- docs/variables.md
|
|
93
81
|
- examples/.env
|
|
94
82
|
- examples/.loki
|
|
83
|
+
- examples/bad.loki
|
|
95
84
|
- examples/concurrent.loki
|
|
96
85
|
- examples/db_subcommands.loki
|
|
97
86
|
- examples/env_usage.loki
|
|
@@ -101,15 +90,25 @@ files:
|
|
|
101
90
|
- examples/subdir/import_demo.loki
|
|
102
91
|
- examples/subdir/import_up_demo.loki
|
|
103
92
|
- gem_tasks.loki
|
|
93
|
+
- git.loki
|
|
104
94
|
- lib/asgard.rb
|
|
105
95
|
- lib/asgard/base.rb
|
|
96
|
+
- lib/asgard/base/dependency_graph.rb
|
|
97
|
+
- lib/asgard/base/dispatch.rb
|
|
98
|
+
- lib/asgard/base/registry.rb
|
|
99
|
+
- lib/asgard/base/task_dsl.rb
|
|
100
|
+
- lib/asgard/doctor.rb
|
|
101
|
+
- lib/asgard/doctor/report.rb
|
|
102
|
+
- lib/asgard/doctor/task_sections.rb
|
|
106
103
|
- lib/asgard/kernel_methods.rb
|
|
107
104
|
- lib/asgard/shell.rb
|
|
108
105
|
- lib/asgard/tasks.rb
|
|
109
106
|
- lib/asgard/version.rb
|
|
110
107
|
- mkdocs.yml
|
|
111
108
|
- quality.loki
|
|
109
|
+
- quality_rails.loki
|
|
112
110
|
- sig/asgard.rbs
|
|
111
|
+
- xyzzy.loki
|
|
113
112
|
homepage: https://github.com/madbomber/asgard
|
|
114
113
|
licenses:
|
|
115
114
|
- MIT
|
|
@@ -132,7 +131,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
132
131
|
- !ruby/object:Gem::Version
|
|
133
132
|
version: '0'
|
|
134
133
|
requirements: []
|
|
135
|
-
rubygems_version: 4.0.
|
|
134
|
+
rubygems_version: 4.0.19
|
|
136
135
|
specification_version: 4
|
|
137
136
|
summary: A powerful Ruby-based task runner
|
|
138
137
|
test_files: []
|