foobar_templates 2.0.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.
- checksums.yaml +7 -0
- data/.beader/.gitignore +6 -0
- data/.beader/issues/1-support-flexible-template-topologies.yaml +21 -0
- data/.beader/issues/2-add-monorepo-support-for-template-discovery-and-generation.yaml +33 -0
- data/.beader/issues/3-implement-monorepo-aware-recursive-template-inventory.yaml +29 -0
- data/.beader/issues/4-add-leaf-template-selection-with-ambiguity-and-not-found-handling.yaml +30 -0
- data/.beader/issues/5-integrate-leaf-template-resolution-into-generation-flow.yaml +30 -0
- data/.beader/issues/6-add-monorepo-discovery-and-generation-test-coverage.yaml +31 -0
- data/.beader/issues/7-document-monorepo-template-configuration-and-selection.yaml +30 -0
- data/.beader/meta.yaml +1 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +154 -0
- data/Rakefile +55 -0
- data/bin/foobar_templates +72 -0
- data/changelog +107 -0
- data/config/config +8 -0
- data/foobar_templates.gemspec +33 -0
- data/lib/foobar_templates/cli/cheat_sheet.rb +12 -0
- data/lib/foobar_templates/cli/cli.rb +3 -0
- data/lib/foobar_templates/cli/dir_to_template.rb +120 -0
- data/lib/foobar_templates/cli/setup_personal_templates_repo.rb +135 -0
- data/lib/foobar_templates/cli/template_generator.rb +462 -0
- data/lib/foobar_templates/configurator.rb +99 -0
- data/lib/foobar_templates/core/core.rb +9 -0
- data/lib/foobar_templates/core/dir_to_template.rb +114 -0
- data/lib/foobar_templates/strings.rb +23 -0
- data/lib/foobar_templates/template_manager.rb +119 -0
- data/lib/foobar_templates/templates/template-test/.vscode/launch.json +0 -0
- data/lib/foobar_templates/templates/template-test/foo-bar/keep +0 -0
- data/lib/foobar_templates/templates/template-test/foo-bar.rb +16 -0
- data/lib/foobar_templates/templates/template-test/foo_bar/keep +0 -0
- data/lib/foobar_templates/templates/template-test/foobar.yml +2 -0
- data/lib/foobar_templates/templates/template-test/simple_dir/keep +0 -0
- data/lib/foobar_templates/templates/template-test/test_confirmed +0 -0
- data/lib/foobar_templates/templates/test_template/foo-bar/keep +0 -0
- data/lib/foobar_templates/templates/test_template/foo-bar.rb +21 -0
- data/lib/foobar_templates/templates/test_template/foo_bar/keep +0 -0
- data/lib/foobar_templates/templates/test_template/foobar.yml +2 -0
- data/lib/foobar_templates/templates/test_template/simple_dir/keep +0 -0
- data/lib/foobar_templates/version.rb +3 -0
- data/lib/foobar_templates.rb +151 -0
- data/spec/data/variable_manifest_test.rb +21 -0
- data/spec/foobar_templates/cli/dir_to_template_spec.rb +153 -0
- data/spec/foobar_templates/core/dir_to_template_spec.rb +104 -0
- data/spec/foobar_templates_spec.rb +573 -0
- data/spec/spec_helper.rb +106 -0
- data/spec/template_manager_spec.rb +68 -0
- metadata +157 -0
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
describe FoobarTemplates do
|
|
5
|
+
before :each do
|
|
6
|
+
@mocked_home = "/tmp/foobar_templates_mock_home"
|
|
7
|
+
@template_root = "#{@mocked_home}/.foobar/templates"
|
|
8
|
+
@dst_dir = "/tmp/foobar_templates_dst_dir"
|
|
9
|
+
|
|
10
|
+
reset_test_env
|
|
11
|
+
FileUtils.chdir(@dst_dir)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'has a version number' do
|
|
15
|
+
expect(FoobarTemplates::VERSION).not_to be nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'has a cheat sheet it will share' do
|
|
19
|
+
output = FoobarTemplates.cheat_sheet
|
|
20
|
+
|
|
21
|
+
expect(output).to match(/foo-bar: \W* good-dog/x)
|
|
22
|
+
expect(output).to match(/FOO_BAR: \W* GOOD_DOG/x)
|
|
23
|
+
expect(output).to match(/FOO_IMAGE_PATH: \W* test\/good-dog/x)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# List
|
|
27
|
+
|
|
28
|
+
it 'gives the user a helpful output when there are no templates installed' do
|
|
29
|
+
list_output = FoobarTemplates.list
|
|
30
|
+
|
|
31
|
+
expect(list_output).to start_with "You have no templates."
|
|
32
|
+
expect(File).to exist("#{ENV['HOME']}/.foobar")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'creates a config file if needed and lists properly' do
|
|
36
|
+
create_user_defined_template
|
|
37
|
+
|
|
38
|
+
list_output = FoobarTemplates.list
|
|
39
|
+
|
|
40
|
+
expect(list_output).to eq " MISC:\n empty_template\n\n"
|
|
41
|
+
expect(File).to exist("#{ENV['HOME']}/.foobar")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "lists with good categories" do
|
|
45
|
+
category = "ARDUINO"
|
|
46
|
+
create_user_defined_template(category)
|
|
47
|
+
|
|
48
|
+
list_output = FoobarTemplates.list
|
|
49
|
+
expect(list_output).to include category
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "lists omit the prefix 'template-' if present in repo" do
|
|
53
|
+
category = "ANYTHING"
|
|
54
|
+
full_template_name = "template-happy-burger"
|
|
55
|
+
create_user_defined_template(category, "template-happy-burger")
|
|
56
|
+
|
|
57
|
+
list_output = FoobarTemplates.list
|
|
58
|
+
# expect(list_output.include?(full_template_name)).to be false
|
|
59
|
+
expect(list_output).not_to include full_template_name
|
|
60
|
+
expect(list_output).to include "happy-burger"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "lists leaf templates inside monorepo containers" do
|
|
64
|
+
create_monorepo_template(["template-platform"], monorepo: true)
|
|
65
|
+
create_monorepo_template(["template-platform", "template-api"], monorepo: false, category: "services")
|
|
66
|
+
create_monorepo_template(["template-platform", "template-ui"], monorepo: false, category: "frontend")
|
|
67
|
+
|
|
68
|
+
list_output = FoobarTemplates.list
|
|
69
|
+
|
|
70
|
+
expect(list_output).to include "api"
|
|
71
|
+
expect(list_output).to include "ui"
|
|
72
|
+
expect(list_output).not_to include "platform"
|
|
73
|
+
expect(list_output).to include "SERVICES"
|
|
74
|
+
expect(list_output).to include "FRONTEND"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "recursively traverses nested monorepo containers" do
|
|
78
|
+
create_monorepo_template(["template-org"], monorepo: true)
|
|
79
|
+
create_monorepo_template(["template-org", "template-team"], monorepo: true)
|
|
80
|
+
create_monorepo_template(["template-org", "template-team", "template-console"], monorepo: false, category: "cli")
|
|
81
|
+
|
|
82
|
+
list_output = FoobarTemplates.list
|
|
83
|
+
|
|
84
|
+
expect(list_output).to include "console"
|
|
85
|
+
expect(list_output).to include "CLI"
|
|
86
|
+
expect(list_output).not_to include "org"
|
|
87
|
+
expect(list_output).not_to include "team"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Generate
|
|
91
|
+
|
|
92
|
+
it "generates from a monorepo leaf template and uses leaf bootstrap config" do
|
|
93
|
+
root_dir = create_monorepo_template(["template-platform"], monorepo: true)
|
|
94
|
+
leaf_dir = create_monorepo_template(["template-platform", "template-api"], monorepo: false, category: "services")
|
|
95
|
+
|
|
96
|
+
File.write("#{root_dir}/foobar.yml", "monorepo: true\nbootstrap_command: echo root-config\n")
|
|
97
|
+
File.write("#{leaf_dir}/foobar.yml", "bootstrap_command: echo leaf-config\n")
|
|
98
|
+
File.write("#{leaf_dir}/foo-bar.rb", "puts 'foo-bar'\n")
|
|
99
|
+
|
|
100
|
+
options = { bin: false, ext: false, coc: false, template: "api" }
|
|
101
|
+
gem_name = "tool-go-good-dog"
|
|
102
|
+
|
|
103
|
+
output = capture_stdout { FoobarTemplates.generate_template(options, gem_name) }
|
|
104
|
+
|
|
105
|
+
expect(output).to include "leaf-config"
|
|
106
|
+
expect(output).not_to include "root-config"
|
|
107
|
+
expect(File).to exist("#{@dst_dir}/#{gem_name}/#{gem_name}.rb")
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "finds the template-test template even if the template- prefix was omitted" do
|
|
111
|
+
options = {bin: false, ext: false, coc: false, template: "test"}
|
|
112
|
+
gem_name = "tmp_gem"
|
|
113
|
+
|
|
114
|
+
capture_stdout { FoobarTemplates.generate_template(options, gem_name) }
|
|
115
|
+
expect(File).to exist("#{@dst_dir}/#{gem_name}/test_confirmed")
|
|
116
|
+
expect(File).to exist("#{@dst_dir}/#{gem_name}/.vscode/launch.json")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "has a useful dynamically_generate_template_directories method" do
|
|
120
|
+
options = { bin: false, ext: false, coc: false, template: "test_template" }
|
|
121
|
+
gem_name = "good-dog"
|
|
122
|
+
my_gem = FoobarTemplates::CLI::TemplateGenerator.new(options, gem_name)
|
|
123
|
+
|
|
124
|
+
src_dst_map = my_gem.send('dynamically_generate_template_directories')
|
|
125
|
+
|
|
126
|
+
expect(src_dst_map['foo-bar']).to eq "good-dog"
|
|
127
|
+
expect(src_dst_map['foo_bar']).to eq "good_dog"
|
|
128
|
+
expect(src_dst_map['simple_dir']).to eq 'simple_dir'
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it "returns the expected interpolated string when substitute_template_values is called" do
|
|
132
|
+
options = { bin: false, ext: false, coc: false, template: "test_template" }
|
|
133
|
+
gem_name = "good-dog"
|
|
134
|
+
my_gem = FoobarTemplates::CLI::TemplateGenerator.new(options, gem_name)
|
|
135
|
+
|
|
136
|
+
short_path = 'foo-bar'
|
|
137
|
+
long_path = 'hello/foo-bar/blah/foo-bar'
|
|
138
|
+
|
|
139
|
+
short_interpolated_string = my_gem.send('substitute_template_values', short_path)
|
|
140
|
+
expect(short_interpolated_string).to eq gem_name
|
|
141
|
+
|
|
142
|
+
long_interpolated_string = my_gem.send('substitute_template_values', long_path)
|
|
143
|
+
expect(long_interpolated_string).to eq "hello/good-dog/blah/good-dog"
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it "has a useful dynamically_generate_templates_files method" do
|
|
147
|
+
options = { bin: false, ext: false, coc: false, template: "test_template" }
|
|
148
|
+
gem_name = "good-dog"
|
|
149
|
+
my_gem = FoobarTemplates::CLI::TemplateGenerator.new(options, gem_name)
|
|
150
|
+
|
|
151
|
+
src_dst_map = my_gem.send('dynamically_generate_templates_files')
|
|
152
|
+
|
|
153
|
+
expect(src_dst_map['foo-bar/keep']).to eq "good-dog/keep"
|
|
154
|
+
expect(src_dst_map['foo-bar.rb']).to eq 'good-dog.rb'
|
|
155
|
+
expect(src_dst_map['foo_bar/keep']).to eq 'good_dog/keep'
|
|
156
|
+
expect(src_dst_map['simple_dir/keep']).to eq 'simple_dir/keep'
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it "won't generate template files that are listed under the gitignore" do
|
|
160
|
+
template_dir = create_user_defined_template("testing", "template-user-supplied")
|
|
161
|
+
options = { bin: false, ext: false, coc: false, template: "template-user-supplied" }
|
|
162
|
+
gem_name = "good-dog"
|
|
163
|
+
|
|
164
|
+
File.write("#{template_dir}/.gitignore", "node_modules/")
|
|
165
|
+
File.write("#{template_dir}/README.md", "Hello")
|
|
166
|
+
FileUtils.mkdir("#{template_dir}/node_modules")
|
|
167
|
+
File.write("#{template_dir}/node_modules/dont_template.rb", "I must not be interpretted")
|
|
168
|
+
`git init #{template_dir}`
|
|
169
|
+
|
|
170
|
+
capture_stdout { FoobarTemplates.generate_template(options, gem_name) }
|
|
171
|
+
|
|
172
|
+
expect(File).not_to exist "#{@dst_dir}/#{gem_name}/node_modules/dont_template.rb"
|
|
173
|
+
expect(File).not_to exist "#{@dst_dir}/#{gem_name}/node_modules"
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it "executes the bootstrap_command if supplied" do
|
|
177
|
+
template_dir = create_user_defined_template("testing", "template-user-supplied")
|
|
178
|
+
options = { bin: false, ext: false, coc: false, template: "template-user-supplied" }
|
|
179
|
+
gem_name = "good-dog"
|
|
180
|
+
|
|
181
|
+
File.write("#{template_dir}/foobar.yml", "bootstrap_command: echo hihihi")
|
|
182
|
+
File.write("#{template_dir}/README.md", "# Readme...")
|
|
183
|
+
`git init #{template_dir}`
|
|
184
|
+
|
|
185
|
+
output = capture_stdout { FoobarTemplates.generate_template(options, gem_name) }
|
|
186
|
+
|
|
187
|
+
expect(output).to include "hihihi"
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it "interpolates variables into the bootstrap_command" do
|
|
191
|
+
# this is quite pointless, we're literally allowing the user to execute a command on their shell...
|
|
192
|
+
template_dir = create_user_defined_template("testing", "template-user-supplied")
|
|
193
|
+
options = { bin: false, ext: false, coc: false, template: "template-user-supplied" }
|
|
194
|
+
gem_name = "good-dog"
|
|
195
|
+
|
|
196
|
+
File.write("#{template_dir}/foobar.yml", 'bootstrap_command: "echo foo-bar"')
|
|
197
|
+
File.write("#{template_dir}/README.md", "# Readme...")
|
|
198
|
+
`git init #{template_dir}`
|
|
199
|
+
|
|
200
|
+
output = capture_stdout { FoobarTemplates.generate_template(options, gem_name) }
|
|
201
|
+
|
|
202
|
+
expect(output).to include "echo #{gem_name}"
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
describe "name_validation" do
|
|
206
|
+
it "rejects names listed in reserved_names and skips bootstrap_command" do
|
|
207
|
+
template_dir = create_user_defined_template("testing", "template-user-supplied")
|
|
208
|
+
options = { bin: false, ext: false, coc: false, template: "template-user-supplied" }
|
|
209
|
+
gem_name = "good-dog"
|
|
210
|
+
|
|
211
|
+
File.write(
|
|
212
|
+
"#{template_dir}/foobar.yml",
|
|
213
|
+
"name_validation:\n reserved_names: [bad-dog, good-dog, ugly-dog]\nbootstrap_command: echo BOOTSTRAP_RAN\n"
|
|
214
|
+
)
|
|
215
|
+
File.write("#{template_dir}/README.md", "# Readme")
|
|
216
|
+
`git init #{template_dir}`
|
|
217
|
+
|
|
218
|
+
expect {
|
|
219
|
+
capture_stdout { capture_stderr { FoobarTemplates.generate_template(options, gem_name) } }
|
|
220
|
+
}.to raise_error(RuntimeError)
|
|
221
|
+
|
|
222
|
+
expect($captured_stderr).to include "reserved by template"
|
|
223
|
+
expect(File).not_to exist("#{@dst_dir}/#{gem_name}")
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
it "allows names that are not in reserved_names" do
|
|
227
|
+
template_dir = create_user_defined_template("testing", "template-user-supplied")
|
|
228
|
+
options = { bin: false, ext: false, coc: false, template: "template-user-supplied" }
|
|
229
|
+
gem_name = "good-dog"
|
|
230
|
+
|
|
231
|
+
File.write(
|
|
232
|
+
"#{template_dir}/foobar.yml",
|
|
233
|
+
"name_validation:\n reserved_names: [bad-dog, ugly-dog]\n"
|
|
234
|
+
)
|
|
235
|
+
File.write("#{template_dir}/README.md", "# Readme")
|
|
236
|
+
`git init #{template_dir}`
|
|
237
|
+
|
|
238
|
+
capture_stdout { FoobarTemplates.generate_template(options, gem_name) }
|
|
239
|
+
|
|
240
|
+
expect(File).to exist("#{@dst_dir}/#{gem_name}/README.md")
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
it "rejects names that don't match regex_validator" do
|
|
244
|
+
template_dir = create_user_defined_template("testing", "template-user-supplied")
|
|
245
|
+
options = { bin: false, ext: false, coc: false, template: "template-user-supplied" }
|
|
246
|
+
gem_name = "good-dog"
|
|
247
|
+
|
|
248
|
+
File.write(
|
|
249
|
+
"#{template_dir}/foobar.yml",
|
|
250
|
+
"name_validation:\n regex_validator: \"^[a-z][a-z0-9_]*$\"\n"
|
|
251
|
+
)
|
|
252
|
+
File.write("#{template_dir}/README.md", "# Readme")
|
|
253
|
+
`git init #{template_dir}`
|
|
254
|
+
|
|
255
|
+
expect {
|
|
256
|
+
capture_stdout { capture_stderr { FoobarTemplates.generate_template(options, gem_name) } }
|
|
257
|
+
}.to raise_error(RuntimeError)
|
|
258
|
+
|
|
259
|
+
expect($captured_stderr).to include "does not match"
|
|
260
|
+
expect(File).not_to exist("#{@dst_dir}/#{gem_name}")
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
it "accepts names that match regex_validator" do
|
|
264
|
+
template_dir = create_user_defined_template("testing", "template-user-supplied")
|
|
265
|
+
options = { bin: false, ext: false, coc: false, template: "template-user-supplied" }
|
|
266
|
+
gem_name = "good-dog"
|
|
267
|
+
|
|
268
|
+
File.write(
|
|
269
|
+
"#{template_dir}/foobar.yml",
|
|
270
|
+
"name_validation:\n regex_validator: \"^[a-z][a-z0-9-]*$\"\n"
|
|
271
|
+
)
|
|
272
|
+
File.write("#{template_dir}/README.md", "# Readme")
|
|
273
|
+
`git init #{template_dir}`
|
|
274
|
+
|
|
275
|
+
capture_stdout { FoobarTemplates.generate_template(options, gem_name) }
|
|
276
|
+
|
|
277
|
+
expect(File).to exist("#{@dst_dir}/#{gem_name}/README.md")
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
it "applies both reserved_names and regex_validator together" do
|
|
281
|
+
template_dir = create_user_defined_template("testing", "template-user-supplied")
|
|
282
|
+
options = { bin: false, ext: false, coc: false, template: "template-user-supplied" }
|
|
283
|
+
gem_name = "fmt"
|
|
284
|
+
|
|
285
|
+
File.write(
|
|
286
|
+
"#{template_dir}/foobar.yml",
|
|
287
|
+
"name_validation:\n reserved_names: [fmt, std]\n regex_validator: \"^[a-z][a-z0-9-]*$\"\n"
|
|
288
|
+
)
|
|
289
|
+
File.write("#{template_dir}/README.md", "# Readme")
|
|
290
|
+
`git init #{template_dir}`
|
|
291
|
+
|
|
292
|
+
expect {
|
|
293
|
+
capture_stdout { capture_stderr { FoobarTemplates.generate_template(options, gem_name) } }
|
|
294
|
+
}.to raise_error(RuntimeError)
|
|
295
|
+
|
|
296
|
+
expect($captured_stderr).to include "reserved"
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
it "raises a clear error when regex_validator is malformed" do
|
|
300
|
+
template_dir = create_user_defined_template("testing", "template-user-supplied")
|
|
301
|
+
options = { bin: false, ext: false, coc: false, template: "template-user-supplied" }
|
|
302
|
+
gem_name = "good-dog"
|
|
303
|
+
|
|
304
|
+
File.write(
|
|
305
|
+
"#{template_dir}/foobar.yml",
|
|
306
|
+
"name_validation:\n regex_validator: \"[unclosed\"\n"
|
|
307
|
+
)
|
|
308
|
+
File.write("#{template_dir}/README.md", "# Readme")
|
|
309
|
+
`git init #{template_dir}`
|
|
310
|
+
|
|
311
|
+
expect {
|
|
312
|
+
capture_stdout { capture_stderr { FoobarTemplates.generate_template(options, gem_name) } }
|
|
313
|
+
}.to raise_error(RuntimeError)
|
|
314
|
+
|
|
315
|
+
expect($captured_stderr).to include "invalid name_validation.regex_validator"
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
it "is a no-op when name_validation is omitted" do
|
|
319
|
+
template_dir = create_user_defined_template("testing", "template-user-supplied")
|
|
320
|
+
options = { bin: false, ext: false, coc: false, template: "template-user-supplied" }
|
|
321
|
+
gem_name = "good-dog"
|
|
322
|
+
|
|
323
|
+
File.write("#{template_dir}/foobar.yml", "category: testing\n")
|
|
324
|
+
File.write("#{template_dir}/README.md", "# Readme")
|
|
325
|
+
`git init #{template_dir}`
|
|
326
|
+
|
|
327
|
+
capture_stdout { FoobarTemplates.generate_template(options, gem_name) }
|
|
328
|
+
|
|
329
|
+
expect(File).to exist("#{@dst_dir}/#{gem_name}/README.md")
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
it "has a test proving every interpolation in one file" do
|
|
334
|
+
expected_manifest = File.read("#{ENV['SPEC_DATA_DIR']}/variable_manifest_test.rb")
|
|
335
|
+
options = { bin: false, ext: false, coc: false, template: "test_template" }
|
|
336
|
+
gem_name = "good-dog"
|
|
337
|
+
|
|
338
|
+
capture_stdout { FoobarTemplates.generate_template(options, gem_name) }
|
|
339
|
+
|
|
340
|
+
resulting_manifest = File.read("#{@dst_dir}/#{gem_name}/#{gem_name}.rb")
|
|
341
|
+
expect(resulting_manifest).to eq expected_manifest
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
it "has config[:unprefixed_name] removing purpose-tool- from name" do
|
|
345
|
+
options = { bin: false, ext: false, coc: false, template: "test_template" }
|
|
346
|
+
gem_name = "tool-go-good-dog"
|
|
347
|
+
my_gem = FoobarTemplates::CLI::TemplateGenerator.new(options, gem_name)
|
|
348
|
+
|
|
349
|
+
config = my_gem.build_interpolation_config
|
|
350
|
+
|
|
351
|
+
expect(config[:unprefixed_name]).to eq "good-dog"
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
describe "domain config prompting" do
|
|
355
|
+
it "prompts for missing domain values when template requires them" do
|
|
356
|
+
template_dir = create_user_defined_template("testing", "template-needs-registry")
|
|
357
|
+
File.write("#{template_dir}/README.md", "Deploy to FOO_REGISTRY_DOMAIN please")
|
|
358
|
+
`git init #{template_dir}`
|
|
359
|
+
|
|
360
|
+
# Remove registry_domain from config so it triggers a prompt
|
|
361
|
+
config_path = "#{@mocked_home}/.foobar/config"
|
|
362
|
+
config_data = YAML.load_file(config_path)
|
|
363
|
+
config_data.delete('registry_domain')
|
|
364
|
+
File.write(config_path, "# Comments made to this file will not be preserved\n#{YAML.dump(config_data)}")
|
|
365
|
+
|
|
366
|
+
options = { bin: false, ext: false, coc: false, template: "template-needs-registry" }
|
|
367
|
+
gem_name = "prompted-app"
|
|
368
|
+
|
|
369
|
+
# Simulate user typing "my-prompted-registry.io"
|
|
370
|
+
allow($stdin).to receive(:gets).and_return("my-prompted-registry.io\n")
|
|
371
|
+
|
|
372
|
+
output = capture_stdout { FoobarTemplates.generate_template(options, gem_name) }
|
|
373
|
+
|
|
374
|
+
expect(output).to include "registry-domain"
|
|
375
|
+
expect(output).to include "~/.foobar/config"
|
|
376
|
+
|
|
377
|
+
# Verify value was saved to config
|
|
378
|
+
saved_config = YAML.load_file(config_path)
|
|
379
|
+
expect(saved_config['registry_domain']).to eq "my-prompted-registry.io"
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
it "does not prompt when domain values are already configured" do
|
|
383
|
+
template_dir = create_user_defined_template("testing", "template-has-domains")
|
|
384
|
+
File.write("#{template_dir}/README.md", "FOO_REGISTRY_DOMAIN and FOO_K8S_DOMAIN")
|
|
385
|
+
`git init #{template_dir}`
|
|
386
|
+
|
|
387
|
+
options = { bin: false, ext: false, coc: false, template: "template-has-domains" }
|
|
388
|
+
gem_name = "no-prompt-app"
|
|
389
|
+
|
|
390
|
+
# $stdin.gets should NOT be called
|
|
391
|
+
expect($stdin).not_to receive(:gets)
|
|
392
|
+
|
|
393
|
+
capture_stdout { FoobarTemplates.generate_template(options, gem_name) }
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
it "does not prompt for templates without domain placeholders" do
|
|
397
|
+
template_dir = create_user_defined_template("testing", "template-simple")
|
|
398
|
+
File.write("#{template_dir}/README.md", "Just a simple template with foo-bar name")
|
|
399
|
+
`git init #{template_dir}`
|
|
400
|
+
|
|
401
|
+
options = { bin: false, ext: false, coc: false, template: "template-simple" }
|
|
402
|
+
gem_name = "simple-app"
|
|
403
|
+
|
|
404
|
+
expect($stdin).not_to receive(:gets)
|
|
405
|
+
|
|
406
|
+
capture_stdout { FoobarTemplates.generate_template(options, gem_name) }
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
it "defaults repo_domain to github.com when user enters empty string" do
|
|
410
|
+
template_dir = create_user_defined_template("testing", "template-needs-repo")
|
|
411
|
+
File.write("#{template_dir}/README.md", "Clone from FOO_GIT_REPO_URL")
|
|
412
|
+
`git init #{template_dir}`
|
|
413
|
+
|
|
414
|
+
config_path = "#{@mocked_home}/.foobar/config"
|
|
415
|
+
config_data = YAML.load_file(config_path)
|
|
416
|
+
config_data.delete('repo_domain')
|
|
417
|
+
File.write(config_path, "# Comments made to this file will not be preserved\n#{YAML.dump(config_data)}")
|
|
418
|
+
|
|
419
|
+
options = { bin: false, ext: false, coc: false, template: "template-needs-repo" }
|
|
420
|
+
gem_name = "default-repo-app"
|
|
421
|
+
|
|
422
|
+
allow($stdin).to receive(:gets).and_return("\n")
|
|
423
|
+
|
|
424
|
+
capture_stdout { FoobarTemplates.generate_template(options, gem_name) }
|
|
425
|
+
|
|
426
|
+
saved_config = YAML.load_file(config_path)
|
|
427
|
+
expect(saved_config['repo_domain']).to eq "github.com"
|
|
428
|
+
end
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
describe "git init behavior" do
|
|
432
|
+
it "skips git init when generating inside an existing git repo" do
|
|
433
|
+
# Initialize a git repo in the destination directory
|
|
434
|
+
`git init #{@dst_dir}`
|
|
435
|
+
|
|
436
|
+
template_dir = create_user_defined_template("testing", "template-git-test")
|
|
437
|
+
File.write("#{template_dir}/README.md", "Hello foo-bar")
|
|
438
|
+
`git init #{template_dir}`
|
|
439
|
+
|
|
440
|
+
options = { bin: false, ext: false, coc: false, template: "template-git-test" }
|
|
441
|
+
gem_name = "git-skip-app"
|
|
442
|
+
|
|
443
|
+
capture_stdout { FoobarTemplates.generate_template(options, gem_name) }
|
|
444
|
+
|
|
445
|
+
# The generated project should NOT have its own .git directory
|
|
446
|
+
expect(File).not_to exist("#{@dst_dir}/#{gem_name}/.git")
|
|
447
|
+
# But the files should still exist
|
|
448
|
+
expect(File).to exist("#{@dst_dir}/#{gem_name}/README.md")
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
it "runs git init when generating outside a git repo" do
|
|
452
|
+
template_dir = create_user_defined_template("testing", "template-git-test2")
|
|
453
|
+
File.write("#{template_dir}/README.md", "Hello foo-bar")
|
|
454
|
+
`git init #{template_dir}`
|
|
455
|
+
|
|
456
|
+
options = { bin: false, ext: false, coc: false, template: "template-git-test2" }
|
|
457
|
+
gem_name = "git-init-app"
|
|
458
|
+
|
|
459
|
+
capture_stdout { FoobarTemplates.generate_template(options, gem_name) }
|
|
460
|
+
|
|
461
|
+
# The generated project SHOULD have its own .git directory
|
|
462
|
+
expect(File).to exist("#{@dst_dir}/#{gem_name}/.git")
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
it "always runs git init when always_perform_git_init is true" do
|
|
466
|
+
# Initialize a git repo in the destination directory
|
|
467
|
+
`git init #{@dst_dir}`
|
|
468
|
+
|
|
469
|
+
# Set always_perform_git_init to true in config
|
|
470
|
+
config_path = "#{@mocked_home}/.foobar/config"
|
|
471
|
+
config_data = YAML.load_file(config_path)
|
|
472
|
+
config_data['always_perform_git_init'] = true
|
|
473
|
+
File.write(config_path, "# Comments made to this file will not be preserved\n#{YAML.dump(config_data)}")
|
|
474
|
+
|
|
475
|
+
template_dir = create_user_defined_template("testing", "template-git-test3")
|
|
476
|
+
File.write("#{template_dir}/README.md", "Hello foo-bar")
|
|
477
|
+
`git init #{template_dir}`
|
|
478
|
+
|
|
479
|
+
options = { bin: false, ext: false, coc: false, template: "template-git-test3" }
|
|
480
|
+
gem_name = "git-force-app"
|
|
481
|
+
|
|
482
|
+
capture_stdout { FoobarTemplates.generate_template(options, gem_name) }
|
|
483
|
+
|
|
484
|
+
# The generated project SHOULD have its own .git directory even though parent is a repo
|
|
485
|
+
expect(File).to exist("#{@dst_dir}/#{gem_name}/.git")
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
describe "install public templates" do
|
|
490
|
+
before :each do
|
|
491
|
+
setup_mock_web_template
|
|
492
|
+
end
|
|
493
|
+
after :each do
|
|
494
|
+
remove_mock_web_template
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
it "can download public templates from the web" do
|
|
498
|
+
capture_stdout { FoobarTemplates.install_public_templates }
|
|
499
|
+
expect(File).to exist("#{ENV['HOME']}/.foobar/templates/template-arduino/README.md")
|
|
500
|
+
end
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
describe "create personal templates" do
|
|
504
|
+
let(:github_name) { "Test" } # set by reset_test_env via `git config --global user.name "Test"`
|
|
505
|
+
let(:local_dir) { "#{ENV['HOME']}/.foobar/templates/templates-#{github_name}" }
|
|
506
|
+
|
|
507
|
+
before :each do
|
|
508
|
+
# Default: no remote — skip network calls.
|
|
509
|
+
allow(FoobarTemplates).to receive(:remote_repo_exists?).and_return(false)
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
it "errors when repo_domain is not configured" do
|
|
513
|
+
config_path = "#{ENV['HOME']}/.foobar/config"
|
|
514
|
+
data = YAML.load_file(config_path)
|
|
515
|
+
data['repo_domain'] = nil
|
|
516
|
+
File.write(config_path, "# Comments made to this file will not be preserved\n#{YAML.dump(data)}")
|
|
517
|
+
|
|
518
|
+
out = StringIO.new
|
|
519
|
+
FoobarTemplates.setup_personal_templates(input: StringIO.new(""), output: out)
|
|
520
|
+
|
|
521
|
+
expect(out.string).to include("`repo_domain` is not set")
|
|
522
|
+
expect(File).not_to exist(local_dir)
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
it "creates the mono-repo with foobar.yml and README when no remote exists" do
|
|
526
|
+
out = StringIO.new
|
|
527
|
+
FoobarTemplates.setup_personal_templates(input: StringIO.new(""), output: out)
|
|
528
|
+
|
|
529
|
+
expect(File).to exist("#{local_dir}/foobar.yml")
|
|
530
|
+
expect(File.read("#{local_dir}/foobar.yml")).to include("monorepo: true")
|
|
531
|
+
|
|
532
|
+
expect(File).to exist("#{local_dir}/README.md")
|
|
533
|
+
expect(File.read("#{local_dir}/README.md")).to include("https://github.com/thenotary/foobar_templates")
|
|
534
|
+
|
|
535
|
+
expect(File).to exist("#{local_dir}/.git")
|
|
536
|
+
expect(out.string).to include("Created personal templates mono-repo")
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
it "refuses to overwrite an existing local templates directory" do
|
|
540
|
+
FileUtils.mkdir_p(local_dir)
|
|
541
|
+
|
|
542
|
+
out = StringIO.new
|
|
543
|
+
FoobarTemplates.setup_personal_templates(input: StringIO.new(""), output: out)
|
|
544
|
+
|
|
545
|
+
expect(out.string).to include("The template directory already exists, #{local_dir}")
|
|
546
|
+
expect(File).not_to exist("#{local_dir}/foobar.yml")
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
it "prompts to clone when the remote repo exists and aborts on 'n'" do
|
|
550
|
+
allow(FoobarTemplates::CLI::SetupPersonalTemplatesRepo).to receive(:remote_repo_exists?).and_return(true)
|
|
551
|
+
|
|
552
|
+
out = StringIO.new
|
|
553
|
+
FoobarTemplates.setup_personal_templates(input: StringIO.new("n\n"), output: out)
|
|
554
|
+
|
|
555
|
+
expect(out.string).to include("clone it down? [Y/n]")
|
|
556
|
+
expect(out.string).to include("Aborted")
|
|
557
|
+
expect(File).not_to exist(local_dir)
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
it "prompts for github name when git user.name is unset" do
|
|
561
|
+
`git config --global --unset user.name`
|
|
562
|
+
|
|
563
|
+
out = StringIO.new
|
|
564
|
+
FoobarTemplates.setup_personal_templates(input: StringIO.new("octocat\n"), output: out)
|
|
565
|
+
|
|
566
|
+
expect(out.string).to include("Enter your GitHub user name")
|
|
567
|
+
expect(File).to exist("#{ENV['HOME']}/.foobar/templates/templates-octocat/foobar.yml")
|
|
568
|
+
ensure
|
|
569
|
+
`git config --global user.name "Test"`
|
|
570
|
+
end
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
|
2
|
+
$test_env = true
|
|
3
|
+
require 'foobar_templates'
|
|
4
|
+
require 'foobar_templates/cli/template_generator'
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
require 'yaml'
|
|
7
|
+
require 'pry'
|
|
8
|
+
|
|
9
|
+
# Mock our home directory
|
|
10
|
+
ENV['HOME'] = "/tmp/foobar_templates_mock_home"
|
|
11
|
+
ENV['SPEC_DATA_DIR'] = File.expand_path("./spec/data") # I fell into this from sloppy chdir handling, bad CLI/ API isolation.
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def setup_mock_web_template
|
|
15
|
+
mock_repo = "#{ENV['HOME']}/template-arduino.git"
|
|
16
|
+
FileUtils.mkdir(mock_repo)
|
|
17
|
+
FileUtils.touch("#{mock_repo}/README.md")
|
|
18
|
+
|
|
19
|
+
`cd "#{mock_repo}" && git init && git add . && git commit -m "haxing"`
|
|
20
|
+
|
|
21
|
+
# Update the config file so install_public_templates finds our mock repo
|
|
22
|
+
config_path = "#{ENV['HOME']}/.foobar/config"
|
|
23
|
+
config_data = YAML.load_file(config_path)
|
|
24
|
+
config_data['public_templates'] = mock_repo
|
|
25
|
+
File.write(config_path, "# Comments made to this file will not be preserved\n#{YAML.dump(config_data)}")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def remove_mock_web_template
|
|
29
|
+
FileUtils.rm_rf("#{ENV['HOME']}/template-arduino.git")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def create_user_defined_template(category = nil, template_name = "empty_template")
|
|
33
|
+
new_template_dir = "#{@template_root}/#{template_name}"
|
|
34
|
+
|
|
35
|
+
# Creates the gem template (empty folder)
|
|
36
|
+
FileUtils.mkdir_p new_template_dir
|
|
37
|
+
|
|
38
|
+
# Writes the category
|
|
39
|
+
File.open("#{new_template_dir}/foobar.yml", "w+") do |f|
|
|
40
|
+
f.puts "category: #{category}" unless category.nil?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
new_template_dir
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def create_monorepo_template(path_segments, monorepo: true, category: nil)
|
|
47
|
+
template_dir = File.join(@template_root, *path_segments)
|
|
48
|
+
FileUtils.mkdir_p(template_dir)
|
|
49
|
+
|
|
50
|
+
config = []
|
|
51
|
+
config << "monorepo: true" if monorepo
|
|
52
|
+
config << "category: #{category}" unless category.nil?
|
|
53
|
+
File.write("#{template_dir}/foobar.yml", config.join("\n"))
|
|
54
|
+
|
|
55
|
+
template_dir
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def reset_test_env
|
|
60
|
+
FileUtils.rm_rf @mocked_home
|
|
61
|
+
FileUtils.rm_rf @dst_dir
|
|
62
|
+
|
|
63
|
+
FileUtils.mkdir_p @dst_dir
|
|
64
|
+
FileUtils.mkdir_p @template_root
|
|
65
|
+
FileUtils.cd @dst_dir
|
|
66
|
+
auth_settings = ' git config --global user.email "you@example.com"'
|
|
67
|
+
auth_settings += ' && git config --global user.name "Test"'
|
|
68
|
+
|
|
69
|
+
`git config --global init.defaultBranch main && #{auth_settings}`
|
|
70
|
+
|
|
71
|
+
# Write domain config to ~/.foobar/config instead of git config
|
|
72
|
+
config_data = {
|
|
73
|
+
'default_template' => 'cli_gem',
|
|
74
|
+
'public_templates' => '',
|
|
75
|
+
'registry_domain' => 'my-registry.example.com',
|
|
76
|
+
'k8s_domain' => 'my-k8s.example.com',
|
|
77
|
+
'repo_domain' => 'github.com',
|
|
78
|
+
}
|
|
79
|
+
FileUtils.mkdir_p "#{@mocked_home}/.foobar"
|
|
80
|
+
File.write("#{@mocked_home}/.foobar/config", "# Comments made to this file will not be preserved\n#{YAML.dump(config_data)}")
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# squelch stdout
|
|
84
|
+
# usage capture_stdout { a_method(a_signal.new, a_model, a_helper) }
|
|
85
|
+
def capture_stdout(&block)
|
|
86
|
+
original_stdout = $stdout
|
|
87
|
+
$stdout = fake = StringIO.new
|
|
88
|
+
begin
|
|
89
|
+
yield
|
|
90
|
+
ensure
|
|
91
|
+
$stdout = original_stdout
|
|
92
|
+
end
|
|
93
|
+
fake.string
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def capture_stderr(&block)
|
|
97
|
+
original_stderr = $stderr
|
|
98
|
+
$stderr = fake = StringIO.new
|
|
99
|
+
begin
|
|
100
|
+
yield
|
|
101
|
+
ensure
|
|
102
|
+
$stderr = original_stderr
|
|
103
|
+
$captured_stderr = fake.string
|
|
104
|
+
end
|
|
105
|
+
fake.string
|
|
106
|
+
end
|