@jujulego/jill 3.0.0-alpha.7 → 3.0.0-alpha.9

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.
package/dist/main.js CHANGED
@@ -1,10 +1,10 @@
1
- ;{try{(function(){var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="423e1769-82e8-4ede-89c9-d0cfbda3929d",e._sentryDebugIdIdentifier="sentry-dbid-423e1769-82e8-4ede-89c9-d0cfbda3929d");})();}catch(e){}};!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{};e.SENTRY_RELEASE={id:"3.0.0-alpha.7"};}catch(e){}}();import { token$, inject$, asyncScope$ } from '@kyrielle/injector';
1
+ ;{try{(function(){var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="04cb3668-7526-4dae-86bb-05b85f96926a",e._sentryDebugIdIdentifier="sentry-dbid-04cb3668-7526-4dae-86bb-05b85f96926a");})();}catch(e){}};!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{};e.SENTRY_RELEASE={id:"3.0.0-alpha.9"};}catch(e){}}();import { token$, inject$, asyncScope$ } from '@kyrielle/injector';
2
2
  import { startSpan, getActiveSpan, updateSpanName, getRootSpan, startInactiveSpan, captureException } from '@sentry/node';
3
3
  import process$1 from 'node:process';
4
4
  import { hideBin } from 'yargs/helpers';
5
- import { pipe$, waitFor$, filter$, map$, collect$, asyncIterator$, var$, observable$, off$, once$, flow$ } from 'kyrielle';
5
+ import { pipe$, waitFor$, filter$, map$, collect$, asyncIterator$, var$, flow$ } from 'kyrielle';
6
6
  import yargs from 'yargs';
7
- import { TaskManager, scheduler$, isWorkloadEnded, WorkloadState, plan, spawn$, SpawnTask, GroupTask, TaskSet, ParallelGroup, FallbackGroup, SequenceGroup } from '@jujulego/tasks';
7
+ import { scheduler$, isWorkloadEnded, WorkloadState, spawn$, sequenceFlow$, parallelFlow$, fallbackFlow$ } from '@jujulego/tasks';
8
8
  import { logger$, withTimestamp, withLabel, qLogDelay, LogLevel, LogGateway, logDelay$, toStderr } from '@kyrielle/logger';
9
9
  import fs from 'node:fs';
10
10
  import { PathScurry } from 'path-scurry';
@@ -15,7 +15,7 @@ import { Glob } from 'glob';
15
15
  import normalize from 'normalize-package-data';
16
16
  import { satisfies, compare, parse } from 'semver';
17
17
  import moo from 'moo';
18
- import cp from 'node:child_process';
18
+ import { spawn } from 'node:child_process';
19
19
  import chalk from 'chalk';
20
20
  import slugify from 'slugify';
21
21
  import { qjson, qprop, q$, defineQuickFormat, qerror, qarg, qwrap } from '@jujulego/quick-tag';
@@ -24,14 +24,16 @@ import os from 'node:os';
24
24
  import { cosmiconfig, defaultLoaders } from 'cosmiconfig';
25
25
  import { chalkTemplateStderr } from 'chalk-template';
26
26
 
27
- var version = "3.0.0-alpha.7";
27
+ var version = "3.0.0-alpha.9";
28
28
 
29
29
  function trace(fun, opts) {
30
30
  const name = typeof opts === 'string' ? opts : opts.name;
31
- const use = typeof opts === 'object' ? opts.use : (_, r)=>r;
31
+ const op = typeof opts === 'object' ? opts.op : undefined;
32
+ const use = typeof opts === 'object' && opts.use || ((_, r)=>r);
32
33
  return function(...args) {
33
34
  return pipe$(startSpan({
34
- name
35
+ name,
36
+ op
35
37
  }, ()=>fun.call(this, ...args)), (r)=>use(name, r));
36
38
  };
37
39
  }
@@ -45,27 +47,19 @@ function instrument(opts) {
45
47
  });
46
48
  };
47
49
  }
48
- function traceAsyncGenerator(name, generator) {
49
- const instrumented = {
50
- ...generator,
51
- next: async ()=>startSpan({
52
- name,
53
- op: 'iterator.next'
54
- }, ()=>generator.next()),
55
- [Symbol.asyncIterator]: ()=>instrumented
56
- };
57
- return instrumented;
58
- }
59
50
  function traceImport(name, loader) {
60
51
  return startSpan({
61
- name: `load ${name}`,
52
+ name: name,
62
53
  op: 'resource.script'
63
54
  }, loader);
64
55
  }
65
56
 
66
57
  function command$5(module) {
67
- const name = getCommandName(module);
68
- const handler = trace(module.handler, 'cli.handler');
58
+ const name = commandName(module);
59
+ const handler = trace(module.handler, {
60
+ name: commandName(module),
61
+ op: 'cli.handler'
62
+ });
69
63
  return (parser)=>parser.command({
70
64
  ...module,
71
65
  async handler (args) {
@@ -77,7 +71,7 @@ function command$5(module) {
77
71
  }
78
72
  });
79
73
  }
80
- function getCommandName(module) {
74
+ function commandName(module) {
81
75
  if (!module.command) {
82
76
  return '[unknown]';
83
77
  }
@@ -97,47 +91,6 @@ const LOGGER = token$('Logger', ()=>logger$(withTimestamp()));
97
91
  const PATH_SCURRY = token$('PathScurry', ()=>new PathScurry('/', {
98
92
  fs
99
93
  }));
100
- /** @deprecated */ const TASK_MANAGER = token$('TaskManager', async ()=>{
101
- const manager = new TaskManager({
102
- jobs: (await inject$(CONFIG, asyncScope$())).jobs,
103
- logger: inject$(LOGGER)
104
- });
105
- let rootSpan = getActiveSpan();
106
- if (rootSpan) rootSpan = getRootSpan(rootSpan);
107
- const spans = new Map();
108
- manager.events$.on('added', (task)=>{
109
- // Main span
110
- const span = startInactiveSpan({
111
- name: task.name,
112
- parentSpan: (task.group && spans.get(task.group.id)) ?? rootSpan,
113
- op: 'task'
114
- });
115
- task.events$.on('completed', ({ status })=>{
116
- span.setStatus({
117
- code: status === 'done' ? 1 : 2
118
- });
119
- span.end();
120
- });
121
- spans.set(task.id, span);
122
- // Status spans
123
- let statusSpan = startInactiveSpan({
124
- name: task.status,
125
- parentSpan: span,
126
- op: 'task.status'
127
- });
128
- task.events$.on('status', ({ status })=>{
129
- statusSpan.end();
130
- if (!task.completed) {
131
- statusSpan = startInactiveSpan({
132
- name: status,
133
- parentSpan: span,
134
- op: 'task.status'
135
- });
136
- }
137
- });
138
- });
139
- return manager;
140
- });
141
94
  const SCHEDULER = token$('Scheduler', async ()=>{
142
95
  const config = await inject$(CONFIG, asyncScope$());
143
96
  const logger = inject$(LOGGER);
@@ -163,40 +116,44 @@ const SCHEDULER = token$('Scheduler', async ()=>{
163
116
  });
164
117
  // Status spans
165
118
  let stateSpan;
166
- const sub = job.state$.subscribe((state)=>{
167
- stateSpan?.end();
168
- if (isWorkloadEnded(state)) {
169
- jobSpan.setAttribute('job.final_state', state);
170
- jobSpan.setStatus({
171
- code: state === WorkloadState.Succeeded ? 1 : 2
172
- });
173
- jobSpan.end();
174
- sub.unsubscribe();
175
- } else {
176
- stateSpan = startInactiveSpan({
177
- op: 'job.state',
178
- name: state,
179
- parentSpan: jobSpan
180
- });
119
+ let subscription;
120
+ job.state$.subscribe({
121
+ start: (sub)=>{
122
+ subscription = sub;
123
+ },
124
+ next: (state)=>{
125
+ stateSpan?.end();
126
+ if (isWorkloadEnded(state)) {
127
+ jobSpan.setAttribute('job.final_state', state);
128
+ jobSpan.setAttribute('job.duration', job.duration().seconds());
129
+ jobSpan.setStatus({
130
+ code: state === WorkloadState.Succeeded ? 1 : 2
131
+ });
132
+ jobSpan.end();
133
+ subscription.unsubscribe();
134
+ } else {
135
+ stateSpan = startInactiveSpan({
136
+ op: 'job.state',
137
+ name: state,
138
+ parentSpan: jobSpan
139
+ });
140
+ }
181
141
  }
182
142
  });
183
143
  });
184
144
  return scheduler;
185
145
  });
186
146
 
187
- // Utils
188
- function printJson(data, stream = process.stdout) {
189
- if (stream.isTTY) {
190
- stream.write(JSON.stringify(data, null, 2));
191
- } else {
192
- stream.write(JSON.stringify(data));
193
- }
194
- }
195
-
196
147
  // Utils
197
148
  function executeCommand(module) {
198
- const prepare = trace(module.prepare, 'cli.prepare');
199
- const execute = module.execute && trace(module.execute, 'cli.execute');
149
+ const prepare = trace(module.prepare, {
150
+ name: commandName(module),
151
+ op: 'cli.prepare'
152
+ });
153
+ const execute = module.execute && trace(module.execute, {
154
+ name: commandName(module),
155
+ op: 'cli.execute'
156
+ });
200
157
  return command$5({
201
158
  ...module,
202
159
  builder (base) {
@@ -208,40 +165,39 @@ function executeCommand(module) {
208
165
  }
209
166
  },
210
167
  async handler (args) {
211
- const tasks = await prepare(args);
168
+ const job = await prepare(args) ?? null;
169
+ if (!job) {
170
+ const logger = inject$(LOGGER);
171
+ logger.warning('No task found');
172
+ process$1.exitCode = 1;
173
+ return;
174
+ }
212
175
  if (args.plan) {
213
- if (args.planMode === 'json') {
214
- printJson(Array.from(plan(tasks)));
215
- } else {
216
- const { default: TaskPlanInk } = await traceImport('TaskPlanInk', ()=>import('./task-plan.ink.js'));
217
- await TaskPlanInk({
218
- tasks
219
- });
220
- }
176
+ const { printPlan } = await traceImport('printPlan', ()=>import('./print-plan.js'));
177
+ printPlan(job);
221
178
  } else {
222
179
  if (execute) {
223
- await execute(args, tasks);
224
- } else if (tasks.tasks.length > 0) {
225
- const { default: TaskExecInk } = await traceImport('TaskExecInk', ()=>import('./task-exec.ink.js'));
226
- await TaskExecInk({
227
- tasks,
180
+ await execute(args, job);
181
+ } else {
182
+ const { default: JobExecInk } = await traceImport('JobExecInk', ()=>import('./job-exec.ink.js'));
183
+ await JobExecInk({
184
+ job,
228
185
  verbose: [
229
186
  'verbose',
230
187
  'debug'
231
188
  ].includes(args.verbose)
232
189
  });
233
- } else {
234
- const logger = inject$(LOGGER);
235
- logger.warning('No task found');
236
- process$1.exitCode = 1;
237
190
  }
238
191
  }
239
192
  }
240
193
  });
241
194
  }
242
- function planCommand(module, tasks$) {
195
+ function planCommand(module, job$) {
243
196
  if ('prepare' in module) {
244
- const prepare = trace(module.prepare, 'cli.prepare');
197
+ const prepare = trace(module.prepare, {
198
+ name: commandName(module),
199
+ op: 'cli.prepare'
200
+ });
245
201
  return command$5({
246
202
  ...module,
247
203
  builder (base) {
@@ -253,7 +209,7 @@ function planCommand(module, tasks$) {
253
209
  }
254
210
  },
255
211
  async handler (args) {
256
- tasks$.mutate(await prepare(args));
212
+ job$.mutate(await prepare(args) ?? null);
257
213
  }
258
214
  });
259
215
  } else {
@@ -305,30 +261,30 @@ class ClientError extends Error {
305
261
  }
306
262
  }
307
263
 
308
- var _dec$4, _dec1$3, _dec2$1, _initProto$4;
309
- _dec$4 = instrument('GitService.isAffected'), _dec1$3 = instrument('GitService.listBranches'), _dec2$1 = instrument('GitService.listTags');
264
+ var _dec$2, _dec1$1, _dec2, _initProto$2;
265
+ _dec$2 = instrument('GitService.isAffected'), _dec1$1 = instrument('GitService.listBranches'), _dec2 = instrument('GitService.listTags');
310
266
  class GitService {
311
267
  static{
312
- ({ e: [_initProto$4] } = _(this, [
268
+ ({ e: [_initProto$2] } = _(this, [
313
269
  [
314
- _dec$4,
270
+ _dec$2,
315
271
  2,
316
272
  "isAffected"
317
273
  ],
318
274
  [
319
- _dec1$3,
275
+ _dec1$1,
320
276
  2,
321
277
  "listBranches"
322
278
  ],
323
279
  [
324
- _dec2$1,
280
+ _dec2,
325
281
  2,
326
282
  "listTags"
327
283
  ]
328
284
  ], []));
329
285
  }
330
286
  // Attributes
331
- _scheduler = (_initProto$4(this), inject$(SCHEDULER));
287
+ _scheduler = (_initProto$2(this), inject$(SCHEDULER));
332
288
  _logger = inject$(LOGGER);
333
289
  // Methods
334
290
  /**
@@ -493,89 +449,40 @@ async function with$(lock, fn) {
493
449
  }
494
450
  }
495
451
 
496
- // Utils
497
- async function* combine(...generators) {
498
- for (const gen of generators){
499
- yield* gen;
500
- }
501
- }
502
- function streamLines$(task, stream = 'stdout') {
503
- return observable$((observer, signal)=>{
504
- const off = off$();
505
- let current = '';
506
- // End
507
- off.add(once$(task.events$, 'completed', ()=>{
508
- if (current) observer.next(current);
509
- observer.complete();
510
- off.unsubscribe();
511
- }));
512
- // Abort
513
- signal.addEventListener('abort', ()=>off.unsubscribe(), {
514
- once: true
515
- });
516
- // Steam
517
- off.add(task.events$.on(`stream.${stream}`, (chunk)=>{
518
- const data = current + chunk.data.toString('utf-8');
519
- const lines = data.split(/\r?\n/);
520
- current = lines.pop() ?? '';
521
- for (const line of lines){
522
- observer.next(line);
523
- }
524
- }));
525
- });
526
- }
527
-
528
- // Class
529
- class CommandTask extends SpawnTask {
530
- workspace;
531
- // Constructor
532
- constructor(workspace, command, args, opts = {}){
533
- let cmd = command;
534
- if (opts.superCommand) {
535
- if (typeof opts.superCommand === 'string') {
536
- opts.superCommand = [
537
- opts.superCommand
538
- ];
539
- }
540
- if (opts.superCommand.length > 0) {
541
- cmd = opts.superCommand[0];
542
- args = [
543
- ...opts.superCommand.slice(1),
544
- command,
545
- ...args
546
- ];
547
- }
452
+ function command$(workspace, cmd, args, opts = {}) {
453
+ const { superCommand, logger = inject$(LOGGER), ...rest } = opts;
454
+ // Apply super command
455
+ if (superCommand) {
456
+ if (typeof superCommand === 'string') {
457
+ args = [
458
+ cmd,
459
+ ...args
460
+ ];
461
+ cmd = superCommand;
462
+ } else if (superCommand.length) {
463
+ args = [
464
+ ...superCommand.slice(1),
465
+ cmd,
466
+ ...args
467
+ ];
468
+ cmd = superCommand[0];
469
+ }
470
+ }
471
+ // Prepare job
472
+ const job = spawn$(cmd, args, {
473
+ ...rest,
474
+ cwd: workspace.root,
475
+ env: {
476
+ FORCE_COLOR: '1',
477
+ ...rest.env
548
478
  }
549
- super(cmd, args, {
550
- workspace,
551
- command
552
- }, {
553
- ...opts,
554
- cwd: workspace.root,
555
- env: {
556
- FORCE_COLOR: '1',
557
- ...opts.env
558
- }
559
- }), this.workspace = workspace;
560
- this._logStreams();
561
- }
562
- // Methods
563
- _logStreams() {
564
- const off = off$(streamLines$(this, 'stdout').subscribe((line)=>this.logger$.info(line)), streamLines$(this, 'stderr').subscribe((line)=>this.logger$.info(line)));
565
- once$(this.events$, 'completed', ()=>{
566
- off.unsubscribe();
567
- });
568
- }
569
- }
570
- // Utils
571
- function isCommandCtx(ctx) {
572
- return 'workspace' in ctx && 'command' in ctx;
479
+ });
480
+ job.stdout.on('data', (data)=>logger.info(data.toString('utf-8').trimEnd()));
481
+ job.stderr.on('data', (data)=>logger.info(data.toString('utf-8').trimEnd()));
482
+ return job;
573
483
  }
574
484
 
575
485
  // Utils
576
- function capitalize(txt) {
577
- return txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase();
578
- }
579
486
  function splitCommandLine(line) {
580
487
  line = line.trim();
581
488
  const parts = [];
@@ -603,173 +510,84 @@ function splitCommandLine(line) {
603
510
  return parts;
604
511
  }
605
512
 
606
- // Class
607
- class ScriptTask extends GroupTask {
608
- workspace;
609
- script;
610
- args;
611
- // Attributes
612
- _preHookTasks = null;
613
- _postHookTasks = null;
614
- _scriptTasks = null;
615
- _runHooks;
616
- // Constructor
617
- constructor(workspace, script, args, opts){
618
- super(script, {
619
- workspace,
620
- script
621
- }, opts), this.workspace = workspace, this.script = script, this.args = args;
622
- this._runHooks = opts?.runHooks ?? true;
623
- }
624
- // Methods
625
- async _runScript(script, args) {
626
- const line = this.workspace.getScript(script);
627
- if (!line) {
628
- return null;
629
- }
630
- // Create command task for script
631
- const [command, ...commandArgs] = splitCommandLine(line);
632
- const set = new TaskSet();
633
- if (!command) {
634
- return set;
635
- }
636
- if (command === 'jill') {
637
- const argv = commandArgs.map((arg)=>arg.replace(/^["'](.+)["']$/, '$1'));
638
- const { PlannerService } = await import('./planner.service.js');
639
- const plannerService = inject$(PlannerService);
640
- const tasks = await plannerService.plan(argv, this.workspace.root);
641
- if (tasks) {
642
- return tasks;
643
- }
644
- }
645
- const pm = await this.workspace.project.packageManager();
646
- set.add(new CommandTask(this.workspace, command, [
647
- ...commandArgs,
648
- ...args
649
- ], {
650
- logger: this.logger$,
651
- superCommand: pm === 'yarn' ? [
652
- 'yarn',
653
- 'exec'
654
- ] : undefined
655
- }));
656
- return set;
657
- }
658
- async prepare() {
659
- // Prepare script run
660
- this._scriptTasks = await this._runScript(this.script, this.args);
661
- if (!this._scriptTasks) {
662
- throw new ScriptNotFound(`No script ${this.script} in ${this.workspace.name}`);
663
- }
664
- // Prepare hooks run
665
- if (this._runHooks) {
666
- this._preHookTasks = await this._runScript(`pre${this.script}`, []);
667
- this._postHookTasks = await this._runScript(`post${this.script}`, []);
668
- }
669
- // Add tasks to group
670
- if (this._preHookTasks) {
671
- this.logger$.verbose(`found pre-hook script "pre${this.script}"`);
672
- for (const tsk of this._preHookTasks){
673
- this.add(tsk);
674
- }
675
- }
676
- for (const tsk of this._scriptTasks){
677
- this.add(tsk);
678
- }
679
- if (this._postHookTasks) {
680
- this.logger$.verbose(`found post-hook script "post${this.script}"`);
681
- for (const tsk of this._postHookTasks){
682
- this.add(tsk);
683
- }
684
- }
685
- }
686
- async *onOrchestrate() {
687
- if (!this._scriptTasks) {
688
- throw new Error('ScriptTask needs to be prepared. Call prepare before starting it');
689
- }
690
- // Run pre-hook
691
- if (this._preHookTasks) {
692
- yield* this._preHookTasks;
693
- if (await this._hasFailed(this._preHookTasks)) {
694
- return this.setStatus('failed');
695
- }
696
- }
697
- // Run script
698
- yield* this._scriptTasks;
699
- if (await this._hasFailed(this._scriptTasks)) {
700
- return this.setStatus('failed');
701
- }
702
- // Run post-hook
703
- if (this._postHookTasks) {
704
- yield* this._postHookTasks;
705
- if (await this._hasFailed(this._postHookTasks)) {
706
- return this.setStatus('failed');
707
- }
708
- }
709
- this.setStatus('done');
710
- }
711
- async _hasFailed(set) {
712
- const results = await waitFor$(set.events$, 'finished');
713
- return results.failed > 0;
714
- }
715
- async onStop() {
716
- if (!this._scriptTasks) return;
717
- for (const tsk of this._scriptTasks){
718
- await tsk.stop();
719
- }
720
- }
721
- complexity(cache = new Map()) {
722
- let complexity = super.complexity(cache);
723
- if (this._scriptTasks) {
724
- complexity += this._scriptTasks.tasks.reduce((cpl, tsk)=>cpl + tsk.complexity(cache), 0);
725
- }
726
- cache.set(this.id, complexity);
727
- return complexity;
728
- }
729
- // Properties
730
- get project() {
731
- return this.workspace.project;
732
- }
513
+ async function runScript$(workspace, script, args, opts = {}) {
514
+ // Run script itself
515
+ const jobs = [
516
+ await planScript$(workspace, script, args, opts)
517
+ ];
518
+ if (!jobs[0]) {
519
+ throw new ScriptNotFound(`No script ${script} in ${workspace.name}`);
520
+ }
521
+ // Run hooks
522
+ if (opts.runHooks) {
523
+ jobs.unshift(await planScript$(workspace, `pre${script}`, [], opts));
524
+ jobs.push(await planScript$(workspace, `post${script}`, [], opts));
525
+ }
526
+ // Prepare workflow
527
+ const flow = pipe$(jobs, filter$((job)=>job !== null), collect$(sequenceFlow$({
528
+ label: script,
529
+ type: 'script'
530
+ })));
531
+ return {
532
+ ...flow,
533
+ script,
534
+ workspace
535
+ };
733
536
  }
734
537
  // Utils
735
- function isScriptCtx(ctx) {
736
- return 'workspace' in ctx && 'script' in ctx;
538
+ async function planScript$(workspace, script, args, opts) {
539
+ // Load script
540
+ const line = workspace?.getScript(script);
541
+ if (!line) {
542
+ return null;
543
+ }
544
+ // Parse script
545
+ const [command, ...commandArgs] = splitCommandLine(line);
546
+ if (!command) {
547
+ return null;
548
+ }
549
+ if (command === 'jill') {
550
+ const argv = commandArgs.map((arg)=>arg.replace(/^["'](.+)["']$/, '$1'));
551
+ const { PlannerService } = await import('./planner.service.js');
552
+ const plannerService = inject$(PlannerService);
553
+ const job = await plannerService.plan(argv, workspace.root);
554
+ if (job) {
555
+ return job;
556
+ }
557
+ }
558
+ // Run command
559
+ const pm = await workspace.project.packageManager();
560
+ return command$(workspace, command, [
561
+ ...commandArgs,
562
+ ...args
563
+ ], {
564
+ logger: opts.logger,
565
+ superCommand: pm === 'yarn' && command !== 'yarn' ? [
566
+ 'yarn',
567
+ 'exec'
568
+ ] : undefined
569
+ });
737
570
  }
738
571
  class ScriptNotFound extends ClientError {
739
572
  name = 'ScriptNotFound';
740
573
  }
741
574
 
742
- var _dec$3, _dec1$2, _initProto$3;
743
- _dec$3 = instrument({
744
- name: 'Workspace.dependencies',
745
- use: traceAsyncGenerator
746
- }), _dec1$2 = instrument({
747
- name: 'Workspace.devDependencies',
748
- use: traceAsyncGenerator
749
- });
575
+ // Utils
576
+ async function* combine(...generators) {
577
+ for (const gen of generators){
578
+ yield* gen;
579
+ }
580
+ }
581
+
750
582
  class Workspace {
751
583
  manifest;
752
584
  project;
753
- static{
754
- ({ e: [_initProto$3] } = _(this, [
755
- [
756
- _dec$3,
757
- 2,
758
- "dependencies"
759
- ],
760
- [
761
- _dec1$2,
762
- 2,
763
- "devDependencies"
764
- ]
765
- ], []));
766
- }
767
585
  // Attributes
768
- _affectedCache = (_initProto$3(this), new Map());
586
+ _affectedCache = new Map();
769
587
  _logger;
770
588
  _git = inject$(GitService);
771
589
  _root;
772
- _tasks = new Map();
590
+ _jobs = new Map();
773
591
  // Constructor
774
592
  constructor(root, manifest, project){
775
593
  this.manifest = manifest;
@@ -778,7 +596,7 @@ class Workspace {
778
596
  this._logger = inject$(LOGGER).child(withLabel(manifest.name));
779
597
  }
780
598
  // Methods
781
- async _buildDependencies(task, opts) {
599
+ async _buildDependencies(job, opts) {
782
600
  const generators = [];
783
601
  switch(opts.buildDeps ?? 'all'){
784
602
  case 'all':
@@ -791,7 +609,7 @@ class Workspace {
791
609
  for await (const dep of combine(...generators)){
792
610
  const build = await dep.build(opts);
793
611
  if (build) {
794
- task.dependsOn(build);
612
+ job.dependsOn(build);
795
613
  }
796
614
  }
797
615
  }
@@ -856,15 +674,15 @@ class Workspace {
856
674
  }
857
675
  async build(opts = {}) {
858
676
  const script = opts.buildScript ?? 'build';
859
- const task = await this.run(script, [], opts);
860
- if (!task) {
677
+ const job = await this.run(script, [], opts);
678
+ if (!job) {
861
679
  this._logger.warning(`will not be built (no "${script}" script found)`);
862
680
  }
863
- return task;
681
+ return job;
864
682
  }
865
683
  async exec(command, args = [], opts = {}) {
866
684
  const pm = await this.project.packageManager();
867
- const task = new CommandTask(this, command, args, {
685
+ const job = command$(this, command, args, {
868
686
  ...opts,
869
687
  logger: this._logger.child(withLabel(`${this.name}$${command}`)),
870
688
  superCommand: pm === 'yarn' ? [
@@ -872,8 +690,8 @@ class Workspace {
872
690
  'exec'
873
691
  ] : undefined
874
692
  });
875
- await this._buildDependencies(task, opts);
876
- return task;
693
+ await this._buildDependencies(job, opts);
694
+ return job;
877
695
  }
878
696
  getScript(script) {
879
697
  const { scripts = {} } = this.manifest;
@@ -885,19 +703,18 @@ class Workspace {
885
703
  return null;
886
704
  }
887
705
  // Create task if it doesn't exist yet
888
- let task = this._tasks.get(script);
889
- if (!task) {
706
+ let job = this._jobs.get(script);
707
+ if (!job) {
890
708
  const config = await inject$(CONFIG, asyncScope$());
891
- task = new ScriptTask(this, script, args, {
709
+ job = await runScript$(this, script, args, {
892
710
  ...opts,
893
711
  logger: this._logger.child(withLabel(`${this.name}#${script}`)),
894
712
  runHooks: config.hooks
895
713
  });
896
- await task.prepare();
897
- await this._buildDependencies(task, opts);
898
- this._tasks.set(script, task);
714
+ await this._buildDependencies(job, opts);
715
+ this._jobs.set(script, job);
899
716
  }
900
- return task;
717
+ return job;
901
718
  }
902
719
  toJSON() {
903
720
  return {
@@ -921,43 +738,9 @@ class Workspace {
921
738
  }
922
739
  }
923
740
 
924
- var _dec$2, _dec1$1, _dec2, _dec3, _dec4, _initProto$2;
925
- _dec$2 = instrument('Project.currentWorkspace'), _dec1$1 = instrument('Project.mainWorkspace'), _dec2 = instrument('Project.packageManager'), _dec3 = instrument('Project.workspace'), _dec4 = instrument({
926
- name: 'Project.workspaces',
927
- use: traceAsyncGenerator
928
- });
929
741
  class Project {
930
- static{
931
- ({ e: [_initProto$2] } = _(this, [
932
- [
933
- _dec$2,
934
- 2,
935
- "currentWorkspace"
936
- ],
937
- [
938
- _dec1$1,
939
- 2,
940
- "mainWorkspace"
941
- ],
942
- [
943
- _dec2,
944
- 2,
945
- "packageManager"
946
- ],
947
- [
948
- _dec3,
949
- 2,
950
- "workspace"
951
- ],
952
- [
953
- _dec4,
954
- 2,
955
- "workspaces"
956
- ]
957
- ], []));
958
- }
959
742
  // Attributes
960
- _isFullyLoaded = (_initProto$2(this), false);
743
+ _isFullyLoaded = false;
961
744
  _lock = mutex$();
962
745
  _mainWorkspace;
963
746
  _packageManager;
@@ -1210,7 +993,7 @@ class TaskSyntaxError extends ClientError {
1210
993
  }
1211
994
 
1212
995
  var _dec, _dec1, _initProto;
1213
- _dec = instrument('TaskParserService.parse'), _dec1 = instrument('TaskParserService.buildTask');
996
+ _dec = instrument('TaskParserService.parse'), _dec1 = instrument('TaskParserService.buildJob');
1214
997
  // Service
1215
998
  class TaskParserService {
1216
999
  static{
@@ -1223,7 +1006,7 @@ class TaskParserService {
1223
1006
  [
1224
1007
  _dec1,
1225
1008
  2,
1226
- "buildTask"
1009
+ "buildJob"
1227
1010
  ]
1228
1011
  ], []));
1229
1012
  }
@@ -1410,42 +1193,36 @@ class TaskParserService {
1410
1193
  }
1411
1194
  }
1412
1195
  }
1413
- async buildTask(node, workspace, opts) {
1196
+ async buildJob(node, workspace, opts) {
1414
1197
  if (TaskParserService.isTaskNode(node)) {
1415
- const task = await workspace.run(node.script, node.args, opts);
1416
- if (!task) {
1198
+ const job = await workspace.run(node.script, node.args, opts);
1199
+ if (!job) {
1417
1200
  throw new TaskExpressionError(`Workspace ${workspace.name} have no ${node.script} script`);
1418
1201
  }
1419
- return task;
1202
+ return job;
1420
1203
  } else {
1421
- let group;
1204
+ let flow;
1422
1205
  if (node.operator === '//') {
1423
- group = new ParallelGroup('In parallel', {
1424
- workspace
1425
- }, {
1426
- logger: this._logger
1206
+ flow = parallelFlow$({
1207
+ label: 'In parallel'
1427
1208
  });
1428
1209
  } else if (node.operator === '||') {
1429
- group = new FallbackGroup('Fallbacks', {
1430
- workspace
1431
- }, {
1432
- logger: this._logger
1210
+ flow = fallbackFlow$({
1211
+ label: 'Fallbacks'
1433
1212
  });
1434
1213
  } else {
1435
1214
  if (node.operator === '->' && TaskParserService._sequenceOperatorWarn) {
1436
1215
  this._logger.warn('Sequence operator -> is deprecated in favor of &&. It will be removed in a next major release.');
1437
1216
  TaskParserService._sequenceOperatorWarn = true;
1438
1217
  }
1439
- group = new SequenceGroup('In sequence', {
1440
- workspace
1441
- }, {
1442
- logger: this._logger
1218
+ flow = sequenceFlow$({
1219
+ label: 'In sequence'
1443
1220
  });
1444
1221
  }
1445
1222
  for (const child of node.tasks){
1446
- group.add(await this.buildTask(child, workspace, opts));
1223
+ flow.push(await this.buildJob(child, workspace, opts));
1447
1224
  }
1448
- return group;
1225
+ return flow;
1449
1226
  }
1450
1227
  }
1451
1228
  }
@@ -1535,16 +1312,22 @@ const command$4 = {
1535
1312
  const scripts = Array.from(taskParser.extractScripts(tree));
1536
1313
  // Load workspaces
1537
1314
  const project = loadProject(args);
1538
- const workspaces = pipe$(asyncIterator$(project.workspaces()), hasEveryScript$(scripts), filters.build());
1315
+ const workspaces = await waitFor$(pipe$(asyncIterator$(project.workspaces()), hasEveryScript$(scripts), filters.build(), collect$()));
1316
+ workspaces.sort((a, b)=>a.name.localeCompare(b.name));
1317
+ if (workspaces.length === 0) {
1318
+ return;
1319
+ }
1539
1320
  // Prepare tasks
1540
- const tasks = new TaskSet();
1541
- for await (const wks of workspaces){
1542
- tasks.add(await taskParser.buildTask(tree.roots[0], wks, {
1321
+ const flow = parallelFlow$({
1322
+ label: '[hidden]'
1323
+ });
1324
+ for (const wks of workspaces){
1325
+ flow.push(await taskParser.buildJob(tree.roots[0], wks, {
1543
1326
  buildScript: args.buildScript,
1544
1327
  buildDeps: args.depsMode
1545
1328
  }));
1546
1329
  }
1547
- return tasks;
1330
+ return flow;
1548
1331
  }
1549
1332
  };
1550
1333
 
@@ -1620,51 +1403,68 @@ const command$3 = {
1620
1403
  rest.splice(0, 1);
1621
1404
  }
1622
1405
  // Run script in workspace
1623
- const tasks = new TaskSet();
1624
- tasks.add(await workspace.exec(args.command, rest, {
1406
+ return await workspace.exec(args.command, rest, {
1625
1407
  buildScript: args.buildScript,
1626
1408
  buildDeps: args.depsMode
1627
- }));
1628
- return tasks;
1409
+ });
1629
1410
  },
1630
- async execute (args, tasks) {
1631
- const task = tasks.tasks[0];
1632
- if (task.dependencies.length > 0) {
1633
- const dependencies = new TaskSet();
1634
- for (const dep of task.dependencies){
1635
- dependencies.add(dep);
1636
- }
1411
+ async execute (args, arg) {
1412
+ const job = arg;
1413
+ if (job.dependencies().length > 0) {
1414
+ const dependencies = pipe$(job.dependencies(), collect$(parallelFlow$({
1415
+ label: 'build dependencies'
1416
+ })));
1637
1417
  // Run dependencies first with spinners
1638
- const { default: TaskExecInk } = await traceImport('TaskExecInk', ()=>import('./task-exec.ink.js'));
1639
- await TaskExecInk({
1640
- tasks: dependencies,
1418
+ const { default: JobExecInk } = await traceImport('JobExecInk', ()=>import('./job-exec.ink.js'));
1419
+ await JobExecInk({
1420
+ job: dependencies,
1641
1421
  verbose: [
1642
1422
  'verbose',
1643
1423
  'debug'
1644
1424
  ].includes(args.verbose)
1645
1425
  });
1426
+ if (dependencies.state() !== WorkloadState.Succeeded) {
1427
+ return;
1428
+ }
1646
1429
  } else {
1647
1430
  const logger = inject$(LOGGER);
1648
1431
  logger.verbose('No dependency to build');
1649
1432
  }
1650
- const child = cp.spawn(task.cmd, task.args, {
1651
- stdio: 'inherit',
1652
- cwd: task.cwd,
1653
- env: {
1654
- ...process$1.env,
1655
- ...task.env
1656
- },
1657
- shell: true,
1658
- windowsHide: true
1659
- });
1660
- process$1.exitCode = await new Promise((resolve)=>{
1661
- child.on('close', (code)=>{
1662
- resolve(code ?? 0);
1433
+ await startSpan({
1434
+ op: 'subprocess',
1435
+ name: [
1436
+ job.cmd,
1437
+ ...job.args
1438
+ ].join(' ')
1439
+ }, async ()=>{
1440
+ const child = spawn(job.cmd, job.args, {
1441
+ stdio: 'inherit',
1442
+ cwd: job.cwd,
1443
+ env: {
1444
+ ...process$1.env,
1445
+ ...job.env
1446
+ },
1447
+ shell: true,
1448
+ windowsHide: true
1449
+ });
1450
+ process$1.exitCode = await new Promise((resolve)=>{
1451
+ child.on('close', (code)=>{
1452
+ resolve(code ?? 0);
1453
+ });
1663
1454
  });
1664
1455
  });
1665
1456
  }
1666
1457
  };
1667
1458
 
1459
+ // Utils
1460
+ function printJson(data, stream = process.stdout) {
1461
+ if (stream.isTTY) {
1462
+ stream.write(JSON.stringify(data, null, 2));
1463
+ } else {
1464
+ stream.write(JSON.stringify(data));
1465
+ }
1466
+ }
1467
+
1668
1468
  // Command
1669
1469
  const command$2 = {
1670
1470
  command: 'list',
@@ -1900,12 +1700,10 @@ const command$1 = {
1900
1700
  // Parse task expression
1901
1701
  const taskParser = inject$(TaskParserService);
1902
1702
  const tree = taskParser.parse(expr.join(' '));
1903
- const tasks = new TaskSet();
1904
- tasks.add(await taskParser.buildTask(tree.roots[0], workspace, {
1703
+ return await taskParser.buildJob(tree.roots[0], workspace, {
1905
1704
  buildScript: args.buildScript,
1906
1705
  buildDeps: args.depsMode
1907
- }));
1908
- return tasks;
1706
+ });
1909
1707
  }
1910
1708
  };
1911
1709
 
@@ -1962,8 +1760,6 @@ var schema = {
1962
1760
  properties: properties
1963
1761
  };
1964
1762
 
1965
- // Constants
1966
- const CPU_COUNT = os.cpus().length;
1967
1763
  /**
1968
1764
  * Loads and make configuration accessible
1969
1765
  */ class ConfigService {
@@ -2002,7 +1798,7 @@ const CPU_COUNT = os.cpus().length;
2002
1798
  // Correct jobs value
2003
1799
  if (config.jobs <= 0) {
2004
1800
  Object.assign(config, {
2005
- jobs: Math.max(CPU_COUNT - 1, 1)
1801
+ jobs: Math.max(os.availableParallelism() - 1, 1)
2006
1802
  });
2007
1803
  }
2008
1804
  this._logger.debug`loaded config:\n${qjson(config, {
@@ -2115,8 +1911,8 @@ function baseParser() {
2115
1911
  }
2116
1912
  /**
2117
1913
  * Prepare parser planning commands
2118
- */ function planParser(tasks$) {
2119
- return pipe$(baseParser(), planCommand(command$4, tasks$), planCommand(command$3, tasks$), planCommand(command$2, tasks$), planCommand(command$1, tasks$), planCommand(command, tasks$));
1914
+ */ function planParser(job$) {
1915
+ return pipe$(baseParser(), planCommand(command$4, job$), planCommand(command$3, job$), planCommand(command$2, job$), planCommand(command$1, job$), planCommand(command, job$));
2120
1916
  }
2121
1917
 
2122
1918
  // Bootstrap
@@ -2125,25 +1921,37 @@ const parser = executeParser();
2125
1921
  void startSpan({
2126
1922
  name: 'jill',
2127
1923
  op: 'cli.main',
1924
+ startTime: 0,
2128
1925
  attributes: {
2129
1926
  'cli.argv': argv
2130
1927
  }
2131
- }, ()=>parser.wrap(parser.terminalWidth()).fail((msg, err)=>{
2132
- const logger = inject$(LOGGER);
2133
- if (msg) {
2134
- logger.error(msg);
2135
- } else if (err instanceof ClientError) {
2136
- logger.error(err.message);
2137
- } else {
2138
- captureException(err, {
2139
- tags: {
2140
- handled: false
2141
- }
2142
- });
2143
- logger.error(err.message);
2144
- }
2145
- process$1.exitCode = 1;
2146
- }).parseAsync(argv).catch(()=>{}));
1928
+ }, async ()=>{
1929
+ try {
1930
+ startInactiveSpan({
1931
+ name: 'bootstrap',
1932
+ op: 'cli.bootstrap',
1933
+ startTime: 0
1934
+ }).end();
1935
+ return await parser.wrap(parser.terminalWidth()).fail((msg, err)=>{
1936
+ const logger = inject$(LOGGER);
1937
+ if (msg) {
1938
+ logger.error(msg);
1939
+ } else if (err instanceof ClientError) {
1940
+ logger.error(err.message);
1941
+ } else {
1942
+ captureException(err, {
1943
+ tags: {
1944
+ handled: false
1945
+ }
1946
+ });
1947
+ logger.error(err.message);
1948
+ }
1949
+ process$1.exitCode = 1;
1950
+ }).parseAsync(argv);
1951
+ } catch {
1952
+ // Already handled
1953
+ }
1954
+ });
2147
1955
 
2148
- export { CommandTask as C, LOGGER as L, ScriptTask as S, TASK_MANAGER as T, isScriptCtx as a, CWD as b, capitalize as c, ConfigService as d, instrument as e, isCommandCtx as i, logFormat as l, planParser as p };
1956
+ export { CWD as C, LOGGER as L, SCHEDULER as S, ConfigService as a, instrument as i, logFormat as l, planParser as p };
2149
1957
  //# sourceMappingURL=main.js.map