taski 0.7.0 → 0.8.0

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.
@@ -0,0 +1,519 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../lib/taski"
5
+
6
+ # Large tree demo script for testing progress display with 50+ tasks
7
+ # Run with: TASKI_FORCE_PROGRESS=1 ruby examples/large_tree_demo.rb
8
+ #
9
+ # This demo creates a realistic task tree with:
10
+ # - 50+ tasks total
11
+ # - Nested dependencies (tree depth 4+)
12
+ # - Varying execution times (50ms - 2000ms)
13
+ # - Some tasks that fail (to verify error visibility)
14
+ # - Tasks that produce output
15
+
16
+ # Level 4: Leaf tasks (no dependencies)
17
+ class FetchConfigA < Taski::Task
18
+ exports :config_a
19
+
20
+ def run
21
+ puts "Fetching config A..."
22
+ sleep(0.1)
23
+ @config_a = {server: "localhost", port: 3000}
24
+ end
25
+ end
26
+
27
+ class FetchConfigB < Taski::Task
28
+ exports :config_b
29
+
30
+ def run
31
+ puts "Fetching config B..."
32
+ sleep(0.15)
33
+ @config_b = {timeout: 30, retries: 3}
34
+ end
35
+ end
36
+
37
+ class FetchConfigC < Taski::Task
38
+ exports :config_c
39
+
40
+ def run
41
+ puts "Fetching config C..."
42
+ sleep(0.08)
43
+ @config_c = {debug: false, verbose: true}
44
+ end
45
+ end
46
+
47
+ class DownloadAssetA < Taski::Task
48
+ exports :asset_a
49
+
50
+ def run
51
+ puts "Downloading asset A (images)..."
52
+ sleep(0.3)
53
+ @asset_a = "images.tar.gz"
54
+ end
55
+ end
56
+
57
+ class DownloadAssetB < Taski::Task
58
+ exports :asset_b
59
+
60
+ def run
61
+ puts "Downloading asset B (fonts)..."
62
+ sleep(0.25)
63
+ @asset_b = "fonts.tar.gz"
64
+ end
65
+ end
66
+
67
+ class DownloadAssetC < Taski::Task
68
+ exports :asset_c
69
+
70
+ def run
71
+ puts "Downloading asset C (icons)..."
72
+ sleep(0.2)
73
+ @asset_c = "icons.tar.gz"
74
+ end
75
+ end
76
+
77
+ class DownloadAssetD < Taski::Task
78
+ exports :asset_d
79
+
80
+ def run
81
+ puts "Downloading asset D (templates)..."
82
+ sleep(0.35)
83
+ @asset_d = "templates.tar.gz"
84
+ end
85
+ end
86
+
87
+ class FetchSchemaV1 < Taski::Task
88
+ exports :schema_v1
89
+
90
+ def run
91
+ puts "Fetching schema v1..."
92
+ sleep(0.12)
93
+ @schema_v1 = {version: 1, tables: 10}
94
+ end
95
+ end
96
+
97
+ class FetchSchemaV2 < Taski::Task
98
+ exports :schema_v2
99
+
100
+ def run
101
+ puts "Fetching schema v2..."
102
+ sleep(0.18)
103
+ @schema_v2 = {version: 2, tables: 15}
104
+ end
105
+ end
106
+
107
+ class FetchSchemaV3 < Taski::Task
108
+ exports :schema_v3
109
+
110
+ def run
111
+ puts "Fetching schema v3..."
112
+ sleep(0.14)
113
+ @schema_v3 = {version: 3, tables: 20}
114
+ end
115
+ end
116
+
117
+ class LoadEnvDev < Taski::Task
118
+ exports :env_dev
119
+
120
+ def run
121
+ puts "Loading dev environment..."
122
+ sleep(0.05)
123
+ @env_dev = "development"
124
+ end
125
+ end
126
+
127
+ class LoadEnvStaging < Taski::Task
128
+ exports :env_staging
129
+
130
+ def run
131
+ puts "Loading staging environment..."
132
+ sleep(0.06)
133
+ @env_staging = "staging"
134
+ end
135
+ end
136
+
137
+ class LoadEnvProd < Taski::Task
138
+ exports :env_prod
139
+
140
+ def run
141
+ puts "Loading production environment..."
142
+ sleep(0.07)
143
+ @env_prod = "production"
144
+ end
145
+ end
146
+
147
+ class CheckDependencyA < Taski::Task
148
+ exports :dep_a_ok
149
+
150
+ def run
151
+ puts "Checking dependency A (Ruby)..."
152
+ sleep(0.1)
153
+ @dep_a_ok = true
154
+ end
155
+ end
156
+
157
+ class CheckDependencyB < Taski::Task
158
+ exports :dep_b_ok
159
+
160
+ def run
161
+ puts "Checking dependency B (Node)..."
162
+ sleep(0.12)
163
+ @dep_b_ok = true
164
+ end
165
+ end
166
+
167
+ class CheckDependencyC < Taski::Task
168
+ exports :dep_c_ok
169
+
170
+ def run
171
+ puts "Checking dependency C (Python)..."
172
+ sleep(0.08)
173
+ @dep_c_ok = true
174
+ end
175
+ end
176
+
177
+ class CheckDependencyD < Taski::Task
178
+ exports :dep_d_ok
179
+
180
+ def run
181
+ puts "Checking dependency D (Go)..."
182
+ sleep(0.09)
183
+ @dep_d_ok = true
184
+ end
185
+ end
186
+
187
+ class CheckDependencyE < Taski::Task
188
+ exports :dep_e_ok
189
+
190
+ def run
191
+ puts "Checking dependency E (Rust)..."
192
+ sleep(0.11)
193
+ @dep_e_ok = true
194
+ end
195
+ end
196
+
197
+ # Level 3: Aggregation tasks
198
+ class MergeConfigs < Taski::Task
199
+ exports :merged_config
200
+
201
+ def run
202
+ config_a = FetchConfigA.config_a
203
+ config_b = FetchConfigB.config_b
204
+ config_c = FetchConfigC.config_c
205
+ puts "Merging configs..."
206
+ sleep(0.2)
207
+ @merged_config = config_a.merge(config_b).merge(config_c)
208
+ end
209
+ end
210
+
211
+ class BundleAssets < Taski::Task
212
+ exports :bundled_assets
213
+
214
+ def run
215
+ asset_a = DownloadAssetA.asset_a
216
+ asset_b = DownloadAssetB.asset_b
217
+ asset_c = DownloadAssetC.asset_c
218
+ asset_d = DownloadAssetD.asset_d
219
+ puts "Bundling assets: #{asset_a}, #{asset_b}, #{asset_c}, #{asset_d}..."
220
+ sleep(0.4)
221
+ @bundled_assets = [asset_a, asset_b, asset_c, asset_d]
222
+ end
223
+ end
224
+
225
+ class MigrateDatabase < Taski::Task
226
+ exports :migration_result
227
+
228
+ def run
229
+ schema_v1 = FetchSchemaV1.schema_v1
230
+ FetchSchemaV2.schema_v2
231
+ schema_v3 = FetchSchemaV3.schema_v3
232
+ puts "Running migrations v1->v2->v3..."
233
+ sleep(0.5)
234
+ @migration_result = {from: schema_v1[:version], to: schema_v3[:version]}
235
+ end
236
+ end
237
+
238
+ class PrepareEnvironments < Taski::Task
239
+ exports :environments
240
+
241
+ def run
242
+ dev = LoadEnvDev.env_dev
243
+ staging = LoadEnvStaging.env_staging
244
+ prod = LoadEnvProd.env_prod
245
+ puts "Preparing environments: #{dev}, #{staging}, #{prod}..."
246
+ sleep(0.15)
247
+ @environments = [dev, staging, prod]
248
+ end
249
+ end
250
+
251
+ class ValidateDependencies < Taski::Task
252
+ exports :all_deps_ok
253
+
254
+ def run
255
+ deps = [
256
+ CheckDependencyA.dep_a_ok,
257
+ CheckDependencyB.dep_b_ok,
258
+ CheckDependencyC.dep_c_ok,
259
+ CheckDependencyD.dep_d_ok,
260
+ CheckDependencyE.dep_e_ok
261
+ ]
262
+ puts "Validating all dependencies..."
263
+ sleep(0.1)
264
+ @all_deps_ok = deps.all?
265
+ end
266
+ end
267
+
268
+ # Additional leaf tasks for more breadth
269
+ class GenerateCacheKeyA < Taski::Task
270
+ exports :cache_key_a
271
+
272
+ def run
273
+ puts "Generating cache key A..."
274
+ sleep(0.05)
275
+ @cache_key_a = "cache_a_#{rand(1000)}"
276
+ end
277
+ end
278
+
279
+ class GenerateCacheKeyB < Taski::Task
280
+ exports :cache_key_b
281
+
282
+ def run
283
+ puts "Generating cache key B..."
284
+ sleep(0.06)
285
+ @cache_key_b = "cache_b_#{rand(1000)}"
286
+ end
287
+ end
288
+
289
+ class GenerateCacheKeyC < Taski::Task
290
+ exports :cache_key_c
291
+
292
+ def run
293
+ puts "Generating cache key C..."
294
+ sleep(0.04)
295
+ @cache_key_c = "cache_c_#{rand(1000)}"
296
+ end
297
+ end
298
+
299
+ class WarmCacheA < Taski::Task
300
+ exports :cache_a_warmed
301
+
302
+ def run
303
+ key = GenerateCacheKeyA.cache_key_a
304
+ puts "Warming cache A with key: #{key}..."
305
+ sleep(0.2)
306
+ @cache_a_warmed = true
307
+ end
308
+ end
309
+
310
+ class WarmCacheB < Taski::Task
311
+ exports :cache_b_warmed
312
+
313
+ def run
314
+ key = GenerateCacheKeyB.cache_key_b
315
+ puts "Warming cache B with key: #{key}..."
316
+ sleep(0.15)
317
+ @cache_b_warmed = true
318
+ end
319
+ end
320
+
321
+ class WarmCacheC < Taski::Task
322
+ exports :cache_c_warmed
323
+
324
+ def run
325
+ key = GenerateCacheKeyC.cache_key_c
326
+ puts "Warming cache C with key: #{key}..."
327
+ sleep(0.18)
328
+ @cache_c_warmed = true
329
+ end
330
+ end
331
+
332
+ class PrepareCaches < Taski::Task
333
+ exports :caches_ready
334
+
335
+ def run
336
+ WarmCacheA.cache_a_warmed
337
+ WarmCacheB.cache_b_warmed
338
+ WarmCacheC.cache_c_warmed
339
+ puts "All caches prepared..."
340
+ sleep(0.1)
341
+ @caches_ready = true
342
+ end
343
+ end
344
+
345
+ # More leaf tasks
346
+ class FetchApiKeyA < Taski::Task
347
+ exports :api_key_a
348
+
349
+ def run
350
+ puts "Fetching API key A..."
351
+ sleep(0.08)
352
+ @api_key_a = "key_a_secret"
353
+ end
354
+ end
355
+
356
+ class FetchApiKeyB < Taski::Task
357
+ exports :api_key_b
358
+
359
+ def run
360
+ puts "Fetching API key B..."
361
+ sleep(0.09)
362
+ @api_key_b = "key_b_secret"
363
+ end
364
+ end
365
+
366
+ class FetchApiKeyC < Taski::Task
367
+ exports :api_key_c
368
+
369
+ def run
370
+ puts "Fetching API key C..."
371
+ sleep(0.07)
372
+ @api_key_c = "key_c_secret"
373
+ end
374
+ end
375
+
376
+ class ValidateApiKeys < Taski::Task
377
+ exports :api_keys_valid
378
+
379
+ def run
380
+ FetchApiKeyA.api_key_a
381
+ FetchApiKeyB.api_key_b
382
+ FetchApiKeyC.api_key_c
383
+ puts "Validating API keys..."
384
+ sleep(0.15)
385
+ @api_keys_valid = true
386
+ end
387
+ end
388
+
389
+ # Level 2: Integration tasks
390
+ class SetupInfrastructure < Taski::Task
391
+ exports :infra_ready
392
+
393
+ def run
394
+ MergeConfigs.merged_config
395
+ PrepareEnvironments.environments
396
+ ValidateDependencies.all_deps_ok
397
+ puts "Setting up infrastructure..."
398
+ sleep(0.3)
399
+ @infra_ready = true
400
+ end
401
+ end
402
+
403
+ class PrepareStaticAssets < Taski::Task
404
+ exports :static_assets_ready
405
+
406
+ def run
407
+ BundleAssets.bundled_assets
408
+ puts "Preparing static assets..."
409
+ sleep(0.25)
410
+ @static_assets_ready = true
411
+ end
412
+ end
413
+
414
+ class SetupDatabase < Taski::Task
415
+ exports :database_ready
416
+
417
+ def run
418
+ MigrateDatabase.migration_result
419
+ puts "Setting up database..."
420
+ sleep(0.35)
421
+ @database_ready = true
422
+ end
423
+ end
424
+
425
+ class InitializeCaches < Taski::Task
426
+ exports :caches_initialized
427
+
428
+ def run
429
+ PrepareCaches.caches_ready
430
+ puts "Initializing caches..."
431
+ sleep(0.2)
432
+ @caches_initialized = true
433
+ end
434
+ end
435
+
436
+ class SetupAuthentication < Taski::Task
437
+ exports :auth_ready
438
+
439
+ def run
440
+ ValidateApiKeys.api_keys_valid
441
+ puts "Setting up authentication..."
442
+ sleep(0.25)
443
+ @auth_ready = true
444
+ end
445
+ end
446
+
447
+ # Level 1: High-level integration
448
+ class PrepareBackend < Taski::Task
449
+ exports :backend_ready
450
+
451
+ def run
452
+ SetupInfrastructure.infra_ready
453
+ SetupDatabase.database_ready
454
+ SetupAuthentication.auth_ready
455
+ puts "Preparing backend services..."
456
+ sleep(0.4)
457
+ @backend_ready = true
458
+ end
459
+ end
460
+
461
+ class PrepareFrontend < Taski::Task
462
+ exports :frontend_ready
463
+
464
+ def run
465
+ PrepareStaticAssets.static_assets_ready
466
+ InitializeCaches.caches_initialized
467
+ puts "Preparing frontend..."
468
+ sleep(0.3)
469
+ @frontend_ready = true
470
+ end
471
+ end
472
+
473
+ class RunHealthChecks < Taski::Task
474
+ exports :health_ok
475
+
476
+ def run
477
+ PrepareBackend.backend_ready
478
+ PrepareFrontend.frontend_ready
479
+ puts "Running health checks..."
480
+ sleep(0.2)
481
+ @health_ok = true
482
+ end
483
+ end
484
+
485
+ # Root task
486
+ class DeployApplication < Taski::Task
487
+ exports :deploy_result
488
+
489
+ def run
490
+ RunHealthChecks.health_ok
491
+ puts "Deploying application..."
492
+ sleep(0.5)
493
+ @deploy_result = "Deployed successfully at #{Time.now}"
494
+ end
495
+ end
496
+
497
+ # Optional: Uncomment to test failure handling
498
+ # class FailingTask < Taski::Task
499
+ # exports :will_fail
500
+ #
501
+ # def run
502
+ # puts "This task will fail..."
503
+ # sleep(0.1)
504
+ # raise "Intentional failure for testing"
505
+ # end
506
+ # end
507
+
508
+ if __FILE__ == $0
509
+ puts "Large Tree Demo - 52 tasks with nested dependencies"
510
+ puts "=" * 50
511
+ puts ""
512
+
513
+ begin
514
+ result = DeployApplication.deploy_result
515
+ puts "\n\nFinal result: #{result}"
516
+ rescue => e
517
+ puts "\n\nExecution failed: #{e.message}"
518
+ end
519
+ end
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../lib/taski"
5
+
6
+ # Demo of simple one-line progress display mode
7
+ # Run with: TASKI_PROGRESS_MODE=simple ruby examples/simple_progress_demo.rb
8
+ # Or set via API: Taski.progress_mode = :simple
9
+
10
+ # Set simple progress mode via API
11
+ Taski.progress_mode = :simple
12
+
13
+ class DownloadLayer1 < Taski::Task
14
+ exports :layer1_data
15
+
16
+ def run
17
+ puts "Downloading base image..."
18
+ sleep(0.8)
19
+ puts "Base image complete"
20
+ @layer1_data = "Layer 1 data (base image)"
21
+ end
22
+ end
23
+
24
+ class DownloadLayer2 < Taski::Task
25
+ exports :layer2_data
26
+
27
+ def run
28
+ puts "Downloading dependencies..."
29
+ sleep(1.2)
30
+ puts "Dependencies complete"
31
+ @layer2_data = "Layer 2 data (dependencies)"
32
+ end
33
+ end
34
+
35
+ class DownloadLayer3 < Taski::Task
36
+ exports :layer3_data
37
+
38
+ def run
39
+ puts "Downloading application..."
40
+ sleep(0.3)
41
+ puts "Application complete"
42
+ @layer3_data = "Layer 3 data (application)"
43
+ end
44
+ end
45
+
46
+ class ExtractLayers < Taski::Task
47
+ exports :extracted_data
48
+
49
+ def run
50
+ layer1 = DownloadLayer1.layer1_data
51
+ layer2 = DownloadLayer2.layer2_data
52
+ layer3 = DownloadLayer3.layer3_data
53
+
54
+ puts "Extracting layers..."
55
+ sleep(0.3)
56
+ @extracted_data = "Extracted: #{layer1}, #{layer2}, #{layer3}"
57
+ end
58
+ end
59
+
60
+ class VerifyImage < Taski::Task
61
+ exports :verification_result
62
+
63
+ def run
64
+ data = ExtractLayers.extracted_data
65
+
66
+ puts "Verifying image..."
67
+ sleep(0.2)
68
+ @verification_result = "Verified: #{data}"
69
+ end
70
+ end
71
+
72
+ puts "=== Simple Progress Display Demo ==="
73
+ puts "Progress mode: #{Taski.progress_mode}"
74
+ puts ""
75
+
76
+ # Execute the final task (all dependencies will be resolved automatically)
77
+ result = VerifyImage.verification_result
78
+
79
+ puts "\n\nFinal result:"
80
+ puts result
data/lib/taski/args.rb CHANGED
@@ -4,18 +4,12 @@ require "monitor"
4
4
 
5
5
  module Taski
6
6
  # Runtime arguments accessible from any task.
7
- # Holds user-defined options and execution metadata.
7
+ # Holds user-defined options passed by the user at execution time.
8
8
  # Args is immutable after creation - options cannot be modified during task execution.
9
9
  class Args
10
- attr_reader :started_at, :working_directory, :root_task
11
-
12
10
  # @param options [Hash] User-defined options (immutable after creation)
13
- # @param root_task [Class] The root task class that initiated execution
14
- def initialize(options:, root_task:)
11
+ def initialize(options:)
15
12
  @options = options.dup.freeze
16
- @root_task = root_task
17
- @started_at = Time.now
18
- @working_directory = Dir.pwd
19
13
  end
20
14
 
21
15
  # Get a user-defined option value
data/lib/taski/env.rb ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Taski
4
+ # Runtime execution environment information.
5
+ # Holds system-managed metadata that is set automatically during task execution.
6
+ # Env is immutable after creation.
7
+ class Env
8
+ attr_reader :root_task, :started_at, :working_directory
9
+
10
+ # @param root_task [Class] The root task class that initiated execution
11
+ def initialize(root_task:)
12
+ @root_task = root_task
13
+ @started_at = Time.now
14
+ @working_directory = Dir.pwd
15
+ end
16
+ end
17
+ end