hitimes 1.3.0-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.md +57 -0
  3. data/HISTORY.md +124 -0
  4. data/LICENSE +16 -0
  5. data/Manifest.txt +44 -0
  6. data/README.md +200 -0
  7. data/Rakefile +28 -0
  8. data/examples/benchmarks.rb +113 -0
  9. data/examples/stats.rb +31 -0
  10. data/ext/hitimes/c/extconf.rb +24 -0
  11. data/ext/hitimes/c/hitimes.c +37 -0
  12. data/ext/hitimes/c/hitimes_instant_clock_gettime.c +28 -0
  13. data/ext/hitimes/c/hitimes_instant_osx.c +45 -0
  14. data/ext/hitimes/c/hitimes_instant_windows.c +27 -0
  15. data/ext/hitimes/c/hitimes_interval.c +370 -0
  16. data/ext/hitimes/c/hitimes_interval.h +73 -0
  17. data/ext/hitimes/c/hitimes_stats.c +269 -0
  18. data/ext/hitimes/c/hitimes_stats.h +30 -0
  19. data/ext/hitimes/java/src/hitimes/Hitimes.java +66 -0
  20. data/ext/hitimes/java/src/hitimes/HitimesInterval.java +176 -0
  21. data/ext/hitimes/java/src/hitimes/HitimesService.java +16 -0
  22. data/ext/hitimes/java/src/hitimes/HitimesStats.java +112 -0
  23. data/lib/hitimes.rb +66 -0
  24. data/lib/hitimes/2.0/hitimes.so +0 -0
  25. data/lib/hitimes/2.1/hitimes.so +0 -0
  26. data/lib/hitimes/2.2/hitimes.so +0 -0
  27. data/lib/hitimes/2.3/hitimes.so +0 -0
  28. data/lib/hitimes/2.4/hitimes.so +0 -0
  29. data/lib/hitimes/2.5/hitimes.so +0 -0
  30. data/lib/hitimes/metric.rb +118 -0
  31. data/lib/hitimes/mutexed_stats.rb +32 -0
  32. data/lib/hitimes/paths.rb +53 -0
  33. data/lib/hitimes/stats.rb +58 -0
  34. data/lib/hitimes/timed_metric.rb +176 -0
  35. data/lib/hitimes/timed_value_metric.rb +233 -0
  36. data/lib/hitimes/value_metric.rb +71 -0
  37. data/lib/hitimes/version.rb +8 -0
  38. data/spec/hitimes_spec.rb +24 -0
  39. data/spec/interval_spec.rb +136 -0
  40. data/spec/metric_spec.rb +28 -0
  41. data/spec/mutex_stats_spec.rb +36 -0
  42. data/spec/paths_spec.rb +11 -0
  43. data/spec/spec_helper.rb +11 -0
  44. data/spec/stats_spec.rb +98 -0
  45. data/spec/timed_metric_spec.rb +155 -0
  46. data/spec/timed_value_metric_spec.rb +171 -0
  47. data/spec/value_metric_spec.rb +108 -0
  48. data/spec/version_spec.rb +7 -0
  49. data/tasks/default.rake +242 -0
  50. data/tasks/extension.rake +38 -0
  51. data/tasks/this.rb +208 -0
  52. metadata +216 -0
@@ -0,0 +1,171 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hitimes::TimedValueMetric do
4
+ before( :each ) do
5
+ @tm = Hitimes::TimedValueMetric.new( 'test-timed-value-metric' )
6
+ end
7
+
8
+ it "knows if it is running or not" do
9
+ @tm.running?.must_equal false
10
+ @tm.start
11
+ @tm.running?.must_equal true
12
+ @tm.stop( 1 )
13
+ @tm.running?.must_equal false
14
+ end
15
+
16
+ it "#split returns the last duration and the timer is still running" do
17
+ @tm.start
18
+ d = @tm.split( 1 )
19
+ @tm.running?.must_equal true
20
+ d.must_be :>, 0
21
+ @tm.value_stats.count.must_equal 1
22
+ @tm.timed_stats.count.must_equal 1
23
+ @tm.duration.must_equal d
24
+ end
25
+
26
+ it "#stop returns false if called more than once in a row" do
27
+ @tm.start
28
+ @tm.stop( 1 ).must_be :>, 0
29
+ @tm.stop( 1 ).must_equal false
30
+ end
31
+
32
+ it "does not count a currently running interval as an interval in calculations" do
33
+ @tm.start
34
+ @tm.value_stats.count.must_equal 0
35
+ @tm.timed_stats.count.must_equal 0
36
+ @tm.split( 1 )
37
+ @tm.value_stats.count.must_equal 1
38
+ @tm.timed_stats.count.must_equal 1
39
+ end
40
+
41
+ it "#split called on a stopped timer does nothing" do
42
+ @tm.start
43
+ @tm.stop( 1 )
44
+ @tm.split( 1 ).must_equal false
45
+ end
46
+
47
+ it "calculates the mean of the durations" do
48
+ 3.times { |x| @tm.start ; sleep 0.05 ; @tm.stop(x) }
49
+ @tm.timed_stats.mean.must_be_close_to(0.05, 0.01)
50
+ @tm.value_stats.mean.must_equal 1.00
51
+ end
52
+
53
+ it "calculates the rate of the counts " do
54
+ 5.times { |x| @tm.start ; sleep 0.05 ; @tm.stop( x ) }
55
+ @tm.rate.must_be_close_to(40.0, 1.0)
56
+ end
57
+
58
+
59
+ it "calculates the stddev of the durations" do
60
+ 3.times { |x| @tm.start ; sleep(0.05 * x) ; @tm.stop(x) }
61
+ @tm.timed_stats.stddev.must_be_close_to(0.05, 0.001)
62
+ @tm.value_stats.stddev.must_equal 1.0
63
+ end
64
+
65
+ it "returns 0.0 for stddev if there is no data" do
66
+ @tm.timed_stats.stddev.must_equal 0.0
67
+ @tm.value_stats.stddev.must_equal 0.0
68
+ end
69
+
70
+ it "keeps track of the min value" do
71
+ 3.times { |x| @tm.start ; sleep 0.05 ; @tm.stop( x ) }
72
+ @tm.timed_stats.min.must_be_close_to( 0.05, 0.003 )
73
+ @tm.value_stats.min.must_equal 0
74
+ end
75
+
76
+ it "keeps track of the max value" do
77
+ 3.times { |x| @tm.start ; sleep 0.05 ; @tm.stop( x ) }
78
+ @tm.timed_stats.max.must_be_close_to( 0.05, 0.003 )
79
+ @tm.value_stats.max.must_equal 2
80
+ end
81
+
82
+ it "keeps track of the sum value" do
83
+ 3.times { |x| @tm.start ; sleep 0.05 ; @tm.stop( x ) }
84
+ @tm.timed_stats.sum.must_be_close_to( 0.15, 0.01 )
85
+ @tm.value_stats.sum.must_equal 3
86
+ end
87
+
88
+ it "keeps track of the sum of squares value" do
89
+ 3.times { |x| @tm.start ; sleep 0.05 ; @tm.stop( x ) }
90
+ @tm.timed_stats.sumsq.must_be_close_to(0.0075, 0.0005)
91
+ @tm.value_stats.sumsq.must_equal 5
92
+ end
93
+
94
+ it "keeps track of the minimum start time of all the intervals" do
95
+ f1 = Time.now.gmtime.to_f * 1000000
96
+ 5.times { @tm.start ; sleep 0.05 ; @tm.stop( 1 ) }
97
+ f2 = Time.now.gmtime.to_f * 1000000
98
+ @tm.sampling_start_time.must_be :>=, f1
99
+ @tm.sampling_start_time.must_be :<, f2
100
+ # distance from now to start time should be greater than the distance from
101
+ # the start to the min start_time
102
+ (f2 - @tm.sampling_start_time).must_be :>, ( @tm.sampling_start_time - f1 )
103
+ end
104
+
105
+ it "keeps track of the last stop time of all the intervals" do
106
+ f1 = Time.now.gmtime.to_f * 1_000_000
107
+ 5.times { @tm.start ; sleep 0.05 ; @tm.stop( 1 ) }
108
+ sleep 0.05
109
+ f2 = Time.now.gmtime.to_f * 1_000_000
110
+ @tm.sampling_stop_time.must_be :>, f1
111
+ @tm.sampling_stop_time.must_be :<=, f2
112
+ # distance from now to max stop time time should be less than the distance
113
+ # from the start to the max stop time
114
+ (f2 - @tm.sampling_stop_time).must_be :<, ( @tm.sampling_stop_time - f1 )
115
+ end
116
+
117
+ it "can create an already running timer" do
118
+ t = Hitimes::TimedValueMetric.now( 'already-running' )
119
+ t.running?.must_equal true
120
+ end
121
+
122
+ it "can measure a block of code from an instance" do
123
+ t = Hitimes::TimedValueMetric.new( 'measure a block' )
124
+ 3.times { t.measure( 1 ) { sleep 0.05 } }
125
+ t.duration.must_be_close_to(0.15, 0.004)
126
+ t.timed_stats.count.must_equal 3
127
+ t.value_stats.count.must_equal 3
128
+ end
129
+
130
+ it "returns the value of the block when measuring" do
131
+ t = Hitimes::TimedValueMetric.new( 'measure a block' )
132
+ x = t.measure( 42 ) { sleep 0.05; 42 }
133
+ t.duration.must_be_close_to(0.05, 0.002)
134
+ x.must_equal 42
135
+ end
136
+
137
+ describe "#to_hash" do
138
+
139
+ it "has name value" do
140
+ h = @tm.to_hash
141
+ h['name'].must_equal "test-timed-value-metric"
142
+ end
143
+
144
+ it "has an empty has for additional_data" do
145
+ h = @tm.to_hash
146
+ h['additional_data'].must_equal Hash.new
147
+ h['additional_data'].size.must_equal 0
148
+ end
149
+
150
+ it "has a rate" do
151
+ 5.times { |x| @tm.start ; sleep 0.05 ; @tm.stop( x ) }
152
+ h = @tm.to_hash
153
+ h['rate'].must_be_close_to(40.0, 1.0)
154
+ end
155
+
156
+ it "has a unit_count" do
157
+ 5.times { |x| @tm.start ; sleep 0.05 ; @tm.stop( x ) }
158
+ h = @tm.to_hash
159
+ h['unit_count'].must_equal 10
160
+ end
161
+
162
+ fields = %w[ name additional_data sampling_start_time sampling_stop_time value_stats timed_stats rate unit_count ]
163
+ fields.each do |f|
164
+ it "has a value for #{f}" do
165
+ 3.times { |x| @tm.measure(x) { sleep 0.001 } }
166
+ h = @tm.to_hash
167
+ h[f].wont_be_nil
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hitimes::ValueMetric do
4
+ before( :each ) do
5
+ @metric = Hitimes::ValueMetric.new( "testing" )
6
+ 10.times { |x| @metric.measure( x ) }
7
+ end
8
+
9
+ it 'has a name' do
10
+ @metric.name.must_equal "testing"
11
+ end
12
+
13
+ it "has associated data from initialization" do
14
+ m = Hitimes::ValueMetric.new( "more-data", 'foo' => 'bar', 'this' => 'that' )
15
+ m.additional_data['foo'].must_equal 'bar'
16
+ m.additional_data['this'].must_equal 'that'
17
+
18
+ m = Hitimes::ValueMetric.new( "more-data", { 'foo' => 'bar', 'this' => 'that' } )
19
+ m.additional_data['foo'].must_equal 'bar'
20
+ m.additional_data['this'].must_equal 'that'
21
+ end
22
+
23
+ it "calculates the mean of the measurements" do
24
+ @metric.mean.must_equal 4.5
25
+ end
26
+
27
+ it "calculates the stddev of the measurements" do
28
+ @metric.stddev.must_be :>, 0.0
29
+ end
30
+
31
+ it "returns 0.0 for stddev if there is no data" do
32
+ m = Hitimes::ValueMetric.new('0-data')
33
+ m.stddev.must_equal 0.0
34
+ end
35
+
36
+ it "keeps track of the sum of data" do
37
+ @metric.sum.must_equal 45.0
38
+ end
39
+
40
+ it "keeps track of the sum of squars of data" do
41
+ @metric.sumsq.must_equal 285.0
42
+ end
43
+
44
+ it "retuns 0.0 for mean if there is no data" do
45
+ Hitimes::ValueMetric.new('0-data').mean.must_equal 0.0
46
+ end
47
+
48
+ it "keeps track of the min value" do
49
+ @metric.min.must_equal 0
50
+ end
51
+
52
+ it "keeps track of the max value" do
53
+ @metric.max.must_equal 9
54
+ end
55
+
56
+ it "keeps track of the first start time of all the measurements" do
57
+ m = Hitimes::ValueMetric.new( "first-start-time" )
58
+ f1 = Time.now.gmtime.to_f * 1_000_000
59
+ 10.times{ |x| m.measure( x ); sleep 0.1 }
60
+ f2 = Time.now.gmtime.to_f * 1_000_000
61
+ m.sampling_start_time.must_be :>=, f1
62
+ m.sampling_start_time.must_be :<, f2
63
+ # distance from now to start time should be greater than the distance from
64
+ # the start to the min start_time
65
+ (f2 - m.sampling_start_time).must_be :>, ( m.sampling_start_time - f1 )
66
+ end
67
+
68
+ it "keeps track of the last stop time of all the intervals" do
69
+ m = Hitimes::ValueMetric.new( "last-stop-time" )
70
+ f1 = Time.now.gmtime.to_f * 1_000_000
71
+ 10.times {|x| m.measure( x ); sleep 0.1 }
72
+ f2 = Time.now.gmtime.to_f * 1_000_000
73
+ m.sampling_stop_time.must_be :>, f1
74
+ m.sampling_stop_time.must_be :<=, f2
75
+ # distance from now to max stop time time should be less than the distance
76
+ # from the start to the max stop time
77
+ (f2 - m.sampling_stop_time).must_be :<, ( m.sampling_stop_time - f1 )
78
+ end
79
+
80
+ describe "#to_hash" do
81
+
82
+ it "has name value" do
83
+ h = @metric.to_hash
84
+ h['name'].must_equal "testing"
85
+ end
86
+
87
+ it "has an empty has for additional_data" do
88
+ h = @metric.to_hash
89
+ h['additional_data'].must_equal Hash.new
90
+ h['additional_data'].size.must_equal 0
91
+ end
92
+
93
+ it "has the right sum" do
94
+ h = @metric.to_hash
95
+ h['sum'].must_equal 45
96
+ end
97
+
98
+ fields = ::Hitimes::Stats::STATS.dup + %w[ name additional_data sampling_start_time sampling_stop_time ]
99
+ fields = fields - [ 'rate' ]
100
+ fields.each do |f|
101
+ it "has a value for #{f}" do
102
+ h = @metric.to_hash
103
+ h[f].wont_be_nil
104
+ end
105
+ end
106
+ end
107
+ end
108
+
@@ -0,0 +1,7 @@
1
+ require "spec_helper"
2
+
3
+ describe "Hitimes::Version" do
4
+ it "should be accessable as a constant" do
5
+ Hitimes::VERSION.must_match(/\d+\.\d+\.\d+/)
6
+ end
7
+ end
@@ -0,0 +1,242 @@
1
+ # vim: syntax=ruby
2
+ require 'rake/clean'
3
+ require 'digest'
4
+ #------------------------------------------------------------------------------
5
+ # If you want to Develop on this project just run 'rake develop' and you'll
6
+ # have all you need to get going. If you want to use bundler for development,
7
+ # then run 'rake develop:using_bundler'
8
+ #------------------------------------------------------------------------------
9
+ namespace :develop do
10
+
11
+ # Install all the development and runtime dependencies of this gem using the
12
+ # gemspec.
13
+ task :default => 'Gemfile' do
14
+ require 'rubygems/dependency_installer'
15
+ installer = ::Gem::DependencyInstaller.new
16
+ puts "Installing bundler..."
17
+ installer.install 'bundler'
18
+ sh 'bundle install'
19
+ puts "\n\nNow run 'rake test'"
20
+ end
21
+
22
+ # Create a Gemfile that just references the gemspec
23
+ file 'Gemfile' => :gemspec do
24
+ File.open( "Gemfile", "w+" ) do |f|
25
+ f.puts "# DO NOT EDIT - This file is automatically generated"
26
+ f.puts "# Make changes to Manifest.txt and/or Rakefile and regenerate"
27
+ f.puts 'source "https://rubygems.org"'
28
+ f.puts 'gemspec'
29
+ end
30
+ end
31
+ end
32
+ desc "Bootstrap development"
33
+ task :develop => "develop:default"
34
+
35
+ #------------------------------------------------------------------------------
36
+ # Minitest - standard TestTask
37
+ #------------------------------------------------------------------------------
38
+ begin
39
+ require 'rake/testtask'
40
+ Rake::TestTask.new( :test ) do |t|
41
+ t.ruby_opts = %w[ -w ]
42
+ t.libs = %w[ lib spec test ]
43
+ t.pattern = "{test,spec}/**/{test_*,*_spec}.rb"
44
+ end
45
+
46
+ task :test_requirements
47
+ task :test => :test_requirements
48
+ task :default => :test
49
+ rescue LoadError
50
+ This.task_warning( 'test' )
51
+ end
52
+
53
+ #------------------------------------------------------------------------------
54
+ # RDoc - standard rdoc rake task, although we must make sure to use a more
55
+ # recent version of rdoc since it is the one that has 'tomdoc' markup
56
+ #------------------------------------------------------------------------------
57
+ begin
58
+ gem 'rdoc' # otherwise we get the wrong task from stdlib
59
+ require 'rdoc/task'
60
+ RDoc::Task.new do |t|
61
+ t.markup = 'tomdoc'
62
+ t.rdoc_dir = 'doc'
63
+ t.main = 'README.md'
64
+ t.title = "#{This.name} #{This.version}"
65
+ t.rdoc_files.include( FileList['*.{rdoc,md,txt}'], FileList['ext/**/*.c'],
66
+ FileList['lib/**/*.rb'] )
67
+ end
68
+ rescue StandardError, LoadError
69
+ This.task_warning( 'rdoc' )
70
+ end
71
+
72
+ #------------------------------------------------------------------------------
73
+ # Coverage - optional code coverage, rcov for 1.8 and simplecov for 1.9, so
74
+ # for the moment only rcov is listed.
75
+ #------------------------------------------------------------------------------
76
+ begin
77
+ require 'simplecov'
78
+ desc 'Run tests with code coverage'
79
+ task :coverage do
80
+ ENV['COVERAGE'] = 'true'
81
+ Rake::Task[:test].execute
82
+ end
83
+ CLOBBER << 'coverage' if File.directory?( 'coverage' )
84
+ rescue LoadError
85
+ This.task_warning( 'simplecov' )
86
+ end
87
+
88
+ #------------------------------------------------------------------------------
89
+ # Manifest - We want an explicit list of thos files that are to be packaged in
90
+ # the gem. Most of this is from Hoe.
91
+ #------------------------------------------------------------------------------
92
+ namespace 'manifest' do
93
+ desc "Check the manifest"
94
+ task :check => :clean do
95
+ files = FileList["**/*", ".*"].exclude( This.exclude_from_manifest ).to_a.sort
96
+ files = files.select{ |f| File.file?( f ) }
97
+
98
+ tmp = "Manifest.tmp"
99
+ File.open( tmp, 'w' ) do |f|
100
+ f.puts files.join("\n")
101
+ end
102
+
103
+ begin
104
+ sh "diff -du Manifest.txt #{tmp}"
105
+ ensure
106
+ rm tmp
107
+ end
108
+ puts "Manifest looks good"
109
+ end
110
+
111
+ desc "Generate the manifest"
112
+ task :generate => :clean do
113
+ files = %x[ git ls-files ].split("\n").sort
114
+ files.reject! { |f| f =~ This.exclude_from_manifest }
115
+ File.open( "Manifest.txt", "w" ) do |f|
116
+ f.puts files.join("\n")
117
+ end
118
+ end
119
+ end
120
+
121
+ #------------------------------------------------------------------------------
122
+ # Fixme - look for fixmes and report them
123
+ #------------------------------------------------------------------------------
124
+ namespace :fixme do
125
+ task :default => 'manifest:check' do
126
+ This.manifest.each do |file|
127
+ next if file == __FILE__
128
+ next unless file =~ %r/(txt|rb|md|rdoc|css|html|xml|css)\Z/
129
+ puts "FIXME: Rename #{file}" if file =~ /fixme/i
130
+ IO.readlines( file ).each_with_index do |line, idx|
131
+ prefix = "FIXME: #{file}:#{idx+1}".ljust(42)
132
+ puts "#{prefix} => #{line.strip}" if line =~ /fixme/i
133
+ end
134
+ end
135
+ end
136
+
137
+ def fixme_project_root
138
+ This.project_path( '../fixme' )
139
+ end
140
+
141
+ def fixme_project_path( subtree )
142
+ fixme_project_root.join( subtree )
143
+ end
144
+
145
+ def local_fixme_files
146
+ This.manifest.select { |p| p =~ %r|^tasks/| }
147
+ end
148
+
149
+ def outdated_fixme_files
150
+ local_fixme_files.select do |local|
151
+ upstream = fixme_project_path( local )
152
+ upstream.exist? &&
153
+ ( Digest::SHA256.file( local ) != Digest::SHA256.file( upstream ) )
154
+ end
155
+ end
156
+
157
+ def fixme_up_to_date?
158
+ outdated_fixme_files.empty?
159
+ end
160
+
161
+ desc "See if the fixme tools are outdated"
162
+ task :outdated => :release_check do
163
+ if fixme_up_to_date? then
164
+ puts "Fixme files are up to date."
165
+ else
166
+ outdated_fixme_files.each do |f|
167
+ puts "#{f} is outdated"
168
+ end
169
+ end
170
+ end
171
+
172
+ desc "Update outdated fixme files"
173
+ task :update => :release_check do
174
+ if fixme_up_to_date? then
175
+ puts "Fixme files are already up to date."
176
+ else
177
+ puts "Updating fixme files:"
178
+ outdated_fixme_files.each do |local|
179
+ upstream = fixme_project_path( local )
180
+ puts " * #{local}"
181
+ FileUtils.cp( upstream, local )
182
+ end
183
+ puts "Use your git commands as appropriate."
184
+ end
185
+ end
186
+ end
187
+ desc "Look for fixmes and report them"
188
+ task :fixme => "fixme:default"
189
+
190
+ #------------------------------------------------------------------------------
191
+ # Gem Specification
192
+ #------------------------------------------------------------------------------
193
+ # Really this is only here to support those who use bundler
194
+ desc "Build the #{This.name}.gemspec file"
195
+ task :gemspec do
196
+ File.open( This.gemspec_file, "wb+" ) do |f|
197
+ f.puts "# DO NOT EDIT - This file is automatically generated"
198
+ f.puts "# Make changes to Manifest.txt and/or Rakefile and regenerate"
199
+ f.write This.platform_gemspec.to_ruby
200
+ end
201
+ end
202
+
203
+ # .rbc files from ruby 2.0
204
+ CLOBBER << FileList["**/*.rbc"]
205
+
206
+ # The standard gem packaging task, everyone has it.
207
+ require 'rubygems/package_task'
208
+ ::Gem::PackageTask.new( This.platform_gemspec ) do
209
+ # nothing
210
+ end
211
+
212
+ #------------------------------------------------------------------------------
213
+ # Release - the steps we go through to do a final release, this is pulled from
214
+ # a compbination of mojombo's rakegem, hoe and hoe-git
215
+ #
216
+ # 1) make sure we are on the master branch
217
+ # 2) make sure there are no uncommitted items
218
+ # 3) check the manifest and make sure all looks good
219
+ # 4) build the gem
220
+ # 5) do an empty commit to have the commit message of the version
221
+ # 6) tag that commit as the version
222
+ # 7) push master
223
+ # 8) push the tag
224
+ # 7) pus the gem
225
+ #------------------------------------------------------------------------------
226
+ task :release_check do
227
+ unless `git branch` =~ /^\* master$/
228
+ abort "You must be on the master branch to release!"
229
+ end
230
+ unless `git status` =~ /^nothing to commit/m
231
+ abort "Nope, sorry, you have unfinished business"
232
+ end
233
+ end
234
+
235
+ desc "Create tag v#{This.version}, build and push #{This.platform_gemspec.full_name} to rubygems.org"
236
+ task :release => [ :release_check, 'manifest:check', :gem ] do
237
+ sh "git commit --allow-empty -a -m 'Release #{This.version}'"
238
+ sh "git tag -a -m 'v#{This.version}' v#{This.version}"
239
+ sh "git push origin master"
240
+ sh "git push origin v#{This.version}"
241
+ sh "gem push pkg/#{This.platform_gemspec.full_name}.gem"
242
+ end