-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcommands.rb
More file actions
64 lines (57 loc) · 2.03 KB
/
commands.rb
File metadata and controls
64 lines (57 loc) · 2.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# frozen_string_literal: true
require "open3"
require "json"
module Importmap
module Update
# Abstracts execution of external commands (bin/importmap) so the rest
# of the codebase doesn't shell out directly. This is the seam tests hook
# into — production code runs commands for real, tests inject a
# FixtureRunner that replays pre-recorded (argv → stdout, exit) tuples.
#
# The interface deliberately mirrors what Open3.capture3 returns:
#
# runner.run("bin/importmap", "outdated")
# # => Result(stdout: "...", stderr: "...", success: true, exit: 0)
#
# Commands are passed as an argv array, not a shell string. That's both
# safer (no shell-injection surprises from package names) and easier to
# match against fixture keys.
module Commands
Result = Struct.new(:stdout, :stderr, :exit_code, keyword_init: true) do
def success?
exit_code == 0
end
end
class CommandError < StandardError
attr_reader :argv, :result
def initialize(argv, result)
@argv = argv
@result = result
super("`#{argv.join(" ")}` exited #{result.exit_code}: #{result.stderr.strip}")
end
end
# Production runner: actually executes the command.
class ShellRunner
# @param cwd [String, nil] working directory (defaults to current)
def initialize(cwd: nil)
@cwd = cwd
end
def run(*argv)
opts = {}
opts[:chdir] = @cwd if @cwd
Bundler.with_unbundled_env do
stdout, stderr, status = Open3.capture3(*argv, opts)
Result.new(stdout: stdout, stderr: stderr, exit_code: status.exitstatus)
end
end
# Raises on non-zero exit. Use when you have no recovery strategy
# and just want to surface the error to the caller.
def run!(*argv)
result = run(*argv)
raise CommandError.new(argv, result) unless result.success?
result
end
end
end
end
end