jacaetevha-growthspurt 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +6 -0
- data/Manifest.txt +11 -0
- data/README.txt +60 -0
- data/VERSION +1 -0
- data/bin/growthspurt +5 -0
- data/lib/growthspurt.rb +393 -0
- data/test/test_growthspurt.rb +2 -0
- metadata +77 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
= growthspurt
|
2
|
+
|
3
|
+
* http://github.com/jacaetevha/growth-spurt
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
=== What is GrowthSpurt?
|
8
|
+
|
9
|
+
It's a utility for creating branches in Git and automatically creating/updating change files based on commit messages.
|
10
|
+
|
11
|
+
=== Why GrowthSpurt?
|
12
|
+
|
13
|
+
I originally wrote this in order help automate builds of our Ruby code into a Java/Maven-centric company build process. Most of the company dealt with Subversion, but I wanted to use Git. Most of the company coded in Java and managed builds/deployments with Maven, but I wanted to use Ruby and Capistrano. I lost on the Capistrano-vs-Maven front, but I was able to continue using Ruby and Git. So, this script was built to automate branching in Git in a standard Major.Minor.Micro format (eg. 1.0.1, 1.0.2, 1.0.3) and pushing those branches to a remote repository, and then using Git to create a CHANGES file and a changes.xml file. The latter is used by Maven's Changes plugin (http://maven.apache.org/plugins/maven-changes-plugin/).
|
14
|
+
|
15
|
+
== FEATURES/PROBLEMS:
|
16
|
+
|
17
|
+
* create CHANGES and changes.xml files based on commit messages from Git for any digit.digit.digit branch, as well as the master branch
|
18
|
+
* can create a new remote and local tracking branch for the new "growth" (branch)
|
19
|
+
* doesn't handle Nano format branches (eg. 1.2.3.45)
|
20
|
+
* once on the branch the check-in of the change files isn't happening properly because they aren't being added
|
21
|
+
* when creating a new version of this project the gemspec file needs to be updated
|
22
|
+
|
23
|
+
== SYNOPSIS:
|
24
|
+
|
25
|
+
To get a synopsis, run growthspurt -h
|
26
|
+
|
27
|
+
== REQUIREMENTS:
|
28
|
+
|
29
|
+
* grit 1.1.1
|
30
|
+
* facets 2.5.2 (in particular, dictionary & enumerable
|
31
|
+
|
32
|
+
== INSTALL:
|
33
|
+
|
34
|
+
* sudo gem install grit facets
|
35
|
+
* sudo gem install jacaetevha-growth-spurt
|
36
|
+
|
37
|
+
== LICENSE:
|
38
|
+
|
39
|
+
(The MIT License)
|
40
|
+
|
41
|
+
Copyright (c) 2009 Jason Rogers
|
42
|
+
|
43
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
44
|
+
a copy of this software and associated documentation files (the
|
45
|
+
'Software'), to deal in the Software without restriction, including
|
46
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
47
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
48
|
+
permit persons to whom the Software is furnished to do so, subject to
|
49
|
+
the following conditions:
|
50
|
+
|
51
|
+
The above copyright notice and this permission notice shall be
|
52
|
+
included in all copies or substantial portions of the Software.
|
53
|
+
|
54
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
55
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
56
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
57
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
58
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
59
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
60
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.6
|
data/bin/growthspurt
ADDED
data/lib/growthspurt.rb
ADDED
@@ -0,0 +1,393 @@
|
|
1
|
+
#!/usr/bin/env ruby -wKU
|
2
|
+
|
3
|
+
# == Synopsis
|
4
|
+
# This script will create a new branch of the CRM application and check that into Git.
|
5
|
+
#
|
6
|
+
# == Examples
|
7
|
+
# This command does will create a branch called 1.0.5 and will update the CHANGES and changes.xml
|
8
|
+
# files with differences between 1.0.5 and 1.0.2
|
9
|
+
# growthspurt -p 1.0.2 -c 1.0.5
|
10
|
+
#
|
11
|
+
# Other examples:
|
12
|
+
# growthspurt -q -p 1.0.4 -c 1.0.5
|
13
|
+
# growthspurt --verbose -p testing_branch -c qa_branch_1
|
14
|
+
# growthspurt -n
|
15
|
+
#
|
16
|
+
# == Usage
|
17
|
+
# growthspurt [options]
|
18
|
+
#
|
19
|
+
# For help use: growthspurt -h
|
20
|
+
#
|
21
|
+
# == Options
|
22
|
+
# -h, --help Displays help message
|
23
|
+
#
|
24
|
+
# -v, --version Display the version, then exit
|
25
|
+
#
|
26
|
+
# -q, --quiet Output as little as possible, overrides verbose
|
27
|
+
#
|
28
|
+
# -V, --verbose Verbose output
|
29
|
+
#
|
30
|
+
# -t, --title The value of the title attribute in the changes.xml file
|
31
|
+
#
|
32
|
+
# -P, --changes-path The path to changes.xml file (defaults to src/changes)
|
33
|
+
#
|
34
|
+
# -N, --no-branch Don't create a new branch, just update the CHANGES and changes.xml files
|
35
|
+
#
|
36
|
+
# -n, --next Create a new branch with this tag as its name (required, unless -n is specified)
|
37
|
+
#
|
38
|
+
# -m, --message Message when creating new branch (defaults to "created version <value of -n argument>")
|
39
|
+
#
|
40
|
+
# -p, --prev Previous version (optional), used in conjunction with -c. Specifying this option
|
41
|
+
# will create the CHANGES and changes.xml files in the "next" branch with the changes
|
42
|
+
# between the current branch and the "previous" branch.
|
43
|
+
#
|
44
|
+
# Eg. While running this script within the master branch the following command will create
|
45
|
+
# a 1.0.5 branch based off of master with a CHANGES file that contains the differences
|
46
|
+
# between the master branch and the 1.0.4 branch:
|
47
|
+
#
|
48
|
+
# growthspurt -p 1.0.4 -n 1.0.5
|
49
|
+
#
|
50
|
+
# == Author
|
51
|
+
# Jason Rogers
|
52
|
+
#
|
53
|
+
# == Copyright
|
54
|
+
# Copyright (c) 2009 Jason Rogers
|
55
|
+
|
56
|
+
require 'optparse'
|
57
|
+
require 'rdoc/usage'
|
58
|
+
require 'ostruct'
|
59
|
+
require 'rexml/document'
|
60
|
+
require 'time'
|
61
|
+
require 'fileutils'
|
62
|
+
require 'grit'
|
63
|
+
require 'facets/dictionary'
|
64
|
+
require 'facets/enumerable'
|
65
|
+
|
66
|
+
class GrowthSpurt
|
67
|
+
include REXML
|
68
|
+
include Grit
|
69
|
+
|
70
|
+
VERSION = File.readlines(File.expand_path(File.join(File.dirname(__FILE__), '..', 'VERSION'))).first.chomp
|
71
|
+
|
72
|
+
def self.pre_commit_hooks
|
73
|
+
@@pre_commit_hooks ||= []
|
74
|
+
end
|
75
|
+
|
76
|
+
attr_reader :options, :diffs, :repo
|
77
|
+
|
78
|
+
def initialize(arguments, stdin)
|
79
|
+
@arguments = arguments
|
80
|
+
@stdin = stdin
|
81
|
+
|
82
|
+
# Set defaults
|
83
|
+
@options = OpenStruct.new
|
84
|
+
@options.verbose = false
|
85
|
+
@options.quiet = false
|
86
|
+
@options.create_branch = true
|
87
|
+
@options.changes_dot_xml_directory = File.join('src', 'changes')
|
88
|
+
@repo = Repo.new('.')
|
89
|
+
@diffs = []
|
90
|
+
end
|
91
|
+
|
92
|
+
# Parse options, check arguments, then process the command
|
93
|
+
def run
|
94
|
+
|
95
|
+
if parsed_options? && arguments_valid?
|
96
|
+
|
97
|
+
puts "Start at #{DateTime.now}\n\n" if @options.verbose
|
98
|
+
|
99
|
+
output_options if @options.verbose # [Optional]
|
100
|
+
|
101
|
+
process_arguments
|
102
|
+
process_command
|
103
|
+
|
104
|
+
puts "\nFinished at #{DateTime.now}" if @options.verbose
|
105
|
+
|
106
|
+
else
|
107
|
+
output_usage
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
protected
|
113
|
+
def parsed_options?
|
114
|
+
# Specify options
|
115
|
+
opts = OptionParser.new
|
116
|
+
opts.on('-v', '--version') { output_version ; exit 0 }
|
117
|
+
opts.on('-h', '--help') { output_help }
|
118
|
+
opts.on('-V', '--verbose') { @options.verbose = true }
|
119
|
+
opts.on('-q', '--quiet') { @options.quiet = true }
|
120
|
+
opts.on('-p', '--prev=name') { |v| @options.previous_version = v }
|
121
|
+
opts.on('-n', '--next=name') { |v| @options.new_version = v }
|
122
|
+
opts.on('-N', '--no-branch') { @options.create_branch = false }
|
123
|
+
opts.on('-m', '--message=msg') { |v| @options.message = v }
|
124
|
+
opts.on('-t', '--title=title') { |v| @options.title = v }
|
125
|
+
opts.on('-c', '--changes-path=path') { |v| @options.changes_dot_xml_directory = v }
|
126
|
+
opts.on('-P', '--pre-commit-hooks=file') { |v| load File.expand_path(v) }
|
127
|
+
|
128
|
+
opts.parse!(@arguments) rescue return false
|
129
|
+
|
130
|
+
process_options
|
131
|
+
true
|
132
|
+
end
|
133
|
+
|
134
|
+
# Performs post-parse processing on options
|
135
|
+
def process_options
|
136
|
+
@options.verbose = false if @options.quiet
|
137
|
+
end
|
138
|
+
|
139
|
+
def output_options
|
140
|
+
puts "Options:\n"
|
141
|
+
|
142
|
+
@options.marshal_dump.each do |name, val|
|
143
|
+
puts " #{name} = #{val}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# True if required arguments were provided
|
148
|
+
def arguments_valid?
|
149
|
+
#
|
150
|
+
# Not sure if the following makes sense. Could be that we want
|
151
|
+
# to specify a (non-existent) branch to see what the changes.xml
|
152
|
+
# file would look like.
|
153
|
+
#
|
154
|
+
if @options.new_version
|
155
|
+
unless @options.create_branch
|
156
|
+
puts "\n\nWARNING: you specified a new branch name, but you did not specify to create it.\nThe changes.xml file will reference this new branch, but it won't be created.\n\n"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
if @options.create_branch
|
161
|
+
return false if @options.new_version.nil? || @options.new_version.empty?
|
162
|
+
unless git_remote_branch_installed?
|
163
|
+
puts "cannot create new branch, either install git-remote-branch (sudo gem install git-remote-branch) or make sure it's in your PATH"
|
164
|
+
return false
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
true
|
169
|
+
end
|
170
|
+
|
171
|
+
# Setup the arguments
|
172
|
+
def process_arguments
|
173
|
+
end
|
174
|
+
|
175
|
+
def output_help
|
176
|
+
output_version
|
177
|
+
RDoc::usage() #exits app
|
178
|
+
end
|
179
|
+
|
180
|
+
def output_usage
|
181
|
+
RDoc::usage('usage') # gets usage from comments above
|
182
|
+
end
|
183
|
+
|
184
|
+
def output_version
|
185
|
+
puts "#{File.basename(__FILE__)} version #{VERSION}"
|
186
|
+
end
|
187
|
+
|
188
|
+
def process_command
|
189
|
+
@options.message = "created version #{@options.new_version}"
|
190
|
+
|
191
|
+
if !@options.new_version && @options.create_branch
|
192
|
+
raise 'must specify a version in order to create a branch (eg. 1.0.1)'
|
193
|
+
exit 1
|
194
|
+
end
|
195
|
+
|
196
|
+
@diffs = load_diffs
|
197
|
+
|
198
|
+
update_changes_files
|
199
|
+
|
200
|
+
if @options.create_branch
|
201
|
+
puts "creating initial branch #{@options.new_version}"
|
202
|
+
`#{grb_location} create #{@options.new_version}`
|
203
|
+
|
204
|
+
update_pom_dot_xml
|
205
|
+
update_dot_gitignore
|
206
|
+
|
207
|
+
run_pre_commit_hooks
|
208
|
+
|
209
|
+
puts "committing to #{@options.new_version}"
|
210
|
+
`git commit -v -a -m"#{@options.message}"`
|
211
|
+
|
212
|
+
puts "pushing to main repository"
|
213
|
+
`git push`
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
private
|
218
|
+
def run_pre_commit_hooks
|
219
|
+
self.class.pre_commit_hooks.each do | hook |
|
220
|
+
hook.run(self)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def load_diffs(opts={})
|
225
|
+
options = {:last => @options.previous_version, :current => current_branch, :diff_collection => self.diffs}.merge(opts)
|
226
|
+
commits = options[:last] ?
|
227
|
+
repo.commits_between(options[:last], options[:current]) :
|
228
|
+
repo.commits_since(options[:current]) #2nd arg could be a date string
|
229
|
+
commits.reverse.each do |commit|
|
230
|
+
options[:diff_collection] << CommitSnapshot.new(commit)
|
231
|
+
end
|
232
|
+
options[:diff_collection]
|
233
|
+
end
|
234
|
+
|
235
|
+
def git_remote_branch_installed?
|
236
|
+
grb_location.nil? == false && grb_location.empty? == false
|
237
|
+
end
|
238
|
+
|
239
|
+
def grb_location
|
240
|
+
@grb ||= `which grb`.chomp
|
241
|
+
end
|
242
|
+
|
243
|
+
def current_branch
|
244
|
+
Head.current(repo).name
|
245
|
+
end
|
246
|
+
|
247
|
+
def release_branches
|
248
|
+
branches = repo.branches.select {|e| e.name =~ /[\d]+\.[\d]+\.[\d]+/ || e.name == 'master'}.collect{|e| e.name}.sensible_sort
|
249
|
+
commits_per_branch = Dictionary.alpha
|
250
|
+
branches.each_with_index do | branch, index |
|
251
|
+
if branch == "master"
|
252
|
+
commits_per_branch[branch] = repo.commits_between(branches[index - 1], branch)
|
253
|
+
else
|
254
|
+
commits_per_branch[branch] = repo.commits(branch).sort{|a, b| b.date <=> a.date}
|
255
|
+
end
|
256
|
+
end
|
257
|
+
commits_per_branch
|
258
|
+
end
|
259
|
+
|
260
|
+
def update_changes_files
|
261
|
+
rest_of_message = "between #{@options.previous_version} and #{@options.new_version}" if @options.new_version && @options.previous_version
|
262
|
+
rest_of_message = "between #{current_branch} and #{@options.new_version}" if @options.new_version && !@options.previous_version
|
263
|
+
rest_of_message = "" unless @options.new_version && @options.create_branch
|
264
|
+
unless self.diffs.empty?
|
265
|
+
File.open('CHANGES', 'w') do | f |
|
266
|
+
self.diffs.each do | diff |
|
267
|
+
f << diff.formatted_for_changes_file
|
268
|
+
end
|
269
|
+
end
|
270
|
+
puts "created/updated CHANGES for differences #{rest_of_message}"
|
271
|
+
repo.add('CHANGES') if @options.create_branch
|
272
|
+
end
|
273
|
+
|
274
|
+
FileUtils.mkdir_p(@options.changes_dot_xml_directory) unless File.exists?(@options.changes_dot_xml_directory)
|
275
|
+
changes_dot_xml_file = File.join(@options.changes_dot_xml_directory, 'changes.xml')
|
276
|
+
File.open(changes_dot_xml_file, 'w') do | f |
|
277
|
+
write_to_file = lambda {|s| f << s}
|
278
|
+
changes_dot_xml_header( &write_to_file )
|
279
|
+
release_branches.each_pair do | branch_name, commits |
|
280
|
+
next if commits.nil? || commits.empty?
|
281
|
+
f << " <release version='#{branch_name == 'master' ? @options.new_version : branch_name}' date='#{commits.last.date}' description='#{commits.last.message.chomp[0..10]}'>\n"
|
282
|
+
commits.each do | commit |
|
283
|
+
CommitSnapshot.new(commit).formatted_for_changes_dot_xml_file( &write_to_file )
|
284
|
+
end
|
285
|
+
f << " </release>\n"
|
286
|
+
end
|
287
|
+
|
288
|
+
changes_dot_xml_footer( &write_to_file )
|
289
|
+
puts "created/updated changes.xml for differences #{rest_of_message}"
|
290
|
+
repo.add(changes_dot_xml_file) if @options.create_branch
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
def update_dot_gitignore
|
295
|
+
lines = (File.exists?('.gitignore') ? File.readlines('.gitignore') : []).collect{|line| line.chomp}
|
296
|
+
lines.delete_if {|line| line == 'CHANGES' || line.include?('changes.xml')}
|
297
|
+
File.open('.gitignore', 'w') do | f |
|
298
|
+
lines.each do | line |
|
299
|
+
f << "#{line}\n"
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
def update_pom_dot_xml
|
305
|
+
return unless File.exists?('pom.xml')
|
306
|
+
xml = File.read('pom.xml')
|
307
|
+
doc = Document.new(xml)
|
308
|
+
doc.root.elements["version"].text = @options.new_version
|
309
|
+
File.open('pom.xml', 'w') do | f |
|
310
|
+
f << doc.to_s
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
def changes_dot_xml_header
|
315
|
+
v = %Q{<document>\n <properties>\n <title>#{@options.title}</title>\n </properties>\n <body>\n}
|
316
|
+
yield v if block_given?
|
317
|
+
v
|
318
|
+
end
|
319
|
+
|
320
|
+
def changes_dot_xml_footer
|
321
|
+
v = %Q{\n </body>\n</document>}
|
322
|
+
yield v if block_given?
|
323
|
+
v
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
class CommitSnapshot
|
328
|
+
ATTRIBUTES = [:commit_ref, :author, :email, :date, :messages]
|
329
|
+
attr_accessor(*ATTRIBUTES)
|
330
|
+
|
331
|
+
def initialize(*args)
|
332
|
+
if args[0].kind_of? Hash
|
333
|
+
ATTRIBUTES.each do | sym |
|
334
|
+
self.instance_variable_set "@#{sym}", args[0][sym]
|
335
|
+
end
|
336
|
+
if self.messages
|
337
|
+
self.messages = (self.messages.kind_of?(String) ? self.messages.split(/[;\n]/) : self.messages).delete_if{|e| e.empty?}
|
338
|
+
end
|
339
|
+
self.date = Time.parse( self.date ) if self.date && !self.date.kind_of?(Time)
|
340
|
+
else
|
341
|
+
commit = args[0]
|
342
|
+
initialize(:commit_ref => commit.id_abbrev, :author => commit.author.name, :email => commit.author.email, :date => commit.date, :messages => commit.message)
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
def formatted_date
|
347
|
+
self.date.strftime('%Y-%m-%d')
|
348
|
+
end
|
349
|
+
|
350
|
+
def formatted_for_changes_file
|
351
|
+
separator = ('-' * self.author.length) + '---------------------------'
|
352
|
+
each_message = self.messages.join("\n")
|
353
|
+
each_message.gsub!(/(.{1,80}|\S{81,})(?: +|$\n?)/, " \\1\n")
|
354
|
+
v = "#{separator}\n %s on %s, %s\n#{separator}\n%s\n\n" % [self.author, formatted_date, self.commit_ref[0...7], each_message]
|
355
|
+
yield v if block_given?
|
356
|
+
v
|
357
|
+
end
|
358
|
+
|
359
|
+
def formatted_for_changes_dot_xml_file
|
360
|
+
# <action dev=.. due-to=.. due-to-email=.. issue=.. type=.. system=.. date=.. >
|
361
|
+
template = " <action dev='%s' type='%s' date='%s'><![CDATA[%s: %s]]></action>\n"
|
362
|
+
reference = self.commit_ref[0...7]
|
363
|
+
v = self.messages.collect { | message_within_commit |
|
364
|
+
msg = message_within_commit.downcase
|
365
|
+
action_type = if !!(msg =~ /bug|fix/)
|
366
|
+
'fix'
|
367
|
+
elsif !!(msg =~ /update/)
|
368
|
+
'update'
|
369
|
+
elsif !!(msg =~ /remove/)
|
370
|
+
'remove'
|
371
|
+
else
|
372
|
+
'add'
|
373
|
+
end
|
374
|
+
|
375
|
+
template % [self.author, action_type, formatted_date, reference, message_within_commit]
|
376
|
+
}.join('')
|
377
|
+
yield v if block_given?
|
378
|
+
v
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
module Enumerable
|
383
|
+
# kudos to Piers Cawley: http://www.bofh.org.uk/2007/12/16/comprehensible-sorting-in-ruby
|
384
|
+
def sensible_sort
|
385
|
+
sort_by {|k| k.to_s.split(/((?:(?:^|\s)[-+])?(?:\.\d+|\d+(?:\.\d+?(?:[eE]\d+)?(?:$|(?![eE\.])))?))/ms).map {|v| Float(v) rescue v.downcase}}
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
if __FILE__ == $0
|
390
|
+
# Create and run the application
|
391
|
+
app = GrowthSpurt.new(ARGV, STDIN)
|
392
|
+
app.run
|
393
|
+
end
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jacaetevha-growthspurt
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jason Rogers
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-07-13 00:00:00 -07:00
|
13
|
+
default_executable: growthspurt
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: facets
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.5.2
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: grit
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.1.1
|
34
|
+
version:
|
35
|
+
description: ""
|
36
|
+
email: jacaetevha@gmail.com
|
37
|
+
executables:
|
38
|
+
- growthspurt
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- README.txt
|
43
|
+
files:
|
44
|
+
- History.txt
|
45
|
+
- Manifest.txt
|
46
|
+
- README.txt
|
47
|
+
- VERSION
|
48
|
+
- bin/growthspurt
|
49
|
+
- lib/growthspurt.rb
|
50
|
+
has_rdoc: true
|
51
|
+
homepage: http://github.com/jacaetevha/growth-spurt
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options:
|
54
|
+
- --charset=UTF-8
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
version:
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: "0"
|
68
|
+
version:
|
69
|
+
requirements: []
|
70
|
+
|
71
|
+
rubyforge_project:
|
72
|
+
rubygems_version: 1.2.0
|
73
|
+
signing_key:
|
74
|
+
specification_version: 2
|
75
|
+
summary: ""
|
76
|
+
test_files:
|
77
|
+
- test/test_growthspurt.rb
|