asgard 0.1.0 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c25b1efcac0de2f525140327f64753c1cb7b0cf82904ea6c4e1be1114b619bf
4
- data.tar.gz: 857e98381996d06968944ed6bafb6b35d86073523672ac6d987ce2fb85a8cc79
3
+ metadata.gz: 2d904144543326c15257e4e61584c46fa9b0ab4f1ba522680daa930950361e6a
4
+ data.tar.gz: fea08260a5db1fdde268eaf4ca930b1e52a07a39f12eaf2ce20e31736319cdff
5
5
  SHA512:
6
- metadata.gz: 383ececde0765e801b1e84dc239895ee0d2ffe491fc6d0c0c4d3a583f0a0912f64ca8dc4a4a6469f12efcae93358302ada9aeb648b6a95ada4fe866c205306b0
7
- data.tar.gz: 3d2ecd3d0dcc3acdaa1ecd6dd6457ce02c23b086c36f178b9aa378ec620069ae99e9ecae3d824d26f0d22fb5906a4b34bc1831a2040abf24bab81833080b470e
6
+ metadata.gz: 9f75f50ba53970998d047e21078b120090ba6c232ac698b0ba705b84a3de542bfef313690e11d2e09989101045323c7cd6549bf51826b316ccf1beeb96ada50d
7
+ data.tar.gz: 497bee99076f476b8fe680962f59b369898381470b27fd59e0f7e4dc7636e620004660cbcf3ceb10a2678e65ddf78a2a7e24e6571362fc7ad3e7929eeb61a614
data/.loki CHANGED
@@ -1,6 +1,8 @@
1
- # default task filename for the asgard task runner
1
+ # frozen_string_literal: true
2
+ # Asgard gem's own task file.
3
+ # Task is pre-defined by the gem — just reopen it to add tasks.
2
4
 
3
- class Tasks < Asgard::Base
5
+ class Tasks
4
6
  var :gem_name, "asgard"
5
7
  var :version, -> { Asgard::VERSION }
6
8
 
data/CHANGELOG.md CHANGED
@@ -7,13 +7,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.1] - 2026-05-28
11
+ ### Added
12
+
13
+ - Parallel dependency execution — wrap deps in an array to run them concurrently:
14
+ `depends_on [:build, :lint]` or `depends_on :setup, [:build, :lint], :deploy`
15
+ - `Asgard.run!(argv)` — single entry point encapsulating find, load, validate, and start
16
+ - `Asgard.load_loki(dir)` — auto-loads all `*.loki` files in a directory alphabetically
17
+ - `Tasks` class pre-defined by the gem (`class Tasks < Asgard::Base`) — task files reopen it without restating the superclass
18
+ - `lib/asgard/tasks.rb` — ships the pre-defined `Tasks` class
19
+
20
+ ### Changed
21
+
22
+ - Replaced `SimpleFlow` dependency with `Dagwood` — purpose-built DAG library with no extra dependencies and no Ruby 4 compatibility issues
23
+ - `bin/asgard` simplified to two lines: `require "asgard"` + `Asgard.run!(ARGV)`
24
+ - Task file convention: `.loki` is the project root marker and entry point; `*.loki` files each reopen `class Tasks` and are auto-loaded before `.loki`
25
+ - `Asgard.find_task_files` renamed to `Asgard.find_task_file` (singular — only `.loki` is the entry point)
26
+ - `depends_on` now accepts mixed sequential/parallel stages; bare symbols run sequentially, arrays within the splat run in parallel
27
+ - `run!` handles its own errors — missing `.loki` and circular dependencies produce a clean one-line message and exit 1 rather than a backtrace
28
+ - Thread-safe dep deduplication via class-level `_ran_tasks` Set + Mutex replaces Thor's `@_invocations`
29
+ - Removed `import` macro — task files use Ruby class reopening instead of modules
30
+
31
+ ### Removed
32
+
33
+ - `SimpleFlow` dependency (replaced by `Dagwood`)
34
+ - `logger` gem workaround (was only needed for SimpleFlow on Ruby 4)
35
+ - `*.loki` glob fallback in `find_task_file` — only `.loki` is the auto-discovered entry point
36
+
10
37
  ## [0.1.0] - 2026-05-28
11
38
 
12
39
  ### Added
13
40
 
14
41
  - `Asgard::Base` — Thor subclass providing the task DSL
15
- - `depends_on` — declare recipe dependencies resolved via `SimpleFlow::DependencyGraph`; dependencies run at most once per invocation
16
- - `var` — declare static or lazy-evaluated variables available to all recipes
42
+ - `depends_on` — declare task dependencies; dependencies run at most once per invocation
43
+ - `var` — declare static or lazy-evaluated variables available to all tasks
17
44
  - `import` — flat-merge a task module into the current class
18
45
  - `dotenv` — load a `.env` file into the environment
19
46
  - `sh` — run a shell command or multiline heredoc script; exits with the command's status on failure
data/CLAUDE.md ADDED
@@ -0,0 +1,117 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## What Asgard Is
6
+
7
+ Asgard is a Ruby task runner. Users define tasks in `.loki` files by reopening the pre-defined `Tasks` class. The name is intentional: Thor handles the CLI, Asgard is where tasks live, and Loki (the `.loki` file) holds all the tricks.
8
+
9
+ ## Commands
10
+
11
+ ```bash
12
+ bundle install
13
+ bundle exec rake test # run tests (enforces 95% SimpleCov coverage)
14
+ bundle exec rake quality # test + flog complexity check
15
+ bundle exec rake build # build .gem into pkg/
16
+ bundle exec rake install # install locally
17
+
18
+ # or use the gem's own .loki file:
19
+ asgard test
20
+ asgard quality
21
+ asgard release
22
+ ```
23
+
24
+ Single test: `ruby -Ilib:test test/test_asgard.rb`
25
+
26
+ ## Architecture
27
+
28
+ ### Entry Point Flow
29
+
30
+ `bin/asgard` → `Asgard.run!(ARGV)` (`lib/asgard.rb`):
31
+ 1. Walk CWD + ancestors for `.loki` (marker only, not a task file)
32
+ 2. Glob + sort `*.loki` files from that dir, `load` each alphabetically
33
+ 3. Load `.loki` itself last
34
+ 4. `Tasks.validate_deps!` — build full dep graph, raise `CircularDependencyError` if cyclic
35
+ 5. `Tasks._reset_ran!` — clear execution tracking
36
+ 6. `Tasks.start(argv)` — Thor dispatches the command
37
+
38
+ ### Core Classes
39
+
40
+ | File | Role |
41
+ |------|------|
42
+ | `lib/asgard/base.rb` | DSL engine; inherits Thor, includes Shell |
43
+ | `lib/asgard/shell.rb` | `sh` / `shebang` helpers |
44
+ | `lib/asgard/tasks.rb` | `class Tasks < Asgard::Base` — the convention class users reopen; also holds gem-owned built-in tasks |
45
+
46
+ ### Naming Convention for Gem-Owned Methods
47
+
48
+ Any task or method defined by Asgard itself inside `Tasks` (i.e. not by the user's `.loki` files) must be prefixed with `_`. This distinguishes built-in gem behavior from user-defined tasks and prevents naming collisions.
49
+
50
+ ```ruby
51
+ # lib/asgard/tasks.rb — gem-owned built-ins use _ prefix
52
+ class Tasks < Asgard::Base
53
+ desc "--version", "Show version"
54
+ map "--version" => :_version
55
+ def _version
56
+ puts Asgard::VERSION
57
+ exit
58
+ end
59
+ end
60
+ ```
61
+
62
+ `method_added` in `Base` already skips `_`-prefixed methods when attaching dependency metadata, so built-ins are naturally excluded from the dependency graph.
63
+
64
+ Do not define `_`-prefixed methods in user `.loki` files — that namespace is reserved for the gem.
65
+
66
+ ### DSL Mechanics (`lib/asgard/base.rb`)
67
+
68
+ **`depends_on`** stores stages in `@_pending_deps`. On `method_added`, those stages are popped and stored in `@_deps[method_name]`. Bare symbols are sequential stages; arrays within a `depends_on` call are parallel stages:
69
+
70
+ ```ruby
71
+ depends_on :a, [:b, :c], :d # stages: [[:a], [:b, :c], [:d]]
72
+ ```
73
+
74
+ **`var`** stores values or lambdas in `@_vars` and creates an instance method that evaluates the lambda once on first access.
75
+
76
+ **`invoke_command`** (Thor dispatch hook):
77
+ 1. Atomically check `@_ran_tasks` Set (with `@_ran_mutex`); return early if already run
78
+ 2. Resolve `@_deps` stages → `_build_dep_graph` → `Dagwood::DependencyGraph#parallel_order`
79
+ 3. For each parallel group: spawn one thread per task, join; single-task groups run inline
80
+ 4. Execute the target task
81
+
82
+ **`_build_dep_graph(stages)`** converts stages to a DAG hash:
83
+ - `[[:a], [:b, :c], [:d]]` → `{ a: [], b: [:a], c: [:a], d: [:b, :c] }`
84
+
85
+ ### Dependency Resolution
86
+
87
+ Dagwood topologically sorts the DAG and returns parallel groups. The thread-safe deduplication (`_ran_tasks` Set + Mutex) ensures each task runs exactly once even when multiple tasks share a common dependency.
88
+
89
+ ### Shell Helpers
90
+
91
+ - `sh(script, silent: false)` — single-line strings use `system(script)`; multi-line strings pipe through `bash -c`; exits with the command's status on failure
92
+ - `shebang(interpreter, script)` — writes script to a tempfile and executes with the named interpreter (`:python3`, `:node`, `:ruby`, `:perl`, `:bash`, etc.)
93
+
94
+ ## Testing
95
+
96
+ All tests are in `test/test_asgard.rb` (one file, ~11 named classes). SimpleCov minimum is 95%; the Rakefile configures this with a prelude that loads coverage before the library.
97
+
98
+ Key test patterns: tests frequently subclass `Asgard::Base` directly (not `Tasks`) to test the engine in isolation, and use `capture_io` for output assertions.
99
+
100
+ ## The `.loki` Format
101
+
102
+ A `.loki` file is plain Ruby that reopens `Tasks`:
103
+
104
+ ```ruby
105
+ class Tasks
106
+ var :gem_name, "asgard"
107
+
108
+ desc "test", "Run tests"
109
+ def test = sh "bundle exec rake test"
110
+
111
+ depends_on :test
112
+ desc "release", "Build and release"
113
+ def release = sh "bundle exec rake release"
114
+ end
115
+ ```
116
+
117
+ Multiple `*.loki` files in the same directory are all loaded (alphabetically). The bare `.loki` file serves only as the project root marker — its content is loaded last.