Class: AllegroRelease::Bump

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

Constant Summary collapse

BUMPS =
%w(major minor patch)
OPTIONS =
BUMPS | ["current", "to_master", "finish"]
VERSION_REGEX =
/(\d+\.\d+\.\d+)/

Class Method Summary collapse

Class Method Details

.add_tagObject



54
55
56
57
58
# File 'lib/allegro_release.rb', line 54

def self.add_tag
  puts "Adding tag #{version_from_file} and pushing to origin.".colorize(:green)
  system_cmd("git tag #{version_from_file}")
  system_cmd("git push origin #{version_from_file}")
end

.bump(current, next_version, options) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
# File 'lib/allegro_release.rb', line 86

def self.bump(current, next_version, options)
  checkout_develop
  create_release_branch(next_version)
  replace(current, next_version)
  update_changelog(next_version)
  check_podspec
  commit_release(next_version)
  push_changes_to_remote_branch(next_version)
  create_pull_request_to_develop(next_version)
  puts "First step is done! Now head to HipChat and paste the content of clipboard that contains link to pull request. After manual merge perform `allegro_release to_master`.\n".colorize(:green) + "Do not delete local release_#{version_from_file} branch, because it will be used to merge to master branch.".colorize(:red)
end

.bump_part(part, options) ⇒ Object



211
212
213
214
215
# File 'lib/allegro_release.rb', line 211

def self.bump_part(part, options)
  current = version_from_file
  next_version = next_version(current, part)
  bump(current, next_version, options)
end

.check_if_repo_cleanObject



232
233
234
235
236
237
238
239
240
# File 'lib/allegro_release.rb', line 232

def self.check_if_repo_clean
  repo_clean = `git status --porcelain`.empty?
  if repo_clean
    puts "Repository is clean, continuing...".colorize(:green)
  else
    puts "Repository is dirty. Please ensure the repo is in a clean state by commiting/stashing/discarding all changes first.".colorize(:red)
    raise RepoNotClean
  end
end

.check_podspecObject



242
243
244
245
# File 'lib/allegro_release.rb', line 242

def self.check_podspec
  puts "Validating #{spec_file}.".colorize(:green)
  system_cmd("pod lib lint --sources='https://stash.allegrogroup.com/scm/iostools/pods.specs.git,https://github.com/CocoaPods/Specs' --allow-warnings #{spec_file}")
end

.checkout_developObject



169
170
171
172
173
174
# File 'lib/allegro_release.rb', line 169

def self.checkout_develop
  return unless File.directory?(".git")
  puts "Pulling current develop branch.".colorize(:green)
  system_cmd("git checkout develop")
  system_cmd("git pull")
end

.checkout_masterObject



47
48
49
50
51
52
# File 'lib/allegro_release.rb', line 47

def self.checkout_master
  puts "Pulling current master branch.".colorize(:green)
  return unless File.directory?(".git")
  system_cmd("git checkout master")
  system_cmd("git pull")
end

.checkout_releaseObject



176
177
178
179
180
# File 'lib/allegro_release.rb', line 176

def self.checkout_release
  return unless File.directory?(".git")
  puts "Checking out release_#{version_from_file} branch.".colorize(:green)
  system_cmd("git checkout release_#{version_from_file}")
end

.commit(jira_id, version) ⇒ Object



182
183
184
185
186
187
188
# File 'lib/allegro_release.rb', line 182

def self.commit(jira_id, version)
  return unless File.directory?(".git")
  commit_message = "'[#{jira_id}] Release #{version}.'"
  puts "Committing changes with message #{commit_message}.".colorize(:green)
  system_cmd("git add --all")
  system_cmd("git commit -m #{commit_message}")
end

.commit_release(version) ⇒ Object



126
127
128
129
130
# File 'lib/allegro_release.rb', line 126

def self.commit_release(version)
  cli = HighLine.new
  jira_id = cli.ask("Give JIRA issue ID to commit changes (e.g. IOSBUY-264 or ICETIOS-368): ".colorize(:yellow)) { |q| q.validate = /\A[A-Z]+-\d+\z/ }
  commit(jira_id, version)
end

.create_local_masterObject



73
74
75
76
77
# File 'lib/allegro_release.rb', line 73

def self.create_local_master
  puts "Fetching master and creating local master branch tracking remote master branch.".colorize(:green)
  system_cmd("git fetch origin master:master")
  system_cmd("git branch --set-upstream-to=origin/master master")
end

.create_pull_request_to_develop(version) ⇒ Object



98
99
100
101
102
103
# File 'lib/allegro_release.rb', line 98

def self.create_pull_request_to_develop(version)
  puts "Creating pull request to develop on Stash.".colorize(:green)
  pull_request_command = "stash pull-request develop -T \"Release #{version_from_file}.\" -d \"Release #{version_from_file}.\""
  link = perform_pull_request(pull_request_command)
  pbcopy "(kotek) (kotek) (successful) (successful) #{link}"
end

.create_pull_request_to_masterObject



79
80
81
82
83
84
# File 'lib/allegro_release.rb', line 79

def self.create_pull_request_to_master
  puts "Creating pull request to master on Stash.".colorize(:green)
  pull_request_command = "stash pull-request master -T \"Release #{version_from_file}.\" -d \"Release #{version_from_file}.\""
  link = perform_pull_request(pull_request_command)
  pbcopy "(kotek) (kotek) (successful) (successful) #{link}"
end

.create_release_branch(version) ⇒ Object



190
191
192
193
194
# File 'lib/allegro_release.rb', line 190

def self.create_release_branch(version)
  return unless File.directory?(".git")
  puts "Creating release branch.".colorize(:green)
  system_cmd("git checkout -b release_#{version}")
end

.finishObject



40
41
42
43
44
45
# File 'lib/allegro_release.rb', line 40

def self.finish
  checkout_master
  add_tag
  push_to_spec_repository
  puts "Last step is done! You released #{spec_file}.".colorize(:green)
end

.next_version(current, part) ⇒ Object



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

def self.next_version(current, part)
  major, minor, patch = current.split('.')
  case part
  when "major"
    major, minor, patch = major.succ, 0, 0, nil
  when "minor"
    minor, patch = minor.succ, 0
  when "patch"
    patch = patch.succ
  else
    raise "unknown part #{part.inspect}"
  end
  [major, minor, patch].compact.join('.')
end

.pbcopy(input) ⇒ Object



247
248
249
250
251
# File 'lib/allegro_release.rb', line 247

def self.pbcopy(input)
  str = input.to_s
  IO.popen('pbcopy', 'w') { |f| f << str }
  str
end

.perform_pull_request(pull_request_command) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/allegro_release.rb', line 105

def self.perform_pull_request(pull_request_command)
  link = `#{pull_request_command}`
  if link.include? 'Authentication failed. Please check your credentials and try again.'
    expired_credentials = "Your Stash credentials expired (probably due to monthly password change). Below you can find instruction about what values to enter. Authorizing again. \n".colorize(:red)
    tip_one = "1. Bitbucket Server Username: <your_username> (go to \"View Profile\" in upper-right corner of Stash)\n".colorize(:blue)
    tip_two = "2. Bitbucket Server Password (optional): <your_password>\n".colorize(:blue)
    tip_three = "3. Bitbucket Server URL: https://stash.allegrogroup.com/\n".colorize(:blue)
    tip_four = "4. Remote (optional): (just press enter)\n".colorize(:blue)
    tip_five = "5. Create a git alias 'git create-pull-request'?: n\n".colorize(:blue)
    puts expired_credentials + tip_one + tip_two + tip_three + tip_four + tip_five
    system_cmd("stash configure")
    link = `#{pull_request_command}`
  end
  return link
end

.push_changes_to_remote_branch(version) ⇒ Object



121
122
123
124
# File 'lib/allegro_release.rb', line 121

def self.push_changes_to_remote_branch(version)
  puts "Pushing branch to upstream.".colorize(:green)
  system_cmd("git push -u origin release_#{version}")
end

.push_to_spec_repositoryObject



60
61
62
63
# File 'lib/allegro_release.rb', line 60

def self.push_to_spec_repository
  puts "Pushing #{spec_file} to spec repository.".colorize(:green)
  system_cmd("pod repo push allegrogroup-scm-iostools-pods.specs --allow-warnings #{spec_file}")
end

.replace(old, new) ⇒ Object



163
164
165
166
167
# File 'lib/allegro_release.rb', line 163

def self.replace(old, new)
  puts "Bumping version #{old} to #{new} of #{spec_file}.".colorize(:green)
  content = File.read(spec_file)
  File.open(spec_file, "w"){|f| f.write(content.sub(old, new)) }
end

.run(bump, options = {}) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/allegro_release.rb', line 16

def self.run(bump, options={})
  case bump
  when *BUMPS
    check_if_repo_clean
    bump_part(bump, options)
  when "current"
    puts "Current version: #{version_from_file()}".colorize(:green)
  when "to_master"
    check_if_repo_clean
    to_master
  when "finish"
    check_if_repo_clean
    finish
  else
    raise InvalidOptionError
  end
rescue InvalidOptionError
  puts "Invalid option. Choose between #{OPTIONS.join(', ')}.".colorize(:red)
rescue NotFoundSpecFileError
  puts "Not found .podspec file.".colorize(:red)
rescue Exception => e
  puts "Shell command error. See message above. Stack: #{e.backtrace.join("\n")}".colorize(:red)
end

.spec_fileObject



201
202
203
204
# File 'lib/allegro_release.rb', line 201

def self.spec_file
  raise NotFoundSpecFileError if Dir.glob('*.podspec')[0].empty?
  Dir.glob('*.podspec')[0]
end

.system_cmd(command) ⇒ Object

Raises:

  • (Exception)


196
197
198
199
# File 'lib/allegro_release.rb', line 196

def self.system_cmd(command)
  puts ("[SHELL] " + command).colorize(:white)
  raise Exception unless system command
end

.to_masterObject



65
66
67
68
69
70
71
# File 'lib/allegro_release.rb', line 65

def self.to_master
  create_local_master
  checkout_release
  push_changes_to_remote_branch(version_from_file)
  create_pull_request_to_master
  puts "Second step is done! Now head to HipChat and paste the content of clipboard that contains link to pull request. After manual merge perform `allegro_release finish`.".colorize(:green)
end

.update_changelog(version) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/allegro_release.rb', line 132

def self.update_changelog(version)
  puts "Updating CHANGELOG.md with #{version} version and #{Time.now.strftime("%d.%m.%Y")} release date.".colorize(:green)
  if Dir.glob('CHANGELOG.md').empty?
    puts "There is no CHANGELOG.md in the repository. Skipping...".colorize(:red)
    return
  end
  changelog_file = Dir.glob('CHANGELOG.md')[0]
  temp_changelog_file = "CHANGELOG.tmp"
  temp_file = File.open(temp_changelog_file, 'w')

  temp_file << "# CHANGELOG\n"
  temp_file << "\n"
  temp_file << "## Version X.Y.Z\n"
  temp_file << "#### Released ?\n"
  temp_file << "\n"
  temp_file << "## Version #{version}\n"
  temp_file << "#### Released #{Time.now.strftime("%d.%m.%Y")}\n"
  temp_file << "\n"

  File.readlines(changelog_file).each_with_index do |line, index|
    if index > 4 
      temp_file << line
    end
  end 

  changelog = File.new(changelog_file)
  temp_file.close
  FileUtils.mv(temp_changelog_file, changelog)
  changelog.close
end

.version_from_fileObject



206
207
208
209
# File 'lib/allegro_release.rb', line 206

def self.version_from_file
  raise NotFoundSpecFileError if Dir.glob('*.podspec').empty?
  File.read(spec_file)[VERSION_REGEX]
end