new 0.1.1 → 1.0.9
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 +13 -5
- data/bin/new +0 -2
- data/lib/new.rb +125 -52
- data/lib/new/cli.rb +514 -67
- data/lib/new/source.rb +110 -0
- data/lib/new/task.rb +67 -24
- data/lib/new/validation.rb +191 -0
- metadata +75 -132
- data/.gitignore +0 -6
- data/.new +0 -23
- data/.rspec +0 -2
- data/Gemfile +0 -16
- data/Gemfile.lock +0 -82
- data/Guardfile +0 -16
- data/LICENSE.txt +0 -22
- data/README.md +0 -128
- data/lib/new/core.rb +0 -7
- data/lib/new/dsl.rb +0 -42
- data/lib/new/interpolate.rb +0 -106
- data/lib/new/project.rb +0 -34
- data/lib/new/template.rb +0 -67
- data/lib/new/version.rb +0 -54
- data/spec/fixtures/custom/.new +0 -16
- data/spec/fixtures/custom/tasks/custom_bar_task/custom_bar_task.rb +0 -3
- data/spec/fixtures/custom/templates/custom_bar_template/.new +0 -3
- data/spec/fixtures/custom/templates/custom_bar_template/custom_bar.txt +0 -0
- data/spec/fixtures/project/.new +0 -4
- data/spec/fixtures/project/.new_cli_release_spec +0 -2
- data/spec/fixtures/tasks/custom_bar_task/custom_bar_task.rb +0 -1
- data/spec/fixtures/tasks/foo_task/Gemfile +0 -5
- data/spec/fixtures/tasks/foo_task/foo_task.rb +0 -7
- data/spec/fixtures/templates/custom_bar_template/.gitkeep +0 -0
- data/spec/fixtures/templates/foo_template/.new +0 -1
- data/spec/fixtures/templates/foo_template/[FOO.BAR].txt.erb +0 -1
- data/spec/fixtures/templates/foo_template/nested_[FOO.BAR]/foo.txt.erb +0 -1
- data/spec/lib/new/cli_spec.rb +0 -107
- data/spec/lib/new/interpolate_spec.rb +0 -43
- data/spec/lib/new/project_spec.rb +0 -33
- data/spec/lib/new/task_spec.rb +0 -39
- data/spec/lib/new/template_spec.rb +0 -59
- data/spec/lib/new/version_spec.rb +0 -26
- data/spec/lib/new_spec.rb +0 -19
- data/spec/spec_helper.rb +0 -46
- data/tasks/gem/.gemspec.erb +0 -4
- data/tasks/gem/README.md +0 -36
- data/tasks/gem/gem.rb +0 -170
- data/tasks/gem/gem_spec.rb +0 -138
- data/templates/js/.bowerrc +0 -3
- data/templates/js/.gitignore +0 -3
- data/templates/js/.new.erb +0 -11
- data/templates/js/CHANGELOG.md +0 -3
- data/templates/js/Gemfile +0 -2
- data/templates/js/Guardfile +0 -7
- data/templates/js/LICENSE-MIT.erb +0 -22
- data/templates/js/README.md.erb +0 -41
- data/templates/js/bower.json.erb +0 -11
- data/templates/js/demo/[PROJECT.FILENAME]_demo.coffee +0 -0
- data/templates/js/demo/[PROJECT.FILENAME]_demo.sass +0 -0
- data/templates/js/demo/index.html.erb +0 -12
- data/templates/js/lib/README.md +0 -2
- data/templates/js/package.json +0 -5
- data/templates/js/spec/[PROJECT.FILENAME]_spec.coffee.erb +0 -1
- data/templates/js/spec/[PROJECT.FILENAME]_spec.sass +0 -0
- data/templates/js/spec/index.html.erb +0 -35
- data/templates/js/src/[PROJECT.FILENAME].coffee.erb +0 -18
- data/templates/js/src/[PROJECT.FILENAME].sass +0 -0
- data/templates/js/testem.yml +0 -23
- data/templates/js/yuyi_menu +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZjNlNjUyMWY0NjY3ZjBjZThkZTM0MjQwODU1YTllYTNhNjYwZDBlZA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NmQ4NmQ4NTUwZWU3ZTAwNmFkZTJkMjUzOTYwN2Y0M2FjMDc2MzExZg==
|
5
7
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NmE3NjBmODFiNDMxODkzNTFmYTAzMjA5YTlhMzEwZWQ4NDU4MmI0MzhiOTJm
|
10
|
+
NzczOGVjOWY2Yzk2NzQ5NTI5YThhMGJkZDBiN2U3MzJkNTA4MDFjYTQ1N2Fk
|
11
|
+
NjM2MzZkZDFhYTUwZDQ3MzFiY2RlZjZjMGQwZmZhZGE4MDlmM2Q=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MzlhMWQ4OWFjYmNhMTQ5YzYxMWNiM2I4OGVlNDA3ZmRkNzViMzM5ODU4ZTYz
|
14
|
+
MTU0NmIyMGU3YTgwNmFlOGVlNTQ0M2Y5YTA1ZGZlMmU2YmZkODcyMWQ4YzRl
|
15
|
+
MDI2NzE4ODRlZDJjZDFiNDI1NWY0NjIzMzcxZjZmMDc2ZDFjNDc=
|
data/bin/new
CHANGED
data/lib/new.rb
CHANGED
@@ -1,71 +1,144 @@
|
|
1
|
+
require 'active_support/core_ext/hash/deep_merge'
|
1
2
|
require 'yaml'
|
2
3
|
|
4
|
+
# Allow true/false to respond to Boolean class
|
5
|
+
module Boolean; end
|
6
|
+
class TrueClass; include Boolean; end
|
7
|
+
class FalseClass; include Boolean; end
|
8
|
+
|
3
9
|
class New
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
def self.tasks
|
14
|
-
custom_tasks | default_tasks
|
15
|
-
end
|
10
|
+
require 'new/validation'
|
11
|
+
|
12
|
+
require 'new/cli'
|
13
|
+
require 'new/source'
|
14
|
+
require 'new/task'
|
15
|
+
|
16
|
+
HOME_DIRECTORY = ENV['HOME']
|
17
|
+
PROJECT_DIRECTORY = Dir.pwd
|
18
|
+
NEWFILE_NAME = 'Newfile'
|
16
19
|
|
17
|
-
# List all the available templates
|
18
20
|
#
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
# CLASS METHODS
|
22
|
+
#
|
23
|
+
class << self
|
24
|
+
@@cli = false
|
25
|
+
@@verbose = false
|
26
|
+
@@new_object = {
|
27
|
+
:sources => {
|
28
|
+
:default => 'brewster1134/new-tasks'
|
29
|
+
}
|
30
|
+
}
|
22
31
|
|
23
|
-
|
24
|
-
|
25
|
-
end
|
32
|
+
# access the current new object
|
33
|
+
def new_object; @@new_object; end
|
26
34
|
|
27
|
-
|
28
|
-
|
29
|
-
end
|
35
|
+
# set cli to true when initialized via cli
|
36
|
+
def set_cli; @@cli = true; end
|
30
37
|
|
31
|
-
|
32
|
-
|
33
|
-
|
38
|
+
# set verbose to true when set via cli
|
39
|
+
def set_verbose; @@verbose = true; end
|
40
|
+
def verbose; @@verbose; end
|
34
41
|
|
35
|
-
|
36
|
-
|
37
|
-
|
42
|
+
# Load Newfile in home & project directory
|
43
|
+
#
|
44
|
+
def load_newfiles
|
45
|
+
load_newfile File.join(HOME_DIRECTORY, NEWFILE_NAME)
|
46
|
+
load_newfile File.join(PROJECT_DIRECTORY, NEWFILE_NAME)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Merge symbolized hash data into global new object
|
50
|
+
#
|
51
|
+
# @param hash [Hash] A hash to be merged into existing data
|
52
|
+
#
|
53
|
+
# @return [Hash] New merged data
|
54
|
+
#
|
55
|
+
def new_object= hash
|
56
|
+
@@new_object.deep_merge! hash.deep_symbolize_keys
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# Load newfile contents into the global new object
|
62
|
+
#
|
63
|
+
# @param newfile_path [String] Path to a valid Newfile
|
64
|
+
#
|
65
|
+
# @return [Hash] Hash of Newfile yaml contents
|
66
|
+
#
|
67
|
+
def load_newfile newfile_path
|
68
|
+
# check file exists
|
69
|
+
return false unless File.file? newfile_path
|
38
70
|
|
39
|
-
|
40
|
-
|
71
|
+
# load Newfile yaml into global new_object hash
|
72
|
+
self.new_object = YAML.load File.read newfile_path
|
73
|
+
end
|
41
74
|
end
|
42
75
|
|
43
76
|
private
|
44
77
|
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
when :custom
|
50
|
-
Dir[File.join(CUSTOM_DIR, dir, '**')]
|
51
|
-
end.map{ |d| File.basename(d).to_sym }
|
52
|
-
end
|
53
|
-
end
|
78
|
+
def initialize version, changelog, *skip_tasks
|
79
|
+
# load newfiles and sources
|
80
|
+
New.load_newfiles unless @@cli
|
81
|
+
New::Source.load_sources
|
54
82
|
|
55
|
-
#
|
56
|
-
|
83
|
+
# update options with new attributes
|
84
|
+
@@new_object[:version] = version
|
85
|
+
@@new_object[:changelog] = changelog
|
57
86
|
|
58
|
-
#
|
59
|
-
|
60
|
-
|
61
|
-
|
87
|
+
# create new options to pass to task
|
88
|
+
new_options = @@new_object.dup
|
89
|
+
new_options.delete(:sources)
|
90
|
+
new_options.delete(:tasks)
|
62
91
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
require 'new/task'
|
92
|
+
new_tasks = []
|
93
|
+
@@new_object[:tasks].each do |task_name, task_options|
|
94
|
+
# skip tasks
|
95
|
+
next if skip_tasks.include? task_name.to_s
|
68
96
|
|
69
|
-
|
70
|
-
|
97
|
+
S.ay "Preparing `#{task_name}`", :header
|
98
|
+
|
99
|
+
# dupe task options
|
100
|
+
new_task_options = task_options ? task_options.dup : {}
|
101
|
+
|
102
|
+
# lookup and add task to array
|
103
|
+
task = New::Source.find_task task_name, new_task_options.delete(:source)
|
104
|
+
new_tasks << task
|
105
|
+
|
106
|
+
# add task options
|
107
|
+
new_options[:task_options] = new_task_options
|
108
|
+
|
109
|
+
# set options
|
110
|
+
task.options = new_options.dup
|
111
|
+
|
112
|
+
# validate task before running anything
|
113
|
+
S.ay 'Validating Options: ', :highlight_key
|
114
|
+
task.validate
|
115
|
+
S.ay 'OK', :highlight_value
|
116
|
+
|
117
|
+
# verify tasks
|
118
|
+
S.ay 'Verifying Task Dependencies: ', :highlight_key
|
119
|
+
task.verify
|
120
|
+
S.ay 'OK', :highlight_value
|
121
|
+
S.ay
|
122
|
+
end
|
123
|
+
|
124
|
+
# write new Newfile with new version
|
125
|
+
new_newfile = YAML.load(File.read(File.join(PROJECT_DIRECTORY, NEWFILE_NAME)))
|
126
|
+
new_newfile['version'] = version
|
127
|
+
File.open File.join(PROJECT_DIRECTORY, NEWFILE_NAME), 'w+' do |f|
|
128
|
+
f.write new_newfile.to_yaml
|
129
|
+
end
|
130
|
+
|
131
|
+
new_tasks.each do |task|
|
132
|
+
S.ay "Running `#{task.name}`", :header
|
133
|
+
task.run
|
134
|
+
end
|
135
|
+
|
136
|
+
# release summary
|
137
|
+
S.ay
|
138
|
+
S.ay 'Version ', :newline => false
|
139
|
+
S.ay "#{@@new_object[:version]}", :preset => :header, :newline => false
|
140
|
+
S.ay ' of ', :newline => false
|
141
|
+
S.ay "#{@@new_object[:name]}", :preset => :header, :newline => false
|
142
|
+
S.ay ' successfully released!'
|
143
|
+
end
|
71
144
|
end
|
data/lib/new/cli.rb
CHANGED
@@ -1,94 +1,541 @@
|
|
1
|
+
require 'active_support/core_ext/hash/reverse_merge'
|
2
|
+
require 'active_support/core_ext/hash/keys'
|
3
|
+
require 'cli_miami'
|
4
|
+
require 'listen'
|
5
|
+
require 'pp'
|
6
|
+
require 'semantic'
|
1
7
|
require 'thor'
|
2
8
|
require 'yaml'
|
3
9
|
|
10
|
+
CliMiami.set_preset :error, :color => :red
|
11
|
+
CliMiami.set_preset :fine_print, :color => :cyan
|
12
|
+
CliMiami.set_preset :header, :color => :green
|
13
|
+
CliMiami.set_preset :highlight_key, :indent => 2, :newline => false, :padding => 30, :justify => :rjust
|
14
|
+
CliMiami.set_preset :highlight_value, :color => :blue, :style => :bright, :indent => 1
|
15
|
+
CliMiami.set_preset :instruction, :color => :yellow, :indent => 2
|
16
|
+
CliMiami.set_preset :list_item, :indent => 2
|
17
|
+
CliMiami.set_preset :prompt, :color => :yellow, :style => :bold
|
18
|
+
|
19
|
+
# create a horizontal line
|
20
|
+
HR = -> {S.ay('-' * 32 , :header)}
|
21
|
+
|
4
22
|
class New::Cli < Thor
|
5
|
-
desc '
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
desc 'init', 'Create a Newfile for your project'
|
24
|
+
option :name, :type => :string, :aliases => ['-n'], :default => '', :desc => 'Your project name'
|
25
|
+
option :version, :type => :string, :aliases => ['-v'], :default => '', :desc => 'Your project\'s current version'
|
26
|
+
option :tasks, :type => :array, :aliases => ['-t'], :default => [], :desc => 'Tasks to run when releasing your project'
|
27
|
+
def init
|
28
|
+
New.load_newfiles
|
29
|
+
New::Source.load_sources
|
30
|
+
|
31
|
+
# initialize empty newfile object
|
32
|
+
newfile_object = {
|
33
|
+
:tasks => {}
|
34
|
+
}
|
35
|
+
|
36
|
+
# get valid name
|
37
|
+
name = @options['name']
|
38
|
+
until !name.empty?
|
39
|
+
name = A.sk 'Project Name:', :prompt
|
40
|
+
end
|
41
|
+
newfile_object[:name] = name
|
42
|
+
|
43
|
+
# get valid version
|
44
|
+
version = Semantic::Version.new(@options['version']) rescue nil
|
45
|
+
until !version.to_s.empty?
|
46
|
+
begin
|
47
|
+
response = A.sk 'Current Project Version:', :prompt
|
48
|
+
version = Semantic::Version.new response
|
49
|
+
rescue
|
50
|
+
S.ay "`#{response}` is not a valid semantic version (e.g. 1.2.3)", :error
|
51
|
+
end
|
52
|
+
end
|
53
|
+
newfile_object[:version] = version.to_s
|
54
|
+
|
55
|
+
# get tasks
|
56
|
+
tasks_list = []
|
57
|
+
@options['tasks'].each do |task|
|
58
|
+
tasks_list << New::Source.find_task(task)
|
59
|
+
end
|
60
|
+
|
61
|
+
# remove any empty tasks in case the user specified an invalid task
|
62
|
+
tasks_list.compact!
|
63
|
+
|
64
|
+
# if no tasks are specified, show all available tasks
|
65
|
+
if tasks_list.empty?
|
66
|
+
S.ay
|
67
|
+
self.tasks :show_source => true, :load_newfiles => false, :load_sources => false
|
68
|
+
|
69
|
+
S.ay 'Add multiple tasks by pressing ENTER after each one', :instruction
|
70
|
+
S.ay 'Enter tasks in the order you want them to run', :instruction
|
71
|
+
S.ay 'Enter both the source and the task (e.g. source#task)', :instruction
|
72
|
+
S.ay 'Enter an empty value to finish', :instruction
|
73
|
+
|
74
|
+
added_task = nil
|
75
|
+
until added_task == '' && !tasks_list.empty?
|
76
|
+
S.ay
|
77
|
+
added_task = A.sk 'Add a task:', :prompt
|
78
|
+
|
79
|
+
# if a task is entered, verify it exists
|
80
|
+
unless added_task.empty?
|
81
|
+
|
82
|
+
# find task
|
83
|
+
task = New::Source.find_task added_task
|
84
|
+
|
85
|
+
# add task to array
|
86
|
+
if task
|
87
|
+
tasks_list << task
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
S.ay
|
93
|
+
end
|
94
|
+
|
95
|
+
# output the summary so far (no task options entered yet)
|
96
|
+
padding = 10
|
97
|
+
S.ay 'Name:', :preset => :highlight_key, :padding => padding
|
98
|
+
S.ay name, :preset => :highlight_value
|
99
|
+
S.ay 'Version:', :preset => :highlight_key, :padding => padding
|
100
|
+
S.ay version.to_s, :preset => :highlight_value
|
101
|
+
S.ay 'Tasks:', :preset => :highlight_key, :padding => padding
|
102
|
+
|
103
|
+
# output first task without a padding so it looks nicer
|
104
|
+
tasks_dup = tasks_list.dup
|
105
|
+
first_task = tasks_dup.shift
|
106
|
+
S.ay "#{first_task.source.name}##{first_task.name}", :highlight_value
|
107
|
+
tasks_dup.each do |task|
|
108
|
+
S.ay "#{task.source.name}##{task.name}", :preset => :highlight_value, :indent => padding + 3
|
109
|
+
end
|
110
|
+
S.ay
|
111
|
+
|
112
|
+
tasks_list.each do |task|
|
113
|
+
HR.call
|
114
|
+
S.ay 'OK, now lets set options for', :highlight_key
|
115
|
+
S.ay task.name.to_s.upcase, :highlight_value
|
116
|
+
HR.call
|
117
|
+
S.ay
|
118
|
+
|
119
|
+
newfile_object[:tasks][task.name] = {}
|
120
|
+
task.class_options.each do |option_name, option_settings|
|
121
|
+
S.ay option_name.to_s, :preset => :highlight_key, :padding => 0
|
122
|
+
S.ay option_settings[:description], :highlight_value
|
123
|
+
|
124
|
+
# show default
|
125
|
+
default = option_settings[:default]
|
126
|
+
if default && !option_settings[:required]
|
127
|
+
default = case default
|
128
|
+
when Array then default.join(', ')
|
129
|
+
when Hash then default.keys.join(', ')
|
130
|
+
else default.to_s
|
131
|
+
end
|
132
|
+
|
133
|
+
S.ay "default: #{default}", :preset => :fine_print, :indent => option_name.length + 3
|
134
|
+
end
|
135
|
+
|
136
|
+
# GET USER INPUT FOR ARRAY TYPE
|
137
|
+
#
|
138
|
+
option_type = option_settings[:type]
|
139
|
+
case
|
140
|
+
|
141
|
+
# collect array option type values
|
142
|
+
when option_type == Array
|
143
|
+
# cast type onto all user input values (default is String)
|
144
|
+
klass = option_settings[:validation] || String
|
145
|
+
|
146
|
+
# collect array elements from the user
|
147
|
+
option_value = nil
|
148
|
+
until option_value
|
149
|
+
begin
|
150
|
+
option_value = get_array_from_user(klass)
|
151
|
+
option_value = New::Task.validate_option(option_name, option_settings, option_value)
|
152
|
+
rescue
|
153
|
+
option_value = nil
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# collect hash option type values
|
158
|
+
when option_type == Hash
|
159
|
+
# loop through the expected keys from the validation and get users input
|
160
|
+
option_value = nil
|
161
|
+
until option_value
|
162
|
+
begin
|
163
|
+
option_value = get_hash_from_user(option_settings[:validation])
|
164
|
+
option_value = New::Task.validate_option(option_name, option_settings, option_value)
|
165
|
+
rescue
|
166
|
+
option_value = nil
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# collect non array/hash option type value
|
171
|
+
else
|
172
|
+
option_value = nil
|
173
|
+
until option_value
|
174
|
+
A.sk '', :newline => false, :preset => :prompt do |response|
|
175
|
+
option_value = New::Task.validate_option(option_name, option_settings, response) rescue nil
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
newfile_object[:tasks][task.name][option_name] = option_value
|
181
|
+
S.ay
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# write project Newfile
|
186
|
+
project_newfile = File.join New::PROJECT_DIRECTORY, New::NEWFILE_NAME
|
187
|
+
File.open project_newfile, 'w+' do |f|
|
188
|
+
f.write newfile_object.deep_stringify_keys.to_yaml
|
29
189
|
end
|
190
|
+
|
191
|
+
# Success Message
|
192
|
+
S.ay "A `#{'Newfile'.green}` was successfully created for your project `#{name.to_s.green}`"
|
193
|
+
S.ay 'Open the file to verify the values are correct, and make any neccessary modifications.'
|
194
|
+
S.ay "You are now ready to run `#{'new release'.green}` to release your software into the wild!"
|
195
|
+
S.ay
|
30
196
|
end
|
31
197
|
|
32
|
-
desc '
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
198
|
+
desc 'tasks', 'List all available tasks'
|
199
|
+
option :sources, :type => :boolean, :aliases => ['-s'], :default => false, :desc => 'Show/Hide task sources'
|
200
|
+
def tasks args = {}
|
201
|
+
# merge into default options
|
202
|
+
options = {
|
203
|
+
:show_source => (@options['sources'] || false),
|
204
|
+
:load_newfiles => true,
|
205
|
+
:load_sources => true
|
206
|
+
}.merge(args)
|
207
|
+
|
208
|
+
New.load_newfiles if options[:load_newfiles]
|
209
|
+
if options[:load_sources]
|
210
|
+
S.ay
|
211
|
+
S.ay 'Fetching sources...', :header
|
212
|
+
S.ay "Use the #{'green'.green} value for defining task sources in your Newfile", :indent => 2 if options[:show_source]
|
213
|
+
S.ay
|
214
|
+
New::Source.load_sources
|
215
|
+
end
|
216
|
+
|
217
|
+
New::Source.sources.each do |source_name, source|
|
218
|
+
# determine the widest task & add some padding
|
219
|
+
longest_task_length = source.tasks.keys.map(&:length).max
|
220
|
+
|
221
|
+
S.ay source_name.to_s, :indent => 2, :newline => false, :style => :underline
|
222
|
+
S.ay source.path, :highlight_value
|
223
|
+
|
224
|
+
source.tasks.each do |task_name, task|
|
225
|
+
if options[:show_source]
|
226
|
+
padding = longest_task_length + source_name.to_s.length + 2
|
227
|
+
S.ay "#{source_name}##{task_name}", :preset => :header, :newline => false, :indent => 2, :padding => padding, :justify => :ljust
|
228
|
+
else
|
229
|
+
padding = longest_task_length + 2
|
230
|
+
S.ay task_name.to_s, :preset => :header, :newline => false, :indent => 2, :padding => padding, :justify => :ljust
|
231
|
+
end
|
232
|
+
S.ay task.description, :indent => 2
|
46
233
|
end
|
47
234
|
|
48
|
-
|
235
|
+
S.ay
|
49
236
|
end
|
50
237
|
end
|
51
238
|
|
52
|
-
desc 'release', 'Release
|
239
|
+
desc 'release', 'Release a new version of your project'
|
240
|
+
option :verbose, :type => :boolean, :aliases => ['-v'], :default => false, :desc => 'Verbose mode'
|
241
|
+
option :skip, :type => :array, :aliases => ['-s'], :default => [], :desc => 'Tasks to skip for this release'
|
53
242
|
def release
|
54
|
-
|
55
|
-
|
243
|
+
New.set_verbose if @options['verbose']
|
244
|
+
New.set_cli
|
245
|
+
New.load_newfiles
|
56
246
|
|
57
|
-
#
|
58
|
-
|
247
|
+
# request the version to bump
|
248
|
+
S.ay
|
249
|
+
S.ay 'Releasing a new version of: ', :highlight_key
|
250
|
+
S.ay New.new_object[:name], :highlight_value
|
251
|
+
S.ay 'What do you want to bump: ', :highlight_key
|
252
|
+
S.ay "[#{'Mmp'.green}] (#{'M'.green}ajor / #{'m'.green}inor / #{'p'.green}atch)", :preset => :highlight_value, :color => :white
|
253
|
+
version = Semantic::Version.new New.new_object[:version]
|
254
|
+
version_bump_part = nil
|
255
|
+
until version_bump_part
|
256
|
+
S.ay 'Current Version:', :highlight_key
|
257
|
+
A.sk version.to_s, :highlight_value do |response|
|
258
|
+
version_bump_part = case response
|
259
|
+
when 'M'
|
260
|
+
version.major += 1
|
261
|
+
version.minor = 0
|
262
|
+
version.patch = 0
|
263
|
+
when 'm'
|
264
|
+
version.minor += 1
|
265
|
+
version.patch = 0
|
266
|
+
when 'p'
|
267
|
+
version.patch += 1
|
268
|
+
else
|
269
|
+
S.ay 'You must choose from [Mmp]', :error
|
270
|
+
nil
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
S.ay 'New Version: ', :highlight_key
|
275
|
+
S.ay version.to_s, :highlight_value
|
276
|
+
S.ay
|
59
277
|
|
60
|
-
#
|
61
|
-
|
278
|
+
# collect a list of changes in this version
|
279
|
+
changelog = get_changelog_from_user
|
280
|
+
S.ay
|
62
281
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
282
|
+
# show tasks
|
283
|
+
S.ay "#{'Running Tasks:'.green} (in order)"
|
284
|
+
skip_tasks = @options['skip'].map(&:to_sym)
|
285
|
+
New.new_object[:tasks].keys.each do |task|
|
286
|
+
if skip_tasks.include?(task)
|
287
|
+
S.ay "#{task.to_s} (skipped)", :preset => :fine_print, :indent => 4
|
288
|
+
else
|
289
|
+
S.ay task.to_s, :indent => 2
|
290
|
+
end
|
291
|
+
end
|
292
|
+
S.ay
|
293
|
+
|
294
|
+
New.new version.to_s, changelog, @options['skip']
|
295
|
+
end
|
296
|
+
|
297
|
+
desc 'version', 'Show the current version'
|
298
|
+
def version
|
299
|
+
New.load_newfiles
|
300
|
+
S.ay New.new_object[:name], :highlight_key
|
301
|
+
S.ay New.new_object[:version], :highlight_value
|
302
|
+
end
|
303
|
+
|
304
|
+
desc 'test', 'Run task tests from sources'
|
305
|
+
option :watch, :type => :boolean, :aliases => ['-w'], :desc => 'Watch local tasks for changes and run tests'
|
306
|
+
option :source, :type => :string, :aliases => ['-s'], :desc => 'Source name'
|
307
|
+
option :task, :type => :string, :aliases => ['-t'], :desc => 'Task name'
|
308
|
+
def test
|
309
|
+
spec_paths = []
|
310
|
+
watch_dirs = []
|
311
|
+
|
312
|
+
New.load_newfiles
|
313
|
+
New::Source.load_sources
|
314
|
+
|
315
|
+
# create a hash with a single source if one is passed
|
316
|
+
sources = if @options['source']
|
317
|
+
source_name = @options['source'].to_sym
|
318
|
+
source_hash = {}
|
319
|
+
source_hash[source_name] = New::Source.sources[source_name]
|
320
|
+
source_hash
|
321
|
+
else
|
322
|
+
New::Source.sources
|
323
|
+
end
|
324
|
+
|
325
|
+
# collect specs to run/watch
|
326
|
+
sources.each do |source_name, source|
|
327
|
+
next unless source
|
328
|
+
|
329
|
+
# create a hash with a single task if one is passed
|
330
|
+
tasks = @options['task'] ? [source.tasks[options['task'].to_sym]] : source.tasks
|
331
|
+
tasks = if @options['task']
|
332
|
+
task_name = @options['task'].to_sym
|
333
|
+
task_hash = {}
|
334
|
+
task_hash[task_name] = source.tasks[task_name]
|
335
|
+
task_hash
|
336
|
+
else
|
337
|
+
source.tasks
|
338
|
+
end
|
339
|
+
|
340
|
+
tasks.each do |task_name, task|
|
341
|
+
next unless task.path
|
342
|
+
|
343
|
+
spec_path = File.join(File.dirname(task.path), "#{task_name}_task_spec.rb")
|
344
|
+
|
345
|
+
# if the source/task has a spec file, and the source is local, watch the task directory for changes and run the spec whenever anything changes
|
346
|
+
if File.file?(spec_path) && File.directory?(source.path)
|
347
|
+
# find task directory in original path, not the sourcerer tmp directory
|
348
|
+
original_task_dir_path = File.dirname(Dir[File.join(source.path, '**', File.basename(task.path))][0])
|
349
|
+
|
350
|
+
watch_dirs << original_task_dir_path
|
351
|
+
spec_paths << spec_path
|
70
352
|
end
|
71
|
-
rescue LoadError
|
72
|
-
New.say "No task '#{task}' found!", type: :fail
|
73
|
-
next
|
74
353
|
end
|
75
|
-
|
76
|
-
|
354
|
+
end
|
355
|
+
|
356
|
+
# run tests
|
357
|
+
if !spec_paths.empty?
|
358
|
+
# S.ay "Running tests for `#{task_name}` task in `#{source_name}` source...", :warn
|
359
|
+
Kernel::system "bundle exec rspec #{spec_paths.join(' ')}"
|
360
|
+
end
|
361
|
+
|
362
|
+
# watch tests
|
363
|
+
# if watch files are found, start a listener to run the spec
|
364
|
+
if @options['watch'] && !watch_dirs.empty?
|
365
|
+
listener = Listen.to *watch_dirs do |modified, added, removed|
|
366
|
+
all = modified + added + removed
|
367
|
+
|
368
|
+
# find sibling spec file from modified file
|
369
|
+
spec_path = all.collect{ |file| Dir[File.join(File.dirname(file), '*_spec.rb')] }.flatten.first
|
370
|
+
|
371
|
+
Kernel::system "bundle exec rspec #{spec_path}"
|
372
|
+
end
|
373
|
+
listener.start
|
374
|
+
Kernel::sleep
|
77
375
|
end
|
78
376
|
end
|
79
377
|
|
80
|
-
|
378
|
+
no_commands do
|
379
|
+
def get_changelog_from_user
|
380
|
+
S.ay 'Lets add some items to the changelog', :header
|
381
|
+
S.ay 'Add multiple entries by pressing ENTER after each one', :instruction
|
382
|
+
S.ay 'Enter an empty value to finish', :instruction
|
81
383
|
|
82
|
-
|
83
|
-
|
84
|
-
New.say "A project named #{name} already exists...", type: :warn
|
85
|
-
New.say " Overwrite it? [Yn]", type: :warn
|
86
|
-
exit if STDIN.gets.chomp! != 'Y'
|
384
|
+
user_changelog = []
|
385
|
+
user_response = nil
|
87
386
|
|
88
|
-
#
|
89
|
-
|
387
|
+
# add entries to the changelog until an empty string is entered
|
388
|
+
until user_response == '' && !user_changelog.empty?
|
389
|
+
A.sk user_changelog.compact.join("\n"), :prompt do |response|
|
390
|
+
if response.empty?
|
391
|
+
user_response = ''
|
392
|
+
next
|
393
|
+
end
|
394
|
+
|
395
|
+
user_changelog << user_response = response
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
user_changelog
|
90
400
|
end
|
91
401
|
|
92
|
-
|
402
|
+
def get_array_from_user validation = String
|
403
|
+
# start to build the array of user values
|
404
|
+
user_array = []
|
405
|
+
|
406
|
+
# convert array to hash of Strings
|
407
|
+
if validation.is_a? Array
|
408
|
+
validation_hash = {}
|
409
|
+
validation.each do |v|
|
410
|
+
validation_hash[v.to_sym] = String
|
411
|
+
end
|
412
|
+
validation = validation_hash
|
413
|
+
end
|
414
|
+
|
415
|
+
if validation.is_a? Hash
|
416
|
+
S.ay 'We need to collect a list of complex objects', :header
|
417
|
+
|
418
|
+
user_response = nil
|
419
|
+
until user_response == 'n'
|
420
|
+
S.ay "#{user_array.length} objects created: ", :indent => 2, :newline => false
|
421
|
+
S.ay user_array.join(', '), :highlight_value
|
422
|
+
A.sk 'Press ENTER to create another object. Enter `n` to stop.', :prompt do |response|
|
423
|
+
if response == 'n'
|
424
|
+
user_response = 'n'
|
425
|
+
next
|
426
|
+
end
|
427
|
+
|
428
|
+
user_response = get_hash_from_user(validation, false)
|
429
|
+
user_array << user_response
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
else
|
434
|
+
S.ay "We need to collect a list of #{validation}s", :header
|
435
|
+
S.ay 'Add multiple values by pressing ENTER after each one', :instruction
|
436
|
+
S.ay 'Enter an empty value to finish', :instruction
|
437
|
+
|
438
|
+
# add to the array until an empty string is entered
|
439
|
+
user_response = nil
|
440
|
+
until user_response == ''
|
441
|
+
A.sk user_array.compact.join(', '), :prompt do |response|
|
442
|
+
|
443
|
+
# if the option is valid, pass through the empty string to end entering values
|
444
|
+
if response.empty?
|
445
|
+
user_response = ''
|
446
|
+
next
|
447
|
+
end
|
448
|
+
|
449
|
+
user_response = New::Task.validate_class(response, validation) rescue nil
|
450
|
+
user_array << user_response
|
451
|
+
end
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
return user_array.compact
|
456
|
+
end
|
457
|
+
|
458
|
+
def get_hash_from_user validation = {}, allow_custom_keys = true
|
459
|
+
# start to build the hash of user values
|
460
|
+
user_hash = {}
|
461
|
+
|
462
|
+
# convert array to hash of Strings
|
463
|
+
if validation.is_a? Array
|
464
|
+
validation_hash = {}
|
465
|
+
validation.each do |v|
|
466
|
+
validation_hash[v.to_sym] = String
|
467
|
+
end
|
468
|
+
validation = validation_hash
|
469
|
+
end
|
470
|
+
|
471
|
+
# get user values for required validation keys
|
472
|
+
validation.each do |key, klass|
|
473
|
+
S.ay 'We need to collect some required values', :header
|
474
|
+
|
475
|
+
user_response = nil
|
476
|
+
until user_response
|
477
|
+
|
478
|
+
# do not allow nested arrays/hashes
|
479
|
+
# these should be declared as their own option
|
480
|
+
if klass == Array || klass == Hash
|
481
|
+
S.ay 'Hash options cannot have nested Arrays or Hashes. They should be declared as their own option.', :error
|
482
|
+
exit
|
483
|
+
end
|
484
|
+
|
485
|
+
A.sk "Enter a VALUE for `#{key}`", :prompt do |response|
|
486
|
+
# make sure validation keys have a value
|
487
|
+
if response == ''
|
488
|
+
user_response = nil
|
489
|
+
next
|
490
|
+
end
|
491
|
+
|
492
|
+
begin
|
493
|
+
user_response = New::Task.validate_class(response, klass)
|
494
|
+
user_hash[key] = user_response
|
495
|
+
S.ay user_hash
|
496
|
+
rescue
|
497
|
+
user_response = nil
|
498
|
+
end
|
499
|
+
end
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
if allow_custom_keys
|
504
|
+
# Allow users to enter custom keys AND values
|
505
|
+
S.ay 'You can add custom keys & values if you want', :header
|
506
|
+
S.ay 'Add multiple key/value pairs by pressing ENTER after each one', :instruction
|
507
|
+
S.ay 'Enter an empty key to finish', :instruction
|
508
|
+
|
509
|
+
user_key_response = nil
|
510
|
+
until user_key_response == ''
|
511
|
+
A.sk 'Enter a KEY name', :prompt do |key_response|
|
512
|
+
# exit loop if user is done entering info
|
513
|
+
if key_response == ''
|
514
|
+
user_key_response = ''
|
515
|
+
next
|
516
|
+
end
|
517
|
+
|
518
|
+
user_value_response = nil
|
519
|
+
until user_value_response
|
520
|
+
A.sk "Enter a VALUE for `#{key_response}`", :prompt do |value_response|
|
521
|
+
# make sure value exists for user created key
|
522
|
+
if value_response == ''
|
523
|
+
user_value_response = nil
|
524
|
+
next
|
525
|
+
end
|
526
|
+
|
527
|
+
# create key/value pair
|
528
|
+
user_hash[key_response.to_sym] = user_value_response = value_response
|
529
|
+
S.ay user_hash
|
530
|
+
end
|
531
|
+
end
|
532
|
+
end
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
return user_hash
|
537
|
+
end
|
93
538
|
end
|
539
|
+
|
540
|
+
default_task :release
|
94
541
|
end
|