app_archetype 1.2.8 → 1.3.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 +4 -4
- data/Gemfile.lock +36 -9
- data/README.md +150 -28
- data/app_archetype.gemspec +3 -0
- data/bin/app_archetype +20 -0
- data/bin/archetype +1 -1
- data/lib/app_archetype/cli.rb +171 -139
- data/lib/app_archetype/commands/delete_template.rb +58 -0
- data/lib/app_archetype/commands/find_templates.rb +66 -0
- data/lib/app_archetype/commands/list_templates.rb +49 -0
- data/lib/app_archetype/commands/new_template.rb +42 -0
- data/lib/app_archetype/commands/open_manifest.rb +48 -0
- data/lib/app_archetype/commands/print_path.rb +20 -0
- data/lib/app_archetype/commands/print_template_variables.rb +67 -0
- data/lib/app_archetype/commands/print_version.rb +19 -0
- data/lib/app_archetype/commands/render_template.rb +178 -0
- data/lib/app_archetype/commands.rb +13 -0
- data/lib/app_archetype/generators.rb +1 -1
- data/lib/app_archetype/template_manager.rb +9 -0
- data/lib/app_archetype/version.rb +1 -1
- data/lib/app_archetype.rb +40 -23
- data/scripts/create_new_command +32 -0
- data/scripts/generators/command/manifest.json +15 -0
- data/scripts/generators/command/template/lib/app_archetype/commands/{{command_name.snake_case}}.rb.hbs +17 -0
- data/spec/app_archetype/cli/presenters_spec.rb +99 -99
- data/spec/app_archetype/cli/prompts_spec.rb +291 -291
- data/spec/app_archetype/cli_spec.rb +427 -65
- data/spec/app_archetype/commands/delete_template_spec.rb +132 -0
- data/spec/app_archetype/commands/find_templates_spec.rb +130 -0
- data/spec/app_archetype/commands/list_templates_spec.rb +55 -0
- data/spec/app_archetype/commands/new_template_spec.rb +84 -0
- data/spec/app_archetype/commands/open_manifest_spec.rb +113 -0
- data/spec/app_archetype/commands/print_path_spec.rb +22 -0
- data/spec/app_archetype/commands/print_template_variables_spec.rb +158 -0
- data/spec/app_archetype/commands/print_version_spec.rb +21 -0
- data/spec/app_archetype/commands/render_template_spec.rb +479 -0
- data/spec/app_archetype/generators_spec.rb +1 -1
- data/spec/app_archetype/template_manager_spec.rb +32 -0
- data/spec/app_archetype_spec.rb +65 -0
- metadata +79 -4
- data/lib/app_archetype/cli/presenters.rb +0 -106
- data/lib/app_archetype/cli/prompts.rb +0 -152
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'tty-prompt'
|
2
|
+
|
3
|
+
module AppArchetype
|
4
|
+
module Commands
|
5
|
+
# Prompts user for variable values and renders template to disk
|
6
|
+
class RenderTemplate
|
7
|
+
def initialize(manager, destination_path, options = Hashie::Mash.new)
|
8
|
+
@manager = manager
|
9
|
+
@destination_path = destination_path
|
10
|
+
@options = options
|
11
|
+
@prompt = TTY::Prompt.new
|
12
|
+
end
|
13
|
+
|
14
|
+
##
|
15
|
+
# Renders a template with instructions described
|
16
|
+
# in the manifest.
|
17
|
+
#
|
18
|
+
# First it looks to the options to determine the
|
19
|
+
# name of the manifest. If one is not provided
|
20
|
+
# then the user will be prompted to choose a manifest
|
21
|
+
# from the list.
|
22
|
+
#
|
23
|
+
# The manager will then attempt to find the manifest.
|
24
|
+
# if one is not found then a RuntimeError will be raised.
|
25
|
+
#
|
26
|
+
# Once the manifest is loaded the template will be loaded
|
27
|
+
# into memory.
|
28
|
+
#
|
29
|
+
# Then the variables specified in the manifest are
|
30
|
+
# resolved. This involves the command prompting
|
31
|
+
# for values.
|
32
|
+
#
|
33
|
+
# A plan can then be constructed with the template and
|
34
|
+
# variables, this plan is then devised and executed.
|
35
|
+
#
|
36
|
+
# When the render is successful a success message
|
37
|
+
# is sent to STDOUT to confirm the operation was
|
38
|
+
# successful.
|
39
|
+
#
|
40
|
+
def run
|
41
|
+
name = @options.name
|
42
|
+
name ||= @prompt.select('Please choose manifest', @manager.manifest_names)
|
43
|
+
|
44
|
+
manifest = @manager.find_by_name(name)
|
45
|
+
|
46
|
+
unless manifest
|
47
|
+
puts "✖ No template with name `#{name}` found."
|
48
|
+
return
|
49
|
+
end
|
50
|
+
|
51
|
+
template = manifest.template
|
52
|
+
template.load
|
53
|
+
|
54
|
+
resolve_variables(manifest)
|
55
|
+
render_template(
|
56
|
+
manifest,
|
57
|
+
template,
|
58
|
+
overwrite: @options.overwrite
|
59
|
+
)
|
60
|
+
|
61
|
+
puts("✔ Rendered #{name} to #{@destination_path}")
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# Prompts user for values for each variable
|
66
|
+
# specified in the given manifest. And then
|
67
|
+
# sets the value of those variables to the
|
68
|
+
# answers to the prompts.
|
69
|
+
#
|
70
|
+
# @param[AppArchetype::Template::Manifest] manifest
|
71
|
+
#
|
72
|
+
def resolve_variables(manifest)
|
73
|
+
manifest.variables.all.each do |var|
|
74
|
+
value = variable_prompt_for(var)
|
75
|
+
var.set!(value)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Builds plan to render template and executes
|
81
|
+
# it - essentially rendering the template to
|
82
|
+
# the output location
|
83
|
+
#
|
84
|
+
# @param [AppArchetype::Template::Manifest] manifest
|
85
|
+
# @param [AppArchetype::Template] template
|
86
|
+
# @param [Boolean] overwrite
|
87
|
+
#
|
88
|
+
def render_template(
|
89
|
+
manifest,
|
90
|
+
template,
|
91
|
+
overwrite: false
|
92
|
+
)
|
93
|
+
plan = AppArchetype::Template::Plan.new(
|
94
|
+
template,
|
95
|
+
manifest.variables,
|
96
|
+
destination_path: @destination_path,
|
97
|
+
overwrite: overwrite
|
98
|
+
)
|
99
|
+
|
100
|
+
plan.devise
|
101
|
+
plan.execute
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# Resolver for a given variable
|
106
|
+
#
|
107
|
+
# First, it will set the value if the value is set in
|
108
|
+
# the manifest.
|
109
|
+
#
|
110
|
+
# Otherwise it will call a function that prompts
|
111
|
+
# a user for input depending on type.
|
112
|
+
#
|
113
|
+
# By default it will call the string variable prompt
|
114
|
+
#
|
115
|
+
# @param [AppArchetype::Template::Variable] var
|
116
|
+
#
|
117
|
+
# @return [Object]
|
118
|
+
#
|
119
|
+
def variable_prompt_for(var)
|
120
|
+
return var.value if var.value?
|
121
|
+
return boolean_variable_prompt_for(var) if var.type == 'boolean'
|
122
|
+
return integer_variable_prompt_for(var) if var.type == 'integer'
|
123
|
+
|
124
|
+
string_variable_prompt_for(var)
|
125
|
+
end
|
126
|
+
|
127
|
+
##
|
128
|
+
# Prompts and then asks for boolean input for
|
129
|
+
# a boolean variable
|
130
|
+
#
|
131
|
+
# @param [AppArchetype::Template::Variable] var
|
132
|
+
#
|
133
|
+
# @return [Boolean]
|
134
|
+
#
|
135
|
+
def boolean_variable_prompt_for(var)
|
136
|
+
puts "• #{var.name} (#{var.description})"
|
137
|
+
|
138
|
+
@prompt.yes?(
|
139
|
+
"Enter value for `#{var.name}` variable:",
|
140
|
+
default: var.default
|
141
|
+
)
|
142
|
+
end
|
143
|
+
|
144
|
+
##
|
145
|
+
# Prompts and then asks for integer input for
|
146
|
+
# a integer variable
|
147
|
+
#
|
148
|
+
# @param [AppArchetype::Template::Variable] var
|
149
|
+
#
|
150
|
+
# @return [Integer]
|
151
|
+
#
|
152
|
+
def integer_variable_prompt_for(var)
|
153
|
+
puts "• #{var.name} (#{var.description})"
|
154
|
+
|
155
|
+
@prompt.ask("Enter value for `#{var.name}` variable:",
|
156
|
+
convert: :int,
|
157
|
+
default: var.default)
|
158
|
+
end
|
159
|
+
|
160
|
+
##
|
161
|
+
# Prompts and then asks for string input for
|
162
|
+
# a string variable
|
163
|
+
#
|
164
|
+
# @param [AppArchetype::Template::Variable] var
|
165
|
+
#
|
166
|
+
# @return [String]
|
167
|
+
#
|
168
|
+
def string_variable_prompt_for(var)
|
169
|
+
puts "• #{var.name} (#{var.description})"
|
170
|
+
|
171
|
+
@prompt.ask(
|
172
|
+
"Enter value for `#{var.name}` variable:",
|
173
|
+
default: var.default
|
174
|
+
)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -60,7 +60,7 @@ module AppArchetype
|
|
60
60
|
# @param [String] path
|
61
61
|
#
|
62
62
|
def render_empty_template(name, path)
|
63
|
-
template_path = File.join(path,
|
63
|
+
template_path = File.join(path, 'template')
|
64
64
|
manifest_path = File.join(path, 'manifest.json')
|
65
65
|
readme_path = File.join(path, 'README.md')
|
66
66
|
|
data/lib/app_archetype.rb
CHANGED
@@ -7,41 +7,58 @@ require 'app_archetype/template_manager'
|
|
7
7
|
require 'app_archetype/renderer'
|
8
8
|
require 'app_archetype/generators'
|
9
9
|
|
10
|
-
require 'app_archetype/cli/prompts'
|
11
|
-
|
12
10
|
require 'app_archetype/version'
|
11
|
+
require_relative './app_archetype/commands'
|
13
12
|
|
14
13
|
# AppArchetype is the namespace for app_archetype
|
15
14
|
module AppArchetype
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
##
|
16
|
+
# Self contained template render method
|
17
|
+
#
|
18
|
+
# Takes collection directory and template name to
|
19
|
+
# load a new manager and find the desired template
|
20
|
+
#
|
21
|
+
# Then executes a render template command with the
|
22
|
+
# found template
|
23
|
+
#
|
24
|
+
# Returns the manifest rendered. Target can optionally
|
25
|
+
# be set to overwrite
|
26
|
+
#
|
27
|
+
# This method is to be used for self contained rendering#
|
28
|
+
# scripts.
|
29
|
+
#
|
30
|
+
# @param [String] collection_dir
|
31
|
+
# @param [String] template_name
|
32
|
+
# @param [String] destination_path
|
33
|
+
# @param [Boolean] overwrite
|
34
|
+
#
|
35
|
+
# @return [AppArchetype::Template::Manifest]
|
36
|
+
#
|
37
|
+
def self.render_template(
|
38
|
+
collection_dir: ENV.fetch('ARCHETYPE_TEMPLATE_DIR'),
|
39
|
+
template_name: '',
|
40
|
+
destination_path: '',
|
41
|
+
overwrite: false
|
22
42
|
)
|
23
|
-
|
43
|
+
manager = AppArchetype::TemplateManager.new(collection_dir)
|
44
|
+
manager.load
|
24
45
|
|
25
|
-
manifest =
|
46
|
+
manifest = manager.find_by_name(template_name)
|
26
47
|
|
27
48
|
template = manifest.template
|
28
49
|
template.load
|
29
50
|
|
30
|
-
|
31
|
-
|
32
|
-
manifest.variables.all.each do |var|
|
33
|
-
value = AppArchetype::CLI::Prompts.variable_prompt_for(var)
|
34
|
-
var.set!(value)
|
35
|
-
end
|
36
|
-
|
37
|
-
plan = AppArchetype::Template::Plan.new(
|
38
|
-
template,
|
39
|
-
manifest.variables,
|
40
|
-
destination_path: destination_path,
|
51
|
+
options = Hashie::Mash.new(
|
52
|
+
name: template_name,
|
41
53
|
overwrite: overwrite
|
42
54
|
)
|
43
55
|
|
44
|
-
|
45
|
-
|
56
|
+
command = AppArchetype::Commands::RenderTemplate.new(
|
57
|
+
manager, destination_path, options
|
58
|
+
)
|
59
|
+
|
60
|
+
command.run
|
61
|
+
|
62
|
+
manifest
|
46
63
|
end
|
47
64
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative '../lib/app_archetype'
|
4
|
+
|
5
|
+
puts 'CREATE NEW COMMAND'
|
6
|
+
|
7
|
+
manifest = AppArchetype.render_template(
|
8
|
+
collection_dir: File.join(__dir__, 'generators'),
|
9
|
+
template_name: 'command',
|
10
|
+
destination_path: File.expand_path(File.join(__dir__, '..'))
|
11
|
+
)
|
12
|
+
|
13
|
+
command_name = manifest.variables.get('command_name').value
|
14
|
+
|
15
|
+
next_steps = <<~TEXT
|
16
|
+
✔ Command created
|
17
|
+
|
18
|
+
TODO:
|
19
|
+
|
20
|
+
Add the following to cli.rb within AppArchetype::CLI:
|
21
|
+
|
22
|
+
```
|
23
|
+
desc '#{command_name.snake_case}', 'TODO: description'
|
24
|
+
|
25
|
+
def #{command_name.snake_case}
|
26
|
+
cmd = AppArchetype::Commands::#{command_name.camel_case}.new(options)
|
27
|
+
cmd.run
|
28
|
+
end
|
29
|
+
```
|
30
|
+
TEXT
|
31
|
+
|
32
|
+
puts next_steps
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'tty-prompt'
|
2
|
+
|
3
|
+
module AppArchetype
|
4
|
+
module Commands
|
5
|
+
class {{command_name.camel_case}}
|
6
|
+
def initialize(manager, options)
|
7
|
+
@manager = manager
|
8
|
+
@options = options
|
9
|
+
@prompt = TTY::Prompt.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
puts('✔ {{command_name.snake_case}} complete')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,99 +1,99 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
RSpec.
|
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
|
-
end
|
1
|
+
# require 'spec_helper'
|
2
|
+
|
3
|
+
# RSpec.xdescribe AppArchetype::CLI::Presenters do
|
4
|
+
# describe '.manifest_list' do
|
5
|
+
# let(:manifest) do
|
6
|
+
# double(
|
7
|
+
# AppArchetype::Template::Manifest,
|
8
|
+
# name: 'test_manifest',
|
9
|
+
# version: '1.0.0'
|
10
|
+
# )
|
11
|
+
# end
|
12
|
+
# let(:manifest_list_row) { ['test_manifest', '1.0.0'] }
|
13
|
+
|
14
|
+
# let(:presenter) { double(CliFormat::Presenter) }
|
15
|
+
# let(:manifests) { [manifest, manifest] }
|
16
|
+
|
17
|
+
# before do
|
18
|
+
# allow(presenter).to receive(:show)
|
19
|
+
# allow(subject).to receive(:table).and_return(presenter)
|
20
|
+
|
21
|
+
# described_class.manifest_list(manifests)
|
22
|
+
# end
|
23
|
+
|
24
|
+
# it 'builds table presenter' do
|
25
|
+
# expect(subject).to have_received(:table).with(
|
26
|
+
# header: AppArchetype::CLI::Presenters::RESULT_HEADER,
|
27
|
+
# data: [manifest_list_row, manifest_list_row]
|
28
|
+
# )
|
29
|
+
# end
|
30
|
+
|
31
|
+
# it 'shows table' do
|
32
|
+
# expect(presenter).to have_received(:show)
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
|
36
|
+
# describe '.variable_list' do
|
37
|
+
# let(:variable) do
|
38
|
+
# double(
|
39
|
+
# AppArchetype::Template::Variable,
|
40
|
+
# name: 'foo',
|
41
|
+
# description: 'a foo',
|
42
|
+
# default: 'yolo',
|
43
|
+
# value: 'bar'
|
44
|
+
# )
|
45
|
+
# end
|
46
|
+
# let(:variable_row) { ['foo', 'a foo', 'yolo'] }
|
47
|
+
|
48
|
+
# let(:presenter) { double(CliFormat::Presenter) }
|
49
|
+
# let(:variables) { [variable, variable] }
|
50
|
+
|
51
|
+
# before do
|
52
|
+
# allow(presenter).to receive(:show)
|
53
|
+
# allow(subject).to receive(:table).and_return(presenter)
|
54
|
+
|
55
|
+
# described_class.variable_list(variables)
|
56
|
+
# end
|
57
|
+
|
58
|
+
# it 'builds table presenter' do
|
59
|
+
# expect(subject).to have_received(:table).with(
|
60
|
+
# header: AppArchetype::CLI::Presenters::VARIABLE_HEADER,
|
61
|
+
# data: [variable_row, variable_row]
|
62
|
+
# )
|
63
|
+
# end
|
64
|
+
|
65
|
+
# it 'shows table' do
|
66
|
+
# expect(presenter).to have_received(:show)
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
|
70
|
+
# describe '.validation_results' do
|
71
|
+
# let(:results) do
|
72
|
+
# [
|
73
|
+
# 'something went wrong',
|
74
|
+
# 'something went wrong'
|
75
|
+
# ]
|
76
|
+
# end
|
77
|
+
|
78
|
+
# let(:result_row) { ['something went wrong'] }
|
79
|
+
# let(:presenter) { double(CliFormat::Presenter) }
|
80
|
+
|
81
|
+
# before do
|
82
|
+
# allow(presenter).to receive(:show)
|
83
|
+
# allow(subject).to receive(:table).and_return(presenter)
|
84
|
+
|
85
|
+
# described_class.validation_result(results)
|
86
|
+
# end
|
87
|
+
|
88
|
+
# it 'builds table presenter' do
|
89
|
+
# expect(subject).to have_received(:table).with(
|
90
|
+
# header: AppArchetype::CLI::Presenters::VALIDATION_HEADER,
|
91
|
+
# data: [result_row, result_row]
|
92
|
+
# )
|
93
|
+
# end
|
94
|
+
|
95
|
+
# it 'shows table' do
|
96
|
+
# expect(presenter).to have_received(:show)
|
97
|
+
# end
|
98
|
+
# end
|
99
|
+
# end
|