workspaces 0.1.11 → 0.1.13

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.
@@ -26,10 +26,16 @@ module Workspaces
26
26
  $stdout.print(prefixed(scrubbed))
27
27
  end
28
28
 
29
+ # The filtering applied to everything written. Public so StepLog can copy exactly what the
30
+ # combined log received, instead of reimplementing the rules.
31
+ def scrub_text(message)
32
+ @overrides.scrub(message)
33
+ end
34
+
29
35
  private
30
36
 
31
37
  def scrub(message)
32
- @overrides.scrub(message)
38
+ scrub_text(message)
33
39
  end
34
40
 
35
41
  def prefixed(message)
@@ -1,3 +1,3 @@
1
1
  module Workspaces
2
- VERSION = '0.1.11'
2
+ VERSION = '0.1.13'
3
3
  end
@@ -3,12 +3,15 @@ require_relative 'recipe'
3
3
  require_relative 'command_runner'
4
4
  require_relative 'backend'
5
5
  require_relative 'environment_overrides'
6
+ require_relative 'step_log'
7
+ require_relative 'duration_format'
6
8
 
7
9
  module Workspaces
8
10
  class Workflow
9
11
  def initialize(workspace, log, state: StateStore.new(Config.state_file))
10
12
  @workspace = workspace
11
- @log = log
13
+ @combined_log = log
14
+ @log = StepLog.new(log, workspace.id)
12
15
  @state = state
13
16
  @backend = Backend.new(workspace.id)
14
17
  end
@@ -18,6 +21,7 @@ module Workspaces
18
21
  overrides = EnvironmentOverrides.new(@workspace.id).load
19
22
  steps = recipe.for_operation(restart: restart)
20
23
  publish_steps(steps)
24
+ StepLog.reset(@workspace.id)
21
25
  @backend.stop!
22
26
  context = build_context(@backend.reserve!)
23
27
  runner = CommandRunner.new(@workspace.path, @log)
@@ -27,6 +31,8 @@ module Workspaces
27
31
  rescue StandardError
28
32
  @backend.stop!
29
33
  raise
34
+ ensure
35
+ @log.finish_step
30
36
  end
31
37
 
32
38
  private
@@ -50,6 +56,7 @@ module Workspaces
50
56
  def execute(step, recipe, context, runner, overrides)
51
57
  started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
52
58
  progress(step, 'active')
59
+ @log.begin_step(step.fetch('id'))
53
60
  @log.puts "==> #{step.fetch('name')}"
54
61
  command = recipe.command(step, context)
55
62
  env = recipe.env(step, context, overrides: overrides)
@@ -60,7 +67,10 @@ module Workspaces
60
67
  @backend.ensure_alive! if @server_started
61
68
  end
62
69
  @server_started = true if step['background']
63
- rescue StandardError
70
+ rescue StandardError => e
71
+ # The reason a step failed is not command output, so the step file would otherwise end
72
+ # without it. Record it where the step's own accordion can show it.
73
+ @log.puts "ERROR: #{e.message}"
64
74
  finish_step(step, 'failed', started_at)
65
75
  raise
66
76
  else
@@ -70,14 +80,15 @@ module Workspaces
70
80
  def finish_step(step, status, started_at)
71
81
  duration = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at).round(3)
72
82
  progress(step, status, duration_seconds: duration)
73
- @log.puts format('==> %s %s (%.3fs)', step.fetch('name'), status, duration)
83
+ @log.puts format('==> %s %s (%s)', step.fetch('name'), status, DurationFormat.call(duration))
74
84
  end
75
85
 
76
86
  def progress(step, status, duration_seconds: nil)
77
87
  @state.transaction do |data|
78
88
  entry = data.fetch(@workspace.id)
79
- entry['steps'].find { |item| item['key'] == step['id'] }
80
- .merge!('state' => status, 'duration_seconds' => duration_seconds)
89
+ record = entry['steps'].find { |item| item['key'] == step['id'] }
90
+ record.merge!('state' => status, 'duration_seconds' => duration_seconds)
91
+ record['started_at'] = Time.now.utc.iso8601(3) if status == 'active'
81
92
  entry['message'] = step['name']
82
93
  entry['current_step'] = step['id']
83
94
  entry['updated_at'] = Time.now.utc.iso8601
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: workspaces
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.11
4
+ version: 0.1.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Workspaces contributors
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-10-15 00:00:00.000000000 Z
11
+ date: 2026-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -71,6 +71,7 @@ files:
71
71
  - exe/workspaces
72
72
  - lib/workspaces.rb
73
73
  - lib/workspaces/backend.rb
74
+ - lib/workspaces/build_history.rb
74
75
  - lib/workspaces/child_env.rb
75
76
  - lib/workspaces/cli.rb
76
77
  - lib/workspaces/command_runner.rb
@@ -83,15 +84,18 @@ files:
83
84
  - lib/workspaces/dashboard/styles.css
84
85
  - lib/workspaces/dashboard/template.html.erb
85
86
  - lib/workspaces/dashboard_view.rb
87
+ - lib/workspaces/duration_format.rb
86
88
  - lib/workspaces/environment_overrides.rb
87
89
  - lib/workspaces/front_door.rb
88
90
  - lib/workspaces/paths.rb
89
91
  - lib/workspaces/port_allocator.rb
90
92
  - lib/workspaces/presentation.rb
93
+ - lib/workspaces/progress.rb
91
94
  - lib/workspaces/proxy_middleware.rb
92
95
  - lib/workspaces/recipe.rb
93
96
  - lib/workspaces/registry.rb
94
97
  - lib/workspaces/state_store.rb
98
+ - lib/workspaces/step_log.rb
95
99
  - lib/workspaces/tee_log.rb
96
100
  - lib/workspaces/tls.rb
97
101
  - lib/workspaces/version.rb