Class: Socialcast::Gitx::CLI

Inherits:
Thor
  • Object
show all
Includes:
Socialcast::Gitx, Git, Github
Defined in:
lib/socialcast-git-extensions/cli.rb

Constant Summary collapse

PULL_REQUEST_DESCRIPTION =
"\n\n" + <<-EOS.dedent
  # Use GitHub flavored Markdown http://github.github.com/github-flavored-markdown/
  # Links to screencasts or screenshots with a desciption of what this is showcasing. For architectual changes please include diagrams that will make it easier for the reviewer to understand the change. Format is ![title](url).
  # Link to ticket describing feature/bug (plantain, JIRA, bugzilla). Format is [title](url).
  # Brief description of the change, and how it accomplishes the task they set out to do.
EOS

Constants included from Socialcast::Gitx

DEFAULT_BASE_BRANCH, DEFAULT_LAST_KNOWN_GOOD_STAGING_BRANCH, DEFAULT_PROTOTYPE_BRANCH, DEFAULT_STAGING_BRANCH, VERSION

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ CLI

Returns a new instance of CLI.



25
26
27
28
29
# File 'lib/socialcast-git-extensions/cli.rb', line 25

def initialize(*args)
  super(*args)
  RestClient.proxy = ENV['HTTPS_PROXY'] if ENV.has_key?('HTTPS_PROXY')
  RestClient.log = Logger.new(STDOUT) if options[:trace]
end

Instance Method Details

#assignpr(*additional_reviewers) ⇒ Object



53
54
55
56
57
58
59
60
61
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
# File 'lib/socialcast-git-extensions/cli.rb', line 53

def assignpr(*additional_reviewers)
  update unless @skip_update

  primary_mention = if buddy = socialcast_review_buddy(current_user)
    "assigned to @#{buddy}"
  end

  secondary_mention = nil
  if !specialty_reviewers.empty? && !options.key?('skip_additional_reviewers')
    additional_reviewers = options[:additional_reviewers] || additional_reviewers

    if additional_reviewers.empty?
      prompt_text = "#{specialty_reviewers.map { |_,v| v['command'] }.join(", ")} or (or hit enter to continue): "
      additional_reviewers = $terminal.ask("Notify additional people? #{prompt_text} ")
    end

    additional_reviewers = additional_reviewers.is_a?(String) ? additional_reviewers.split(" ") : additional_reviewers

    (specialty_reviewers.keys & additional_reviewers).each do |command|
      reviewer = specialty_reviewers[command]
      secondary_mention ||= ''
      secondary_mention += "\nAssigned additionally to @#{reviewer['socialcast_username']} for #{reviewer['label']} review"
    end
  end

  branch = current_branch
  repo = current_repo
  current_pr = current_pr_for_branch(repo, branch)
  issue_url = current_pr['issue_url']
  url = current_pr['html_url']

  assignee = github_review_buddy(current_user)
  assign_pull_request(assignee, issue_url) if assignee

  if use_pr_comments?
    issue_message = ['#reviewrequest', primary_mention, secondary_mention, "\n/cc @#{developer_group} #scgitx"].compact.join(' ')
    comment_on_issue(issue_url, issue_message)
  else
    review_message = ["#reviewrequest for #{branch} in #{current_repo}", "PR #{url} #{primary_mention}", '', current_pr['body'], '', secondary_mention, "/cc @#{developer_group} #scgitx", '', changelog_summary(branch)].compact.join("\n").gsub(/\n{2,}/, "\n\n")
    post review_message, :message_type => 'review_request'
  end
end

#backportpr(pull_request_num, maintenance_branch) ⇒ Object



123
124
125
126
127
128
129
130
131
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
# File 'lib/socialcast-git-extensions/cli.rb', line 123

def backportpr(pull_request_num, maintenance_branch)
  original_base_branch = ENV['BASE_BRANCH']
  ENV['BASE_BRANCH'] = maintenance_branch
  repo = current_repo
  assignee = github_track_reviewer('Backport')
  socialcast_reviewer = socialcast_track_reviewer('Backport')

  pull_request_data = github_api_request('GET', "repos/#{repo}/pulls/#{pull_request_num}")
  commits_data = github_api_request('GET', pull_request_data['commits_url'])

  non_merge_commits_data = commits_data.select { |commit_data| commit_data['parents'].length == 1 }
  shas = non_merge_commits_data.map { |commit| commit['sha'] }

  backport_branch = "backport_#{pull_request_num}_to_#{maintenance_branch}"
  backport_to(backport_branch, shas)

  maintenance_branch_url = "https://github.com/#{repo}/tree/#{maintenance_branch}"
  description = "Backport ##{pull_request_num} to #{maintenance_branch_url}\n***\n#{pull_request_data['body']}"

  pr_hash = create_pull_request(backport_branch, repo, description)
  assign_pull_request(assignee, pr_hash['issue_url']) if assignee

  reviewer_mention = "@#{socialcast_reviewer}" if socialcast_reviewer
  if use_pr_comments?
    issue_message = ['#reviewrequest backport', reviewer_mention, "/cc @#{developer_group} #scgitx"].compact.join(' ')
    comment_on_issue(pr_hash['issue_url'], issue_message)
  else
    review_message = ["#reviewrequest backport ##{pull_request_num} to #{maintenance_branch} in #{current_repo} #scgitx"]
    if socialcast_reviewer
      review_message << "/cc #{reviewer_mention} for #backport track"
    end
    review_message << "/cc @#{developer_group}"
    post review_message.join("\n\n"), :url => pr_hash['html_url'], :message_type => 'review_request'
  end
ensure
  ENV['BASE_BRANCH'] = original_base_branch
end

#branchdiff(branch = nil, other_branch = 'master') ⇒ Object



292
293
294
295
296
297
298
299
300
301
# File 'lib/socialcast-git-extensions/cli.rb', line 292

def branchdiff(branch = nil, other_branch = 'master')
  branch ||= ask "What remote branch would you like to compare against '#{other_branch}' (ex: staging)?"
  run_cmd "git fetch origin"
  results = branch_difference(branch, other_branch)
  if results.any?
    say "\nBranches in origin/#{branch} and not in origin/#{other_branch}:\n\n#{results.join("\n")}\n\n"
  else
    say "\nNo branches found in origin/#{branch} that are not also in origin/#{other_branch}\n\n"
  end
end

#cleanupObject



178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/socialcast-git-extensions/cli.rb', line 178

def cleanup
  run_cmd "git checkout #{base_branch}"
  run_cmd "git pull"
  run_cmd 'git remote prune origin'

  say "Deleting branches that have been merged into "
  say base_branch, :green
  branches(:merged => true, :remote => true).each do |branch|
    run_cmd "git push origin --delete #{branch}" unless reserved_branch?(branch)
  end
  branches(:merged => true).each do |branch|
    run_cmd "git branch -d #{branch}" unless reserved_branch?(branch)
  end
end

#createprObject



34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/socialcast-git-extensions/cli.rb', line 34

def createpr
  update unless @skip_update
  description = options[:description] || editor_input(PULL_REQUEST_DESCRIPTION)

  if use_pr_comments?
    creator_socialcast_username = Socialcast::CommandLine::Authenticate.current_user['username'] rescue nil
    description = "#{description}\n\nCreated by @#{creator_socialcast_username}" if creator_socialcast_username
  end

  branch = current_branch
  repo = current_repo
  url = create_pull_request(branch, repo, description)['html_url']
  say "Pull request created: #{url}"
end

#findpr(commit_hash) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/socialcast-git-extensions/cli.rb', line 109

def findpr(commit_hash)
  repo = current_repo
  data = pull_requests_for_commit(repo, commit_hash)

  if data['items']
    data['items'].each do |entry|
      say "\n" << [entry['html_url'], entry['title'], "#{entry['user'] && entry['user']['login']} #{entry['created_at']}"].join("\n\t")
    end
  else
    say "No results found", :yellow
  end
end

#integrate(target_branch = prototype_branch) ⇒ Object



229
230
231
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
# File 'lib/socialcast-git-extensions/cli.rb', line 229

def integrate(target_branch = prototype_branch)
  branch = current_branch

  update
  integrate_branch(branch, target_branch)
  integrate_branch(target_branch, prototype_branch) if target_branch == staging_branch
  run_cmd "git checkout #{branch}"

  current_pr = begin
    current_pr_for_branch(current_repo, current_branch)
  rescue => e
    say e.message.to_s
    nil
  end

  say("WARNING: Unable to find current pull request.  Use `git createpr` to create one.", :red) unless current_pr

  if use_pr_comments? && current_pr
    issue_message = "Integrated into #{target_branch}"
    comment_on_issue(current_pr['issue_url'], issue_message) unless options[:quiet]
  else
    message = <<-EOS.strip_heredoc
      #worklog integrating #{branch} into #{target_branch} in #{current_repo} #scgitx
      /cc @#{developer_group}
    EOS

    post message.strip
  end
end

#nuke(bad_branch) ⇒ Object



266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
# File 'lib/socialcast-git-extensions/cli.rb', line 266

def nuke(bad_branch)
  default_good_branch = "last_known_good_#{bad_branch}"
  good_branch = options[:destination] || ask("What branch do you want to reset #{bad_branch} to? (default: #{default_good_branch})")
  good_branch = default_good_branch if good_branch.length == 0
  good_branch = "last_known_good_#{good_branch}" unless good_branch.starts_with?('last_known_good_')

  removed_branches = nuke_branch(bad_branch, good_branch)
  nuke_branch("last_known_good_#{bad_branch}", good_branch)

  message = <<-EOS.strip_heredoc
    #worklog resetting #{bad_branch} branch to #{good_branch} in #{current_repo} #scgitx
    /cc @#{developer_group}
  EOS

  if removed_branches.any?
    message += <<-EOS.strip_heredoc

      The following branches were affected:
    EOS
    message += removed_branches.map{ |b| ['*', b].join(' ') }.join("\n")
  end

  post message.strip
end

#promoteObject



260
261
262
# File 'lib/socialcast-git-extensions/cli.rb', line 260

def promote
  integrate staging_branch
end

#releaseObject



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
# File 'lib/socialcast-git-extensions/cli.rb', line 304

def release
  branch = current_branch
  assert_not_protected_branch!(branch, 'release')

  if enforce_staging_before_release?
    assert_in_last_known_good_staging(branch)
  end

  return unless yes?("Release #{branch} to production? (y/n)", :green)

  update
  run_cmd "git checkout #{base_branch}"
  run_cmd "git pull origin #{base_branch}"
  run_cmd "git pull . #{branch}"
  run_cmd "git push origin HEAD"
  integrate_branch(base_branch, staging_branch)
  integrate_branch(base_branch, prototype_branch)
  cleanup

  unless use_pr_comments?
    message = <<-EOS.strip_heredoc
      #worklog releasing #{branch} to #{base_branch} in #{current_repo} #scgitx
      /cc @#{developer_group}
    EOS

    post message.strip
  end
end

#reviewrequest(*additional_reviewers) ⇒ Object



101
102
103
104
105
106
# File 'lib/socialcast-git-extensions/cli.rb', line 101

def reviewrequest(*additional_reviewers)
  update
  @skip_update = true
  createpr
  assignpr(*additional_reviewers)
end

#shareObject



224
225
226
# File 'lib/socialcast-git-extensions/cli.rb', line 224

def share
  share_branch current_branch
end

#start(branch_name = nil) ⇒ Object



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/socialcast-git-extensions/cli.rb', line 199

def start(branch_name = nil)
  unless branch_name
    example_branch = %w{ cpr-3922-api-fix-invalid-auth red-212-desktop-cleanup-avatar-markup red-3212-share-form-add-edit-link }.sample
    repo = Rugged::Repository.new(Dir.pwd)
    remote_branches = repo.remotes.collect {|b| b.name.split('/').last }
    ## Explicitly use Highline.ask
    branch_name = $terminal.ask("What would you like to name your branch? (ex: #{example_branch})") do |q|
      q.validate = lambda { |branch| branch =~ /^[A-Za-z0-9\-_]+$/ && !remote_branches.include?(branch) }
      q.responses[:not_valid] = "This branch name is either already taken, or is not a valid branch name"
    end
  end

  run_cmd "git checkout #{base_branch}"
  run_cmd 'git pull'
  run_cmd "git checkout -b #{branch_name}"

  message = <<-EOS.strip_heredoc
    #worklog starting work on #{branch_name} in #{current_repo} #scgitx
    /cc @#{developer_group}
  EOS

  post message.strip
end

#trackObject



194
195
196
# File 'lib/socialcast-git-extensions/cli.rb', line 194

def track
  track_branch current_branch
end

#updateObject



164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/socialcast-git-extensions/cli.rb', line 164

def update
  branch = current_branch

  say 'updating '
  say "#{branch} ", :green
  say "to have most recent changes from "
  say base_branch, :green

  run_cmd "git pull origin #{branch}" rescue nil
  run_cmd "git pull origin #{base_branch}"
  run_cmd 'git push origin HEAD'
end