-
Notifications
You must be signed in to change notification settings - Fork 112
/
mock_project.rb
123 lines (104 loc) · 3.86 KB
/
mock_project.rb
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# typed: strict
# frozen_string_literal: true
require "open3"
require "helpers/mock_gem"
module Tapioca
# A mock project used for testing purposes
class MockProject < MockDir
extend T::Sig
# Path to Tapioca's source files
TAPIOCA_PATH = T.let((Pathname.new(__FILE__) / ".." / ".." / "..").to_s, String)
# Write `contents` to the gemfile in this project
sig { params(contents: String, append: T::Boolean).void }
def gemfile(contents, append: false)
write("Gemfile", contents, append: append)
end
# Add a gem requirement to this project's gemfile from a `MockGem`
sig { params(gem: MockGem, require: T.nilable(T.any(FalseClass, String))).void }
def require_mock_gem(gem, require: nil)
line = gem.gemfile_line.dup
line << ", require: #{require.inspect}" unless require.nil?
line << "\n"
gemfile(line, append: true)
end
# Add a gem requirement to this project's gemfile from a real gem
sig { params(name: String, version: T.nilable(String), require: T.nilable(T.any(FalseClass, String))).void }
def require_real_gem(name, version = nil, require: nil)
line = +"gem \"#{name}\""
line << ", \"#{version}\"" if version
line << ", require: #{require.inspect}" unless require.nil?
line << "\n"
gemfile(line, append: true)
end
# Default Gemfile contents requiring only Tapioca
sig { returns(String) }
def tapioca_gemfile
<<~GEMFILE
source("https://rubygems.org")
gemspec name: "tapioca", path: "#{TAPIOCA_PATH}"
GEMFILE
end
# Write `contents` to the `sorbet/config` file of this project
sig { params(contents: String, append: T::Boolean).void }
def sorbet_config(contents, append: false)
write("sorbet/config", contents, append: append)
end
sig { returns(String) }
def bundler_version
@bundler_version || Bundler::VERSION
end
sig { void }
def reset_bundler_version
return unless @bundler_version
bundle_install
end
class ExecResult < T::Struct
extend T::Sig
const :out, String
const :err, String
const :status, T::Boolean
sig { returns(String) }
def to_s
<<~STR
########## STDOUT ##########
#{out.empty? ? "<empty>" : out}
########## STDERR ##########
#{err.empty? ? "<empty>" : err}
########## STATUS: #{status} ##########
STR
end
end
# Run `bundle install` in this project context (unbundled env)
sig { params(version: T.nilable(String)).returns(ExecResult) }
def bundle_install(version: nil)
@bundler_version = T.let(version, T.nilable(String))
opts = {}
opts[:chdir] = path
Bundler.with_unbundled_env do
::Gem.install("bundler", bundler_version)
out, err, status = Open3.capture3(["bundle", "_#{bundler_version}_", "install"].join(" "), opts)
ExecResult.new(out: out, err: err, status: T.must(status.success?))
end
end
# Run a `command` with `bundle exec` in this project context (unbundled env)
sig { params(command: String).returns(ExecResult) }
def bundle_exec(command)
opts = {}
opts[:chdir] = path
Bundler.with_unbundled_env do
out, err, status = Open3.capture3(["bundle", "_#{bundler_version}_", "exec", command].join(" "), opts)
ExecResult.new(out: out, err: err, status: T.must(status.success?))
end
end
# Run a Tapioca `command` with `bundle exec` in this project context (unbundled env)
sig { params(command: String).returns(ExecResult) }
def tapioca(command)
exec_command = ["tapioca", command]
if command.start_with?(/gem/)
exec_command << "--workers=1" unless command.match?("--workers")
exec_command << "--no-doc" unless command.match?("--doc")
end
bundle_exec(exec_command.join(" "))
end
end
end