asgard 0.2.0 → 0.3.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/.loki +13 -26
- data/.rubocop.yml +157 -0
- data/CHANGELOG.md +89 -11
- data/CLAUDE.md +19 -9
- data/README.md +161 -54
- data/docs/api.md +91 -15
- data/docs/changelog.md +12 -0
- data/docs/dependencies.md +25 -25
- data/docs/environment.md +30 -14
- data/docs/examples.md +3 -3
- data/docs/getting-started.md +5 -6
- data/docs/helpers.md +117 -9
- data/docs/index.md +6 -6
- data/docs/options.md +42 -8
- data/docs/shell.md +11 -11
- data/docs/subcommands.md +9 -9
- data/docs/task-files.md +266 -113
- data/docs/tasks.md +17 -15
- data/docs/variables.md +267 -51
- data/examples/.env +4 -0
- data/examples/.loki +24 -2
- data/examples/concurrent.loki +5 -5
- data/examples/db_subcommands.loki +3 -3
- data/examples/env_usage.loki +27 -0
- data/examples/kitchen_sink.loki +48 -15
- data/examples/server_subcommands.loki +33 -24
- data/examples/subdir/.loki +12 -0
- data/examples/subdir/import_demo.loki +14 -0
- data/examples/subdir/import_up_demo.loki +18 -0
- data/gem_tasks.loki +35 -0
- data/lib/asgard/base.rb +158 -80
- data/lib/asgard/kernel_methods.rb +79 -0
- data/lib/asgard/shell.rb +8 -7
- data/lib/asgard/tasks.rb +12 -17
- data/lib/asgard/version.rb +1 -1
- data/lib/asgard.rb +6 -18
- data/quality.loki +75 -0
- metadata +15 -5
- data/Rakefile +0 -22
data/docs/dependencies.md
CHANGED
|
@@ -26,15 +26,15 @@ Bare symbols run one after another in the order declared:
|
|
|
26
26
|
|
|
27
27
|
```ruby
|
|
28
28
|
class Tasks
|
|
29
|
-
desc "
|
|
29
|
+
desc "Compile the project"
|
|
30
30
|
def build = sh "rake build"
|
|
31
31
|
|
|
32
32
|
depends_on :build
|
|
33
|
-
desc "
|
|
33
|
+
desc "Run the test suite"
|
|
34
34
|
def test = sh "rake test"
|
|
35
35
|
|
|
36
36
|
depends_on :test
|
|
37
|
-
desc "
|
|
37
|
+
desc "Publish the gem"
|
|
38
38
|
def release = sh "bundle exec rake release"
|
|
39
39
|
end
|
|
40
40
|
```
|
|
@@ -47,7 +47,7 @@ Multiple sequential dependencies in a single `depends_on` call run left to right
|
|
|
47
47
|
|
|
48
48
|
```ruby
|
|
49
49
|
depends_on :clean, :build, :test
|
|
50
|
-
desc "
|
|
50
|
+
desc "Clean, build, and test"
|
|
51
51
|
def package = sh "rake package"
|
|
52
52
|
```
|
|
53
53
|
|
|
@@ -59,14 +59,14 @@ Wrap symbols in an array to declare they can run concurrently. Asgard waits for
|
|
|
59
59
|
|
|
60
60
|
```ruby
|
|
61
61
|
class Tasks
|
|
62
|
-
desc "
|
|
62
|
+
desc "Check code style"
|
|
63
63
|
def lint = sh "bundle exec rubocop"
|
|
64
64
|
|
|
65
|
-
desc "
|
|
65
|
+
desc "Run type checks"
|
|
66
66
|
def typecheck = sh "bundle exec srb tc"
|
|
67
67
|
|
|
68
68
|
depends_on [:lint, :typecheck]
|
|
69
|
-
desc "
|
|
69
|
+
desc "Run tests (after lint and typecheck)"
|
|
70
70
|
def test = sh "bundle exec rake test"
|
|
71
71
|
end
|
|
72
72
|
```
|
|
@@ -85,16 +85,16 @@ Mix bare symbols and arrays in a single `depends_on` call. Execution proceeds st
|
|
|
85
85
|
|
|
86
86
|
```ruby
|
|
87
87
|
class Tasks
|
|
88
|
-
desc "
|
|
89
|
-
desc "
|
|
90
|
-
desc "
|
|
91
|
-
desc "
|
|
92
|
-
desc "
|
|
88
|
+
desc "Install dependencies"; def setup = sh "bundle install"
|
|
89
|
+
desc "Check code style"; def lint = sh "bundle exec rubocop"
|
|
90
|
+
desc "Compile assets"; def build = sh "rake assets:precompile"
|
|
91
|
+
desc "Run tests"; def test = sh "bundle exec rake test"
|
|
92
|
+
desc "Post to Slack"; def notify = sh "curl $SLACK_WEBHOOK -d '{\"text\":\"done\"}'"
|
|
93
93
|
|
|
94
94
|
# setup first, then lint+build in parallel, then test, then notify
|
|
95
95
|
depends_on :setup, [:lint, :build], :test, :notify
|
|
96
|
-
desc "
|
|
97
|
-
def ci =
|
|
96
|
+
desc "Full CI pipeline"
|
|
97
|
+
def ci = puts "CI complete"
|
|
98
98
|
end
|
|
99
99
|
```
|
|
100
100
|
|
|
@@ -124,19 +124,19 @@ Each task runs at most once per `asgard` invocation. If multiple tasks declare t
|
|
|
124
124
|
|
|
125
125
|
```ruby
|
|
126
126
|
class Tasks
|
|
127
|
-
desc "
|
|
127
|
+
desc "Install gems"
|
|
128
128
|
def setup = sh "bundle install"
|
|
129
129
|
|
|
130
130
|
depends_on :setup
|
|
131
|
-
desc "
|
|
131
|
+
desc "Run tests"
|
|
132
132
|
def test = sh "rake test"
|
|
133
133
|
|
|
134
134
|
depends_on :setup
|
|
135
|
-
desc "
|
|
135
|
+
desc "Check style"
|
|
136
136
|
def lint = sh "rubocop"
|
|
137
137
|
|
|
138
138
|
depends_on [:test, :lint]
|
|
139
|
-
desc "
|
|
139
|
+
desc "Test and lint (setup runs once)"
|
|
140
140
|
def ci = puts "done"
|
|
141
141
|
end
|
|
142
142
|
```
|
|
@@ -152,10 +152,10 @@ Asgard validates the full dependency graph using [Dagwood](https://rubygems.org/
|
|
|
152
152
|
```ruby
|
|
153
153
|
class Tasks
|
|
154
154
|
depends_on :b
|
|
155
|
-
desc "
|
|
155
|
+
desc "Task A"; def a = puts "a"
|
|
156
156
|
|
|
157
157
|
depends_on :a
|
|
158
|
-
desc "
|
|
158
|
+
desc "Task B"; def b = puts "b"
|
|
159
159
|
end
|
|
160
160
|
```
|
|
161
161
|
|
|
@@ -175,14 +175,14 @@ No backtrace is shown — just a single diagnostic line.
|
|
|
175
175
|
```ruby
|
|
176
176
|
# build.loki
|
|
177
177
|
class Tasks
|
|
178
|
-
desc "
|
|
178
|
+
desc "Compile"
|
|
179
179
|
def build = sh "rake build"
|
|
180
180
|
end
|
|
181
181
|
|
|
182
182
|
# test.loki
|
|
183
183
|
class Tasks
|
|
184
184
|
depends_on :build # build.loki must be loaded first
|
|
185
|
-
desc "
|
|
185
|
+
desc "Test"
|
|
186
186
|
def test = sh "rake test"
|
|
187
187
|
end
|
|
188
188
|
```
|
|
@@ -197,14 +197,14 @@ When `--auto-load` is used, `*.loki` files are loaded alphabetically, so `build.
|
|
|
197
197
|
|
|
198
198
|
```ruby
|
|
199
199
|
class DBCommands < Tasks
|
|
200
|
-
desc "
|
|
200
|
+
desc "Run migrations"
|
|
201
201
|
def migrate = sh "rails db:migrate"
|
|
202
202
|
|
|
203
|
-
desc "
|
|
203
|
+
desc "Load seed data"
|
|
204
204
|
def seed = sh "rails db:seed"
|
|
205
205
|
|
|
206
206
|
depends_on :migrate, :seed
|
|
207
|
-
desc "
|
|
207
|
+
desc "Migrate then seed"
|
|
208
208
|
def reset = puts "Done."
|
|
209
209
|
end
|
|
210
210
|
|
data/docs/environment.md
CHANGED
|
@@ -12,8 +12,8 @@ Call `dotenv` inside the class body (not inside a task method) to load the defau
|
|
|
12
12
|
class Tasks
|
|
13
13
|
dotenv # loads .env from the current working directory
|
|
14
14
|
|
|
15
|
-
desc "
|
|
16
|
-
def check =
|
|
15
|
+
desc "Print the app name from .env"
|
|
16
|
+
def check = puts env(:app_name)
|
|
17
17
|
end
|
|
18
18
|
```
|
|
19
19
|
|
|
@@ -46,17 +46,14 @@ end
|
|
|
46
46
|
`dotenv` is a **class-level** call — it executes at Ruby class-load time, not when a task is invoked. This means:
|
|
47
47
|
|
|
48
48
|
1. Variables are available in `ENV` before any task method runs.
|
|
49
|
-
2. They are
|
|
50
|
-
3. They are available during `depends_on` dependency resolution.
|
|
49
|
+
2. They are available during `depends_on` dependency resolution.
|
|
51
50
|
|
|
52
51
|
```ruby
|
|
53
52
|
class Tasks
|
|
54
53
|
dotenv
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
desc "migrate", "Run migrations"
|
|
59
|
-
def migrate = sh "DATABASE_URL=#{database_url} rails db:migrate"
|
|
55
|
+
desc "Run migrations"
|
|
56
|
+
def migrate = sh "DATABASE_URL=#{env(:database_url)} rails db:migrate"
|
|
60
57
|
end
|
|
61
58
|
```
|
|
62
59
|
|
|
@@ -79,20 +76,39 @@ This makes it safe to commit a `.env.local` line to your `.loki` without requiri
|
|
|
79
76
|
|
|
80
77
|
---
|
|
81
78
|
|
|
82
|
-
## Environment Variables vs.
|
|
79
|
+
## Environment Variables vs. Class Variables
|
|
83
80
|
|
|
84
|
-
Use `dotenv` to bring external configuration into `ENV
|
|
81
|
+
Use `dotenv` to bring external configuration into `ENV`. Use `@@` class variables for fixed values declared in the task file, and read from `ENV` directly in task bodies or helper methods when the value comes from the environment:
|
|
85
82
|
|
|
86
83
|
```ruby
|
|
87
84
|
class Tasks
|
|
88
85
|
dotenv
|
|
89
86
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
87
|
+
@@app_name ||= "myapp".freeze
|
|
88
|
+
|
|
89
|
+
desc "Start the server"
|
|
90
|
+
def start
|
|
91
|
+
port = ENV.fetch("PORT", "3000").to_i
|
|
92
|
+
sh "puma -b tcp://0.0.0.0:#{port} -w #{ENV.fetch('WORKERS', '2')}"
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
For `ENV` values used in multiple tasks, define a private helper method:
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
class Tasks
|
|
101
|
+
dotenv
|
|
93
102
|
|
|
94
|
-
desc "
|
|
103
|
+
desc "Start the server"
|
|
95
104
|
def start = sh "puma -p #{port}"
|
|
105
|
+
|
|
106
|
+
desc "Show config"
|
|
107
|
+
def config = puts "#{@@app_name} on port #{port}"
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
def port = ENV.fetch("PORT", "3000").to_i
|
|
96
112
|
end
|
|
97
113
|
```
|
|
98
114
|
|
data/docs/examples.md
CHANGED
|
@@ -27,7 +27,7 @@ Alternatively, copy individual example files into your own project's directory.
|
|
|
27
27
|
|
|
28
28
|
The most comprehensive example — demonstrates every Thor DSL feature available in Asgard:
|
|
29
29
|
|
|
30
|
-
-
|
|
30
|
+
- `@@` class variables for shared configuration values
|
|
31
31
|
- `dotenv` (commented out, ready to activate)
|
|
32
32
|
- `class_option` with `:boolean` and `:string` types, including `enum`
|
|
33
33
|
- `default_task` — sets the default command when `asgard` is run with no arguments
|
|
@@ -56,7 +56,7 @@ asgard pipeline
|
|
|
56
56
|
|
|
57
57
|
---
|
|
58
58
|
|
|
59
|
-
##
|
|
59
|
+
## Server Subcommands
|
|
60
60
|
|
|
61
61
|
**Path:** `examples/server_subcommands.loki`
|
|
62
62
|
|
|
@@ -80,7 +80,7 @@ The `ServerCommands` class inherits from `Tasks`, giving it access to `sh`, `dep
|
|
|
80
80
|
|
|
81
81
|
---
|
|
82
82
|
|
|
83
|
-
##
|
|
83
|
+
## DB Subcommands
|
|
84
84
|
|
|
85
85
|
**Path:** `examples/db_subcommands.loki`
|
|
86
86
|
|
data/docs/getting-started.md
CHANGED
|
@@ -50,8 +50,8 @@ Open `.loki` in your editor and add a task:
|
|
|
50
50
|
|
|
51
51
|
```ruby
|
|
52
52
|
class Tasks
|
|
53
|
-
desc "
|
|
54
|
-
def hello =
|
|
53
|
+
desc "Say hello to the world"
|
|
54
|
+
def hello = puts "Hello, World!"
|
|
55
55
|
end
|
|
56
56
|
```
|
|
57
57
|
|
|
@@ -64,7 +64,6 @@ end
|
|
|
64
64
|
|
|
65
65
|
```bash
|
|
66
66
|
asgard hello
|
|
67
|
-
# echo "Hello, World!"
|
|
68
67
|
# Hello, World!
|
|
69
68
|
```
|
|
70
69
|
|
|
@@ -90,7 +89,7 @@ Positional parameters are declared directly in the method signature. Document th
|
|
|
90
89
|
class Tasks
|
|
91
90
|
desc "greet NAME", "Greet someone by name"
|
|
92
91
|
def greet(name = "World")
|
|
93
|
-
|
|
92
|
+
puts "Hello, #{name}!"
|
|
94
93
|
end
|
|
95
94
|
end
|
|
96
95
|
```
|
|
@@ -115,7 +114,7 @@ class Tasks
|
|
|
115
114
|
option :shout, aliases: "-s", type: :boolean, desc: "Uppercase the greeting"
|
|
116
115
|
def greet(name = "World")
|
|
117
116
|
msg = options[:shout] ? "HELLO, #{name.upcase}!" : "Hello, #{name}!"
|
|
118
|
-
|
|
117
|
+
puts msg
|
|
119
118
|
end
|
|
120
119
|
end
|
|
121
120
|
```
|
|
@@ -163,7 +162,7 @@ Inside a task body, use the `debug?` and `verbose?` predicates:
|
|
|
163
162
|
|
|
164
163
|
```ruby
|
|
165
164
|
def hello
|
|
166
|
-
|
|
165
|
+
puts "building..."
|
|
167
166
|
sh "make --debug" if debug?
|
|
168
167
|
end
|
|
169
168
|
```
|
data/docs/helpers.md
CHANGED
|
@@ -10,13 +10,13 @@ Methods declared after `private` are callable from any task in the same class bu
|
|
|
10
10
|
|
|
11
11
|
```ruby
|
|
12
12
|
class Tasks
|
|
13
|
-
desc "
|
|
13
|
+
desc "Compile and package"
|
|
14
14
|
def build
|
|
15
15
|
compile("src")
|
|
16
16
|
package(app_version)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
desc "
|
|
19
|
+
desc "Build and publish to RubyGems"
|
|
20
20
|
def release
|
|
21
21
|
build
|
|
22
22
|
sh "gem push pkg/myapp-#{app_version}.gem"
|
|
@@ -49,13 +49,13 @@ Thor's `no_commands` block marks public methods as excluded from CLI discovery.
|
|
|
49
49
|
|
|
50
50
|
```ruby
|
|
51
51
|
class Tasks
|
|
52
|
-
desc "
|
|
52
|
+
desc "Compile the project"
|
|
53
53
|
def build
|
|
54
54
|
puts "Revision: #{current_sha}"
|
|
55
55
|
sh "rake build"
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
-
desc "
|
|
58
|
+
desc "Deploy to production"
|
|
59
59
|
def deploy
|
|
60
60
|
puts "Deploying revision #{current_sha}..."
|
|
61
61
|
sh "cap production deploy"
|
|
@@ -73,7 +73,89 @@ class Tasks
|
|
|
73
73
|
end
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## The `helper` DSL Method
|
|
79
|
+
|
|
80
|
+
`helper` is an Asgard DSL method that defines a helper available in **both class context and instance context** with a single declaration. It is the right tool when a value needs to be used inside a `header` or `footer` call (which execute at class load time) and also inside task instance methods.
|
|
81
|
+
|
|
82
|
+
### The problem it solves
|
|
83
|
+
|
|
84
|
+
Thor task methods run as instance methods. Class-level DSL calls like `header` and `footer` run as class methods. A plain `def` only creates an instance method, so it cannot be called inside `header`. Conversely, `def self.name` only creates a class method, so it cannot be called inside a task body without `self.class.name`.
|
|
85
|
+
|
|
86
|
+
The manual workaround is verbose:
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
class Tasks
|
|
90
|
+
@@project ||= "myapp".freeze
|
|
91
|
+
|
|
92
|
+
# class method for header/footer
|
|
93
|
+
def self.version
|
|
94
|
+
@@version ||= File.read("lib/myapp/version.rb").match(/VERSION\s*=\s*"([^"]+)"/)[1].freeze
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# private instance method delegating to the class method
|
|
98
|
+
no_commands do
|
|
99
|
+
private def version = self.class.version
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
header "#{@@project} v#{version}"
|
|
103
|
+
|
|
104
|
+
desc "Show version"
|
|
105
|
+
def show_version = puts version
|
|
106
|
+
end
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`helper` replaces those six lines with one:
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
class Tasks
|
|
113
|
+
@@project ||= "myapp".freeze
|
|
114
|
+
|
|
115
|
+
helper(:version) {
|
|
116
|
+
@@version ||= File.read("lib/myapp/version.rb").match(/VERSION\s*=\s*"([^"]+)"/)[1].freeze
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
header "#{@@project} v#{version}"
|
|
120
|
+
|
|
121
|
+
desc "Show version"
|
|
122
|
+
def show_version = puts version
|
|
123
|
+
end
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Arguments
|
|
127
|
+
|
|
128
|
+
`helper` supports any argument signature valid in a Ruby method definition: positional, keyword, default values, and blocks.
|
|
129
|
+
|
|
130
|
+
```ruby
|
|
131
|
+
# No arguments
|
|
132
|
+
helper(:project_root) { loki_up.parent.to_s }
|
|
133
|
+
|
|
134
|
+
# Positional arguments
|
|
135
|
+
helper(:gem_path) { |name| "lib/#{name}/version.rb" }
|
|
136
|
+
|
|
137
|
+
# Positional with default
|
|
138
|
+
helper(:tag_prefix) { |sep = "-"| "#{@@project}#{sep}" }
|
|
139
|
+
|
|
140
|
+
# Positional and keyword arguments
|
|
141
|
+
helper(:format_version) { |name, version, prefix: "v", separator: "-"|
|
|
142
|
+
"#{prefix}#{name}#{separator}#{version}"
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Wrong argument counts or unknown keyword names raise the same `ArgumentError` Ruby raises for any method call — no special error handling needed.
|
|
147
|
+
|
|
148
|
+
### Visibility
|
|
149
|
+
|
|
150
|
+
`helper`-defined methods are:
|
|
151
|
+
|
|
152
|
+
- **Excluded from `asgard help`** — they never appear as commands
|
|
153
|
+
- **Blocked from CLI invocation** — cannot be called directly from the command line
|
|
154
|
+
- **Private on the instance side** — not accessible from outside the class
|
|
155
|
+
|
|
156
|
+
### When to use `helper`
|
|
157
|
+
|
|
158
|
+
Use `helper` when the value or computation must be available in both a class-level DSL call (`header`, `footer`, a `@@var` initializer) and inside task instance methods. For helpers that are only needed inside task bodies, a plain `private` method is simpler.
|
|
77
159
|
|
|
78
160
|
---
|
|
79
161
|
|
|
@@ -93,6 +175,8 @@ For most helpers, `private` is the right choice. Use `no_commands` when the help
|
|
|
93
175
|
|
|
94
176
|
## Sharing Helpers Across Files
|
|
95
177
|
|
|
178
|
+
### Within a project
|
|
179
|
+
|
|
96
180
|
Extract shared helpers into a plain Ruby module and load it from `.loki` using `require_relative`:
|
|
97
181
|
|
|
98
182
|
```ruby
|
|
@@ -117,10 +201,10 @@ require_relative "shared/helpers"
|
|
|
117
201
|
class Tasks
|
|
118
202
|
include BuildHelpers
|
|
119
203
|
|
|
120
|
-
desc "
|
|
204
|
+
desc "Compile the project"
|
|
121
205
|
def build = compile("src")
|
|
122
206
|
|
|
123
|
-
desc "
|
|
207
|
+
desc "Create distribution archive"
|
|
124
208
|
def package = sh "tar czf #{dist_path(app_version)} bin/"
|
|
125
209
|
end
|
|
126
210
|
```
|
|
@@ -130,6 +214,30 @@ Because `include` in the class body makes the module methods available as instan
|
|
|
130
214
|
!!! tip
|
|
131
215
|
Helpers in a shared module can call `sh`, `shebang`, and other Asgard DSL methods because those are included in `Tasks` (via `Asgard::Base` and `Asgard::Shell`) and are available in `self` when the module method is invoked.
|
|
132
216
|
|
|
217
|
+
### Across projects with `import_up`
|
|
218
|
+
|
|
219
|
+
If helpers are defined as tasks in a shared `.loki` file, use `import_up` to load them from any sub-project without knowing the absolute path:
|
|
220
|
+
|
|
221
|
+
```
|
|
222
|
+
~/sandbox/
|
|
223
|
+
shared_helpers.loki ← defines helper tasks available to all sub-projects
|
|
224
|
+
projectA/
|
|
225
|
+
.loki
|
|
226
|
+
projectB/
|
|
227
|
+
.loki
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
```ruby
|
|
231
|
+
# projectA/.loki (and identically in projectB/.loki)
|
|
232
|
+
import_up "shared_helpers.loki"
|
|
233
|
+
|
|
234
|
+
class Tasks
|
|
235
|
+
# shared tasks are already defined in Tasks by here
|
|
236
|
+
end
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
`import_up` walks up from `Dir.pwd` until it finds `shared_helpers.loki`, then loads it. It returns `false` without raising if the file is not found, making it safe to use in projects where the shared file may not always be present.
|
|
240
|
+
|
|
133
241
|
---
|
|
134
242
|
|
|
135
243
|
## Helper Methods in Subcommands
|
|
@@ -138,10 +246,10 @@ Subcommand classes that inherit from `Tasks` also inherit all private helpers an
|
|
|
138
246
|
|
|
139
247
|
```ruby
|
|
140
248
|
class DeployCommands < Tasks
|
|
141
|
-
desc "
|
|
249
|
+
desc "Deploy to staging"
|
|
142
250
|
def staging = deploy_to("staging")
|
|
143
251
|
|
|
144
|
-
desc "
|
|
252
|
+
desc "Deploy to production"
|
|
145
253
|
def production = deploy_to("production")
|
|
146
254
|
|
|
147
255
|
private
|
data/docs/index.md
CHANGED
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
<li><strong>Task Dependencies</strong> — sequential, parallel, and mixed dependency graphs via <code>depends_on</code></li>
|
|
14
14
|
<li><strong>Concurrent Execution</strong> — parallel task groups run in native Ruby threads</li>
|
|
15
15
|
<li><strong>Subcommands</strong> — group related tasks under a named namespace</li>
|
|
16
|
-
<li><strong>Variables</strong> —
|
|
16
|
+
<li><strong>Variables</strong> — shared configuration via Ruby class variables (<code>@@name</code>), visible across all tasks and subcommands</li>
|
|
17
17
|
<li><strong>Shell Helpers</strong> — <code>sh</code> for any shell command or heredoc; <code>shebang</code> for polyglot scripts</li>
|
|
18
18
|
<li><strong>Dotenv Support</strong> — load <code>.env</code> files into the environment with <code>dotenv</code></li>
|
|
19
19
|
<li><strong>Auto-Discovery</strong> — <code>.loki</code> root marker searched from CWD upward through parent directories</li>
|
|
20
|
-
<li><strong>Multi-File Tasks</strong> — split tasks across <code>*.loki</code> files
|
|
20
|
+
<li><strong>Multi-File Tasks</strong> — split tasks across <code>*.loki</code> files loaded via <code>import</code></li>
|
|
21
21
|
<li><strong>Built-in Flags</strong> — <code>--version</code>, <code>--debug</code>, and <code>--verbose</code> available on every task</li>
|
|
22
22
|
</ul>
|
|
23
23
|
</td>
|
|
@@ -40,8 +40,8 @@ touch .loki
|
|
|
40
40
|
# Add your first task
|
|
41
41
|
cat >> .loki << 'EOF'
|
|
42
42
|
class Tasks
|
|
43
|
-
desc "
|
|
44
|
-
def hello =
|
|
43
|
+
desc "Say hello"
|
|
44
|
+
def hello = puts "Hello from Asgard!"
|
|
45
45
|
end
|
|
46
46
|
EOF
|
|
47
47
|
|
|
@@ -53,9 +53,9 @@ asgard hello
|
|
|
53
53
|
|
|
54
54
|
## How It Works
|
|
55
55
|
|
|
56
|
-
Asgard searches upward from your current directory for a `.loki` file. That file marks the project root. Additional `*.loki` files in the same directory can be loaded
|
|
56
|
+
Asgard searches upward from your current directory for a `.loki` file. That file marks the project root. Additional `*.loki` files in the same directory can be loaded via `import "*.loki"` at the top of `.loki`. All task files reopen `class Tasks`, which is pre-defined by the gem as a subclass of `Asgard::Base` (itself a Thor subclass).
|
|
57
57
|
|
|
58
|
-
The full Thor DSL is available: `desc`, `method_option`, `class_option`, `long_desc`, `argument`, `default_task`, `map`, and `subcommand` all work exactly as documented in Thor — with Asgard's own `depends_on`, `
|
|
58
|
+
The full Thor DSL is available: `desc`, `method_option`, `class_option`, `long_desc`, `argument`, `default_task`, `map`, and `subcommand` all work exactly as documented in Thor — with Asgard's own `depends_on`, `sh`, `shebang`, and `dotenv` layered on top.
|
|
59
59
|
|
|
60
60
|
---
|
|
61
61
|
|
data/docs/options.md
CHANGED
|
@@ -53,7 +53,7 @@ class Tasks
|
|
|
53
53
|
enum: %w[development staging production],
|
|
54
54
|
desc: "Target environment"
|
|
55
55
|
|
|
56
|
-
desc "
|
|
56
|
+
desc "Deploy the application"
|
|
57
57
|
def deploy
|
|
58
58
|
if options[:dry_run]
|
|
59
59
|
puts "Would deploy to #{options[:env]}"
|
|
@@ -62,7 +62,7 @@ class Tasks
|
|
|
62
62
|
end
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
-
desc "
|
|
65
|
+
desc "Run database migrations"
|
|
66
66
|
def migrate
|
|
67
67
|
sh "rails db:migrate RAILS_ENV=#{options[:env]}"
|
|
68
68
|
end
|
|
@@ -71,19 +71,53 @@ end
|
|
|
71
71
|
|
|
72
72
|
Both `deploy` and `migrate` automatically accept `--dry-run` and `--env`.
|
|
73
73
|
|
|
74
|
+
### Boolean class options and `no_negate`
|
|
75
|
+
|
|
76
|
+
Thor automatically generates `[--no-name]` and `[--skip-name]` help entries alongside every boolean `class_option`. When negation is meaningful — `--dry-run` paired with `--no-dry-run` — this is useful. When negation is meaningless, call `no_negate` immediately after the declaration to remove the extra variants from the help output:
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
class Tasks
|
|
80
|
+
class_option :color,
|
|
81
|
+
type: :boolean,
|
|
82
|
+
default: true,
|
|
83
|
+
desc: "Colorise output"
|
|
84
|
+
no_negate :color
|
|
85
|
+
end
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Help output before `no_negate`:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
[--color], [--no-color], [--skip-color] # Colorise output
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Help output after `no_negate`:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
[--color] # Colorise output
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`no_negate` accepts multiple option names in a single call:
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
no_negate :color, :version, :emoji
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
It has no effect on runtime behaviour — `--no-color` still works on the CLI; only the help display is affected.
|
|
107
|
+
|
|
74
108
|
---
|
|
75
109
|
|
|
76
110
|
## Built-in Flags
|
|
77
111
|
|
|
78
|
-
`Tasks` ships with three built-in
|
|
112
|
+
`Tasks` ships with three built-in `class_option` declarations — `--debug`, `--verbose`, and `--version` — all visible in the Options section of `asgard help`.
|
|
79
113
|
|
|
80
114
|
### `--version`
|
|
81
115
|
|
|
82
|
-
Prints `Asgard::VERSION` and exits.
|
|
116
|
+
A `class_option :version` of type `:boolean`. Prints `Asgard::VERSION` and exits. Handled by `Asgard.run!` before the `.loki` file is loaded, so it works even in a directory without a `.loki` file. `no_negate :version` suppresses the `[--no-version]` / `[--skip-version]` variants (see [Boolean class options and `no_negate`](#boolean-class-options-and-no_negate) above):
|
|
83
117
|
|
|
84
118
|
```bash
|
|
85
119
|
asgard --version
|
|
86
|
-
# 0.
|
|
120
|
+
# 0.3.0
|
|
87
121
|
```
|
|
88
122
|
|
|
89
123
|
### `--debug`
|
|
@@ -173,8 +207,8 @@ asgard deploy production --verbose
|
|
|
173
207
|
Methods whose names start with `_` are considered gem-owned in Asgard's naming convention. `run!` guards against invoking them directly from the CLI:
|
|
174
208
|
|
|
175
209
|
```bash
|
|
176
|
-
asgard
|
|
177
|
-
# asgard: unknown command '
|
|
210
|
+
asgard _something
|
|
211
|
+
# asgard: unknown command '_something'
|
|
178
212
|
```
|
|
179
213
|
|
|
180
|
-
If you define your own methods on `Tasks`, avoid the `_` prefix to prevent them from being
|
|
214
|
+
If you define your own methods on `Tasks`, avoid the `_` prefix to prevent them from being blocked. Built-in `class_option` declarations (like `--version`, `--debug`, `--verbose`) do not use the `_` prefix because they are options, not commands.
|