Class: BumperPusher::Bumper

Inherits:
Object
  • Object
show all
Defined in:
lib/bumper_pusher/bumper.rb

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Bumper

Returns a new instance of Bumper.



13
14
15
16
# File 'lib/bumper_pusher/bumper.rb', line 13

def initialize(options)
  @options = options
  @spec_file = find_spec_file
end

Instance Method Details

#ask_sure_yObject



195
196
197
198
199
200
201
202
203
204
# File 'lib/bumper_pusher/bumper.rb', line 195

def ask_sure_y
  unless @options[:dry_run]
    puts 'Are you sure? Press Y to continue:'
    str = gets.chomp
    if str != 'Y'
      puts '-> exit'
      exit
    end
  end
end

#ask_to_mergeObject



391
392
393
394
395
396
397
398
399
400
401
402
# File 'lib/bumper_pusher/bumper.rb', line 391

def ask_to_merge
  puts 'Automatic merge failed, please open new terminal, resolve conflicts, then press Y. Or press N to terminate'
  str = ''
  while str != 'Y' && str != 'N'
    str = gets.chomp
    puts str
  end
  if str == 'N'
    puts '-> exit'
    exit
  end
end

#bump_version(versions_array) ⇒ Object



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/bumper_pusher/bumper.rb', line 163

def bump_version(versions_array)
  bumped_result = versions_array.dup
  bumped_result.map! { |x| x.to_i }

  if @options[:beta]
    bumped_version = versions_array.join('.') + '.1'
  else
    case @options[:bump_number]
      when :major
        bumped_result[0] += 1
        bumped_result[1] = 0
        bumped_result[2] = 0
      when :minor
        bumped_result[1] += 1
        bumped_result[2] = 0
      when :patch
        bumped_result[2] += 1
      else
        raise('unknown bump_number')
    end
    bumped_version = bumped_result.join('.')
  end

  puts "Bump version: #{versions_array.join('.')} -> #{bumped_version}"

  unless @options[:dry_run] || @options[:beta]
    ask_sure_y
  end

  bumped_version
end

#check_exit_status(output) ⇒ Object



267
268
269
270
271
272
# File 'lib/bumper_pusher/bumper.rb', line 267

def check_exit_status(output)
  if $?.exitstatus != 0
    puts "Output:\n#{output}\nExit status = #{$?.exitstatus} ->Terminate script."
    exit
  end
end

#check_repo_is_clean_or_dry_runObject



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
# File 'lib/bumper_pusher/bumper.rb', line 18

def check_repo_is_clean_or_dry_run
  value =%x[#{'git status --porcelain'}]

  if value.empty?
    puts 'Repo is clean -> continue'
  else
    if @options[:dry_run]
      puts 'Repo not clean, "Dry run" enabled -> continue'
    else
      if @options[:beta]
        puts 'Repo not clean, "Beta build" enabled -> continue'
      else
        puts 'Repository not clean -> exit'
        exit
      end
    end
  end

  current_branch = get_current_branch

  unless @options[:beta]

    if is_git_flow_installed
      # supposed, that with git flow you should release from develop branch
      if current_branch != 'develop' && !is_branch_hotfix?
        puts "Warning: You're in branch (#{current_branch})!".yellow
        ask_sure_y
      end
    else
      # supposed, that w/o git flow you should release from master or release branch
      if current_branch != 'master' || !/release/.match(current_branch)[0].nil?
        puts "Warning: You're in branch (#{current_branch})!".yellow
        ask_sure_y
      end
    end

  end
end

#execute_interactive_if_not_dry_run(cmd) ⇒ Object



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/bumper_pusher/bumper.rb', line 232

def execute_interactive_if_not_dry_run(cmd)
  if @options[:dry_run]
    puts "Dry run: #{cmd}"
    nil
  else
    Open3.popen3(cmd) do |i, o, e, th|
      Thread.new {
        until i.closed? do
          input =Readline.readline("", true).strip
          i.puts input
        end
      }

      t_err = Thread.new {
        until e.eof? do
          putc e.readchar
        end
      }

      t_out = Thread.new {
        until o.eof? do
          putc o.readchar
        end
      }

      Process::waitpid(th.pid) rescue nil
      # "rescue nil" is there in case process already ended.

      t_err.join
      t_out.join
    end
  end
end

#execute_line(line) ⇒ Object



206
207
208
209
210
211
# File 'lib/bumper_pusher/bumper.rb', line 206

def execute_line(line)
  output = `#{line}`
  check_exit_status(output)

  output
end

#execute_line_if_not_dry_run(line, check_exit = true) ⇒ Object

Parameters:

  • line (Object)
  • check_exit (Object) (defaults to: true)


215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/bumper_pusher/bumper.rb', line 215

def execute_line_if_not_dry_run(line, check_exit = true)
  if @options[:dry_run]
    puts "Dry run: #{line}"
    check_exit ? nil : 0
  else
    puts line
    value = %x[#{line}]
    if check_exit
      puts value
      check_exit_status(value)
      value
    else
      $?.exitstatus
    end
  end
end

#find_current_gem_fileObject



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/bumper_pusher/bumper.rb', line 115

def find_current_gem_file
  list_of_specs = execute_line("find . -name '*.gem' -maxdepth 1")
  arr = list_of_specs.split("\n")

  spec_file = ''

  case arr.count
    when 0
      if @options[:dry_run]
        return "test.#{POD_SPEC_TYPE}"
      end
      puts "No #{POD_SPEC_TYPE} files found. -> Exit."
      exit
    when 1
      spec_file = arr[0]
    else
      puts 'Which spec should be used?'
      arr.each_with_index { |file, index| puts "#{index+1}. #{file}" }
      input_index = Integer(gets.chomp)
      spec_file = arr[input_index-1]
  end

  if spec_file == nil
    puts "Can't find specified spec file -> exit"
    exit
  end

  spec_file.sub('./', '')

end

#find_spec_fileObject



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
100
101
102
103
104
105
106
107
108
109
# File 'lib/bumper_pusher/bumper.rb', line 62

def find_spec_file

  pod_arr = execute_line("find . -name '*.#{POD_SPEC_TYPE}'  -maxdepth 1").split("\n")
  gem_arr = execute_line("find . -name '*.#{GEM_SPEC_TYPE}' -maxdepth 1").split("\n")
  if gem_arr.any? && pod_arr.any?
    puts 'Warning: both podspec and gemspec found!'.yellow
  end
  all_specs = gem_arr | pod_arr

  spec_file = ''

  case all_specs.count
    when 0
      puts 'No spec files found. -> Exit.'
      if is_debug?
        puts 'Debug -> set @spec_mode to gem -> continue'
        @spec_mode = GEM_SPEC_TYPE
      else
        exit
      end
    when 1
      spec_file = all_specs[0]
    else
      puts 'Which spec should be used?'
      all_specs.each_with_index { |file, index| puts "#{index+1}. #{file}" }
      input_index = Integer(gets.chomp)
      spec_file = all_specs[input_index-1]
  end

  if spec_file == nil
    puts "Can't find specified spec file -> exit"
    exit
  end

  if gem_arr.include?(spec_file)
    @spec_mode = GEM_SPEC_TYPE
  else
    if pod_arr.include?(spec_file)
      @spec_mode = POD_SPEC_TYPE
    else

    end

  end

  spec_file.sub('./', '')

end

#find_version_fileObject



404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
# File 'lib/bumper_pusher/bumper.rb', line 404

def find_version_file
  version_file = nil
  arr = `find . -name 'version.rb'  -maxdepth 4`.split("\n")
  case arr.count
    when 0
      puts "version.rb file not found"
    when 1
      puts "version.rb file found (#{arr[0]}) -> bump this file"
      version_file = arr[0]
    else
      puts 'More than 1 version.rb file found. -> skip'
  end

  version_file ? version_file.sub('./', '') : @spec_file
end

#find_version_in_file(podspec) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/bumper_pusher/bumper.rb', line 146

def find_version_in_file(podspec)
  readme = File.read(podspec)

  #try to find version in format 1.22.333
  re = /(\d+)\.(\d+)\.(\d+)/m

  match_result = re.match(readme)

  unless match_result
    puts 'Not found any versions'
    exit
  end

  puts "Found version #{match_result[0]}"
  return match_result[0], match_result.captures
end

#get_current_branchObject



57
58
59
# File 'lib/bumper_pusher/bumper.rb', line 57

def get_current_branch
  `git rev-parse --abbrev-ref HEAD`.strip!
end

#is_branch_hotfix?Boolean

Returns:

  • (Boolean)


439
440
441
442
# File 'lib/bumper_pusher/bumper.rb', line 439

def is_branch_hotfix?
  branch = get_current_branch
  branch.include? 'hotfix'
end

#is_debug?Boolean

Returns:

  • (Boolean)


111
112
113
# File 'lib/bumper_pusher/bumper.rb', line 111

def is_debug?
  (ENV['RUBYLIB'] =~ /ruby-debug-ide/) ? true : false
end

#is_git_flow_installedObject



435
436
437
# File 'lib/bumper_pusher/bumper.rb', line 435

def is_git_flow_installed
  system('git flow version') ? true : false
end

#revert_last_bumpObject



420
421
422
423
424
425
426
427
428
429
430
431
432
433
# File 'lib/bumper_pusher/bumper.rb', line 420

def revert_last_bump
  spec_file = @spec_file
  result, _ = find_version_in_file(spec_file)

  puts "DELETE tag #{result} and HARD reset HEAD~1?\nPress Y to continue:"
  str = gets.chomp
  if str != 'Y'
    puts '-> exit'
    exit
  end
  execute_line_if_not_dry_run("git tag -d #{result}")
  execute_line_if_not_dry_run('git reset --hard HEAD~1')
  execute_line_if_not_dry_run("git push --delete origin #{result}")
end

#run_bumping_scriptObject



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/bumper_pusher/bumper.rb', line 274

def run_bumping_script

  check_repo_is_clean_or_dry_run

  unless @options[:beta]
    unless is_branch_hotfix?
      execute_line_if_not_dry_run('git pull')
    end
    current_branch = get_current_branch
    execute_line_if_not_dry_run("git checkout master && git pull && git checkout #{current_branch}")
    execute_line_if_not_dry_run('git pull --all')
    execute_line_if_not_dry_run('git push --all')
  end

  version_file = find_version_file
  result, versions_array = find_version_in_file(version_file)
  bumped_version = bump_version(versions_array)


  unless @options[:beta]
    execute_line_if_not_dry_run('git push --all')
    if is_git_flow_installed && !is_branch_hotfix?
      execute_line_if_not_dry_run("git flow release start #{bumped_version}")
    end
  end

  if @options[:bump]
    execute_line_if_not_dry_run("sed -i \"\" \"s/#{result}/#{bumped_version}/\" README.md")
    execute_line_if_not_dry_run("sed -i \"\" \"s/#{result}/#{bumped_version}/\" #{version_file}")
  end

  if @options[:commit]
    execute_line_if_not_dry_run("git commit --all -m \"Update #{@spec_mode} to version #{bumped_version}\"")

    if is_git_flow_installed
      if is_branch_hotfix?
        branch_split = get_current_branch.split('/').last
        unless execute_line_if_not_dry_run("git flow hotfix finish -n #{branch_split}", check_exit = false) == 0
          ask_to_merge
          execute_line_if_not_dry_run("git flow hotfix finish -n #{branch_split}")
        end
      else
        unless execute_line_if_not_dry_run("git flow release finish -n #{bumped_version}", check_exit = false) == 0
          ask_to_merge
          execute_line_if_not_dry_run("git flow release finish -n #{bumped_version}")
        end
      end
      execute_line_if_not_dry_run('git checkout master')
    end
    execute_line_if_not_dry_run('git push --all')
    execute_line_if_not_dry_run("git tag #{bumped_version}")
  end

  if @options[:push]
    execute_line_if_not_dry_run('git push --all')
    execute_line_if_not_dry_run('git push --tags')


    if @spec_mode == POD_SPEC_TYPE
      execute_line_if_not_dry_run("pod trunk push #{@spec_file}")
    else
      if @spec_mode == GEM_SPEC_TYPE
        execute_line_if_not_dry_run("gem build #{@spec_file}")
        gem = find_current_gem_file
        execute_line_if_not_dry_run("gem push #{gem}")

        if @options[:install]
          execute_line_if_not_dry_run("gem install #{gem}")
        end

        execute_line_if_not_dry_run("rm #{gem}")
      else
        raise 'Unknown spec type'
      end
    end
  end

  if @options[:beta]
    if @spec_mode == GEM_SPEC_TYPE
      execute_line_if_not_dry_run("gem build #{@spec_file}")
      gem = find_current_gem_file
      execute_interactive_if_not_dry_run("gem install #{gem}")

      execute_line_if_not_dry_run("sed -i \"\" \"s/#{bumped_version}/#{result}/\" README.md")
      execute_line_if_not_dry_run("sed -i \"\" \"s/#{bumped_version}/#{result}/\" #{version_file}")
      execute_line_if_not_dry_run("rm #{gem}")
    else
      raise 'Unknown spec type'
    end
  end


  if @options[:changelog] && !@options[:beta]
    if `which github_changelog_generator`.empty?
      puts 'Cancelled bumping: no github_changelog_generator gem found'
    else

      if is_git_flow_installed
        execute_line_if_not_dry_run('git flow hotfix start update-changelog')
      end
      execute_line_if_not_dry_run('github_changelog_generator')
      execute_line_if_not_dry_run("git commit CHANGELOG.md -m \"Update changelog for version #{bumped_version}\"")
      if is_git_flow_installed
        unless execute_line_if_not_dry_run('git flow hotfix finish -n update-changelog', check_exit = false) == 0
          ask_to_merge
          execute_line_if_not_dry_run('git flow hotfix finish -n update-changelog')
        end
        execute_line_if_not_dry_run("git push && git checkout master && git push && git checkout #{get_current_branch}")
      else
        execute_line_if_not_dry_run('git push')
      end

    end
  end

end