asgard 0.5.0 → 0.5.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/CHANGELOG.md +15 -1
- data/docs/examples.md +54 -0
- data/examples/confirm.loki +48 -0
- data/examples/do.loki +45 -0
- data/lib/asgard/base.rb +4 -0
- data/lib/asgard/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 299e2b451fc4acf80bf87970012a5fea712bf7f2efc4103465355d091d2b1282
|
|
4
|
+
data.tar.gz: e9dc3f90d5abaaac9b735e2b92a35296b5956bc0e261526244aff5d1ba500a8e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5279427ba559b0067881a8e828642222c3189b002c01dbeb409f69bfe39a018e7288a088125ea29b56d71f8a16370965ed4bea03a9328be9ef6c29b7a4c5d3af
|
|
7
|
+
data.tar.gz: cf33a3581b2fceeec5baf59d8fe42505c3d29e9d7f0717e5b81110208c1f9aa339883e06a1c5e9bc29487eba13e4f63ab37d509e48d03285a0ef90a20a64fcb1
|
data/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [0.5.
|
|
8
|
+
## [0.5.1] - 2026-10-19
|
|
9
9
|
|
|
10
10
|
### Added
|
|
11
11
|
|
|
@@ -31,6 +31,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
31
31
|
`empty?`); every list is empty when the task is run by hand.
|
|
32
32
|
- **`Asgard::Watch::Error`** (subclass of `Asgard::Error`) — raised when a
|
|
33
33
|
`watch` names a task the project does not define.
|
|
34
|
+
- **`examples/do.loki`** — `asgard do lint test build` runs tasks in
|
|
35
|
+
sequence, with comma-separated steps for arguments and options
|
|
36
|
+
(`asgard do hello Alice, farewell Bob --formal`). A plain user task, not
|
|
37
|
+
a built-in; it stops at the first failure.
|
|
38
|
+
- **`examples/confirm.loki`** — a hidden `confirm` task to list first in a
|
|
39
|
+
dangerous task's `depends_on`; answering anything but y/yes aborts with
|
|
40
|
+
exit 1. Refuses without a terminal unless `ASGARD_YES` is set.
|
|
34
41
|
|
|
35
42
|
### Changed
|
|
36
43
|
|
|
@@ -43,6 +50,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
43
50
|
- `Asgard.machine_wide?` is true for `watcher list` as well as
|
|
44
51
|
`schedule list`, so both work from a directory with no `.loki` above it.
|
|
45
52
|
|
|
53
|
+
### Fixed
|
|
54
|
+
|
|
55
|
+
- **Usage errors exit 1** — a missing argument, an unknown command, or a bad
|
|
56
|
+
subcommand (`asgard greet` with no NAME, `asgard nope`) printed Thor's
|
|
57
|
+
error but exited 0, so CI and scripts saw success. `Asgard::Base` now
|
|
58
|
+
defines `exit_on_failure?` as true.
|
|
59
|
+
|
|
46
60
|
## [0.4.1] - 2026-10-02
|
|
47
61
|
|
|
48
62
|
### Added
|
data/docs/examples.md
CHANGED
|
@@ -130,6 +130,58 @@ This example is also useful as a test harness for verifying that parallel execut
|
|
|
130
130
|
|
|
131
131
|
---
|
|
132
132
|
|
|
133
|
+
## `do.loki`
|
|
134
|
+
|
|
135
|
+
**Path:** `examples/do.loki`
|
|
136
|
+
|
|
137
|
+
A plain user task that runs other tasks in sequence, the way `rake a b c` or `just a b c` does. No gem changes needed:
|
|
138
|
+
|
|
139
|
+
- Steps are comma-separated, so each step can carry its own arguments and options; with no commas, every word is a task of its own
|
|
140
|
+
- Each step is parsed by Thor as if it were typed on the command line
|
|
141
|
+
- The sequence stops at the first failure (a failing `sh`, or a step returning `:fail`)
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
asgard do greet finish
|
|
145
|
+
asgard do hello Alice, farewell Bob --formal
|
|
146
|
+
# Hello, Alice!
|
|
147
|
+
# Goodbye, Bob.
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
!!! note
|
|
151
|
+
Every task runs at most once per `asgard` invocation, so `asgard do hello Alice, hello Bob` greets only Alice. The same rule makes a dependency shared by several steps run once.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## `confirm.loki`
|
|
156
|
+
|
|
157
|
+
**Path:** `examples/confirm.loki`
|
|
158
|
+
|
|
159
|
+
A guard task. List `confirm` first in a dangerous task's `depends_on`, and the task runs only after the user answers yes:
|
|
160
|
+
|
|
161
|
+
```ruby
|
|
162
|
+
depends_on :confirm
|
|
163
|
+
desc "Drop and recreate the database"
|
|
164
|
+
def reset_database = sh "bin/rails db:reset"
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
asgard reset_database
|
|
169
|
+
# Really run `asgard reset_database`? [y/N] n
|
|
170
|
+
# asgard: aborted `asgard reset_database` (exit 1)
|
|
171
|
+
|
|
172
|
+
ASGARD_YES=1 asgard reset_database # no question, for scripts and CI
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
- Answering no **raises** `Asgard::Error`, which stops the dependent task. Returning `:fail` would not: a dependency's return value never stops the task that depends on it
|
|
176
|
+
- A dependency doesn't know which task asked for it, so the question shows the whole command line
|
|
177
|
+
- With no terminal (a schedule, the watcher, a pipe) it refuses unless `ASGARD_YES` is set
|
|
178
|
+
- `confirm` is declared with `hide: true`, so it stays out of `asgard help`
|
|
179
|
+
|
|
180
|
+
!!! note
|
|
181
|
+
`confirm` runs at most once per `asgard` invocation, so `asgard do reset_database, drop_cache` asks once for the whole line. Keep it in its own first stage: in `depends_on [:confirm, :backup]`, `backup` runs while the question waits.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
133
185
|
## Summary
|
|
134
186
|
|
|
135
187
|
| File | Primary Focus |
|
|
@@ -138,3 +190,5 @@ This example is also useful as a test harness for verifying that parallel execut
|
|
|
138
190
|
| `server_subcommands.loki` | Subcommand groups, per-command options, depends_on in subcommands |
|
|
139
191
|
| `db_subcommands.loki` | Multi-step depends_on chains, enum validation, long_desc in subcommands |
|
|
140
192
|
| `concurrent.loki` | Parallel task execution, thread concurrency demonstration |
|
|
193
|
+
| `do.loki` | Running several tasks in sequence from one command line |
|
|
194
|
+
| `confirm.loki` | A guard dependency that asks before a dangerous task runs |
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Demonstrates a guard task: list `confirm` first in a dangerous task's
|
|
3
|
+
# depends_on and the task only runs after the user answers yes.
|
|
4
|
+
#
|
|
5
|
+
# Run with:
|
|
6
|
+
# asgard reset_database # asks, runs only on y/yes
|
|
7
|
+
# ASGARD_YES=1 asgard reset_database # no question (scripts, CI)
|
|
8
|
+
#
|
|
9
|
+
# Behavior:
|
|
10
|
+
# - A dependency doesn't know which task asked for it, so the question
|
|
11
|
+
# shows the whole command line: "Really run `asgard reset_database`?"
|
|
12
|
+
# - Answering no raises Asgard::Error, which stops everything that
|
|
13
|
+
# hasn't run yet; asgard prints "asgard: aborted ..." and exits 1.
|
|
14
|
+
# Returning :fail would NOT work: a dependency's return value never
|
|
15
|
+
# stops the task that depends on it.
|
|
16
|
+
# - With no terminal to ask (a schedule, the watcher, a pipe) it refuses
|
|
17
|
+
# unless ASGARD_YES is set, rather than hanging or guessing.
|
|
18
|
+
# - It runs at most once per asgard invocation, so
|
|
19
|
+
# `asgard do reset_database, drop_cache` asks once for the whole line.
|
|
20
|
+
# - Put confirm in its own first stage. In a parallel group,
|
|
21
|
+
# `depends_on [:confirm, :backup]`, backup runs while the question waits.
|
|
22
|
+
|
|
23
|
+
class Tasks
|
|
24
|
+
# Not a Thor command (a class method), so it can be tested on its own:
|
|
25
|
+
# Tasks.confirmed?("y", yes_env: nil) #=> true
|
|
26
|
+
def self.confirmed?(answer, yes_env:)
|
|
27
|
+
return true if yes_env && !yes_env.empty?
|
|
28
|
+
|
|
29
|
+
%w[y yes].include?(answer.to_s.strip.downcase)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
desc "Ask before running the task that depends on this", hide: true
|
|
33
|
+
def confirm
|
|
34
|
+
command = "asgard #{ARGV.join(' ')}"
|
|
35
|
+
yes_env = env(:asgard_yes, "")
|
|
36
|
+
return if self.class.confirmed?(nil, yes_env:)
|
|
37
|
+
raise Asgard::Error, "refusing `#{command}`: no terminal to confirm on (set ASGARD_YES=1)" unless $stdin.tty?
|
|
38
|
+
|
|
39
|
+
answer = ask("Really run `#{command}`? [y/N]")
|
|
40
|
+
raise Asgard::Error, "aborted `#{command}`" unless self.class.confirmed?(answer, yes_env:)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
depends_on :confirm
|
|
44
|
+
desc "Pretend to drop and recreate the database (demo for confirm)"
|
|
45
|
+
def reset_database
|
|
46
|
+
puts "Database reset."
|
|
47
|
+
end
|
|
48
|
+
end
|
data/examples/do.loki
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Demonstrates a plain user task that runs other tasks in sequence — the
|
|
3
|
+
# `rake a b c` / `just a b c` style, which Thor's one-command dispatch
|
|
4
|
+
# doesn't offer on its own.
|
|
5
|
+
#
|
|
6
|
+
# Steps are comma-separated so a step can carry its own arguments and
|
|
7
|
+
# options; with no commas, every word is a task of its own.
|
|
8
|
+
#
|
|
9
|
+
# Run with:
|
|
10
|
+
# asgard do greet finish
|
|
11
|
+
# asgard do hello Alice, farewell Bob --formal, finish
|
|
12
|
+
#
|
|
13
|
+
# Behavior:
|
|
14
|
+
# - Each step is parsed by Thor exactly as if typed on the command line,
|
|
15
|
+
# so its arguments and options work as usual.
|
|
16
|
+
# - The sequence stops at the first failure: a failing `sh` exits the
|
|
17
|
+
# process, and a step returning :fail makes `do` return :fail (exit 1).
|
|
18
|
+
# - Every task runs at most once per asgard invocation, so
|
|
19
|
+
# `asgard do hello Alice, hello Bob` greets only Alice, and a dependency
|
|
20
|
+
# shared by several steps runs once.
|
|
21
|
+
|
|
22
|
+
require "shellwords"
|
|
23
|
+
|
|
24
|
+
class Tasks
|
|
25
|
+
# Not a Thor command (a class method), so it can be tested on its own:
|
|
26
|
+
# Tasks.do_steps("lint, hello Alice") #=> [["lint"], ["hello", "Alice"]]
|
|
27
|
+
def self.do_steps(line)
|
|
28
|
+
line.include?(",") ? line.split(",").map { |step| Shellwords.split(step) }.reject(&:empty?)
|
|
29
|
+
: Shellwords.split(line).map { |word| [word] }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
desc "do STEPS...", "Run several tasks in sequence, e.g. `asgard do hello Alice, farewell Bob --formal`"
|
|
33
|
+
stop_on_unknown_option! :do
|
|
34
|
+
def do(*words)
|
|
35
|
+
steps = self.class.do_steps(words.join(" "))
|
|
36
|
+
raise Asgard::Error, "do: no tasks given" if steps.empty?
|
|
37
|
+
|
|
38
|
+
steps.each do |name, *args|
|
|
39
|
+
raise Asgard::Error, "do: unknown task '#{name}'" if name == "do" || !self.class.all_commands.key?(name)
|
|
40
|
+
# dispatch with nil options is what Tasks.start does: Thor parses this
|
|
41
|
+
# step's argv itself. (invoke would reuse the options parsed for `do`.)
|
|
42
|
+
return :fail if self.class.send(:dispatch, nil, [name, *args], nil, shell: shell) == :fail
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/asgard/base.rb
CHANGED
|
@@ -18,6 +18,10 @@ module Asgard
|
|
|
18
18
|
include Dispatch
|
|
19
19
|
|
|
20
20
|
class << self
|
|
21
|
+
# A usage error (missing argument, unknown command or option) exits 1,
|
|
22
|
+
# so CI and `asgard do` sequences see the failure. Thor's default is 0.
|
|
23
|
+
def exit_on_failure? = true
|
|
24
|
+
|
|
21
25
|
def header(text = nil)
|
|
22
26
|
return @_header if text.nil?
|
|
23
27
|
(@_header ||= []) << text
|
data/lib/asgard/version.rb
CHANGED
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.5.
|
|
4
|
+
version: 0.5.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dewayne VanHoozer
|
|
@@ -129,9 +129,11 @@ files:
|
|
|
129
129
|
- examples/.loki
|
|
130
130
|
- examples/bad.loki
|
|
131
131
|
- examples/concurrent.loki
|
|
132
|
+
- examples/confirm.loki
|
|
132
133
|
- examples/db_subcommands.loki
|
|
133
134
|
- examples/depends_on_block/bad/.loki
|
|
134
135
|
- examples/depends_on_block/good/.loki
|
|
136
|
+
- examples/do.loki
|
|
135
137
|
- examples/env_usage.loki
|
|
136
138
|
- examples/kitchen_sink.loki
|
|
137
139
|
- examples/server_subcommands.loki
|