Module: GitReflow
- Extended by:
- GitReflow
- Included in:
- GitReflow
- Defined in:
- lib/git_reflow.rb,
lib/git_reflow/version.rb
Constant Summary collapse
- LGTM =
/lgtm|looks good to me|:\+1:|:thumbsup:|:shipit:/i- VERSION =
"0.3.6"
Instance Method Summary collapse
- #append_to_squashed_commit_message(message = '') ⇒ Object
-
#ask_to_open_in_browser(url) ⇒ Object
WARNING: this currently only supports OS X and UBUNTU.
- #build_color(status) ⇒ Object
- #colorized_build_description(status) ⇒ Object
- #comment_authors_for_pull_request(pull_request, options = {}) ⇒ Object
- #current_branch ⇒ Object
- #deliver(options = {}) ⇒ Object
- #display_pull_request_summary(pull_request) ⇒ Object
- #fetch_destination(destination_branch) ⇒ Object
- #find_authors_of_open_pull_request_comments(pull_request) ⇒ Object
- #find_pull_request(options) ⇒ Object
- #get_build_status(sha) ⇒ Object
- #get_commited_time(commit_sha) ⇒ Object
- #get_first_commit_message ⇒ Object
- #github ⇒ Object
- #github_api_endpoint ⇒ Object
- #github_oauth_token ⇒ Object
- #github_site_url ⇒ Object
- #github_user ⇒ Object
- #has_pull_request_comments?(pull_request) ⇒ Boolean
- #merge_feature_branch(options = {}) ⇒ Object
- #pull_request_comments(pull_request) ⇒ Object
- #push_current_branch ⇒ Object
- #remote_repo_name ⇒ Object
- #remote_user ⇒ Object
- #review(options = {}) ⇒ Object
- #run_command_with_label(command, options = {}) ⇒ Object
- #set_github_api_endpoint(api_endpoint, options = {local: false}) ⇒ Object
- #set_github_site_url(site_url, options = {local: false}) ⇒ Object
- #set_oauth_token(oauth_token, options = {}) ⇒ Object
- #setup(options = {}) ⇒ Object
- #status(destination_branch) ⇒ Object
- #update_destination(destination_branch) ⇒ Object
Instance Method Details
#append_to_squashed_commit_message(message = '') ⇒ Object
263 264 265 266 |
# File 'lib/git_reflow.rb', line 263 def ( = '') `echo "#{}" | cat - .git/SQUASH_MSG > ./tmp_squash_msg` `mv ./tmp_squash_msg .git/SQUASH_MSG` end |
#ask_to_open_in_browser(url) ⇒ Object
WARNING: this currently only supports OS X and UBUNTU
381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
# File 'lib/git_reflow.rb', line 381 def ask_to_open_in_browser(url) if RUBY_PLATFORM =~ /darwin|linux/i open_in_browser = ask "Would you like to open it in your browser? " if open_in_browser =~ /^y/i if RUBY_PLATFORM =~ /darwin/i # OS X `open #{url}` else # Ubuntu `xdg-open #{url}` end end end end |
#build_color(status) ⇒ Object
296 297 298 299 |
# File 'lib/git_reflow.rb', line 296 def build_color status colorized_statuses = { pending: :yellow, success: :green, error: :red, failure: :red } colorized_statuses[status.state.to_sym] end |
#colorized_build_description(status) ⇒ Object
301 302 303 |
# File 'lib/git_reflow.rb', line 301 def colorized_build_description status status.description.colorize( build_color status ) end |
#comment_authors_for_pull_request(pull_request, options = {}) ⇒ Object
314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
# File 'lib/git_reflow.rb', line 314 def (pull_request, = {}) all_comments = pull_request_comments(pull_request) = [] all_comments.each do |comment| next if [:after] and Time.parse(comment.created_at) < [:after] if ([:with].nil? or comment[:body] =~ [:with]) |= [comment.user.login] end end # remove the current user from the list to check -= [github_user] end |
#current_branch ⇒ Object
208 209 210 |
# File 'lib/git_reflow.rb', line 208 def current_branch `git branch --no-color | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g'`.strip end |
#deliver(options = {}) ⇒ Object
109 110 111 112 113 114 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 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/git_reflow.rb', line 109 def deliver( = {}) feature_branch = current_branch ['base'] ||= 'master' fetch_destination ['base'] update_destination(current_branch) begin existing_pull_request = find_pull_request( :from => current_branch, :to => ['base'] ) if existing_pull_request.nil? puts "Error: No pull request exists for #{remote_user}:#{current_branch}\nPlease submit your branch for review first with \`git reflow review\`" else = (existing_pull_request) has_comments = has_pull_request_comments?(existing_pull_request) status = get_build_status existing_pull_request.head.sha # if there any comment_authors left, then they haven't given a lgtm after the last commit if ((status.nil? or status.state == "success") and has_comments and .empty?) or ['skip_lgtm'] = (existing_pull_request, :with => LGTM) = "#{(existing_pull_request[:body] || )}" puts "Merging pull request ##{existing_pull_request.number}: '#{existing_pull_request.title}', from '#{existing_pull_request.head.label}' into '#{existing_pull_request.base.label}'" update_destination(['base']) merge_feature_branch(:feature_branch => feature_branch, :destination_branch => ['base'], :pull_request_number => existing_pull_request.number, :message => "\nCloses ##{existing_pull_request.number}\n\nLGTM given by: @#{.join(', @')}\n") () puts "git commit".colorize(:green) committed = system('git commit') if committed puts "Merge complete!" deploy_and_cleanup = ask "Would you like to push this branch to your remote repo and cleanup your feature branch? " if deploy_and_cleanup =~ /^y/i run_command_with_label "git push origin #{['base']}" run_command_with_label "git push origin :#{feature_branch}" run_command_with_label "git branch -D #{feature_branch}" puts "Nice job buddy." end else puts "There were problems commiting your feature... please check the errors above and try again." end elsif !status.nil? and status.state != "success" puts "[#{ 'deliver halted'.colorize(:red) }] #{status.description}: #{status.target_url}" elsif .count > 0 puts "[deliver halted] You still need a LGTM from: #{.join(', ')}" else puts "[deliver halted] Your code has not been reviewed yet." end end rescue Github::Error::UnprocessableEntity => e errors = JSON.parse(e.[:body]) = errors["errors"].collect {|error| "GitHub Error: #{error["message"].gsub(/^base\s/, '')}" unless error["message"].nil?}.compact.join("\n") puts end end |
#display_pull_request_summary(pull_request) ⇒ Object
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 |
# File 'lib/git_reflow.rb', line 329 def display_pull_request_summary(pull_request) summary_data = { "branches" => "#{pull_request.head.label} -> #{pull_request.base.label}", "number" => pull_request.number, "url" => pull_request.html_url } notices = "" reviewed_by = (pull_request).map {|| .colorize(:red) } # check for CI build status status = get_build_status pull_request.head.sha if status notices << "[notice] Your build status is not successful: #{status.target_url}.\n" unless status.state == "success" summary_data.merge!( "Build status" => colorized_build_description(status) ) end # check for needed lgtm's pull_comments = pull_request_comments(pull_request) if pull_comments.reject {|comment| comment.user.login == github_user}.any? = (pull_request) last_committed_at = get_commited_time(pull_request.head.sha) = (pull_request, :with => LGTM, :after => last_committed_at) summary_data.merge!("Last comment" => pull_comments.last[:body].inspect) if .any? reviewed_by.map! { || .include?(.uncolorize) ? .colorize(:green) : } end notices << "[notice] You still need a LGTM from: #{.join(', ')}\n" if .any? else notices << "[notice] No one has reviewed your pull request.\n" end summary_data['reviewed by'] = reviewed_by.join(', ') padding_size = summary_data.keys.max_by(&:size).size + 2 summary_data.keys.sort.each do |name| string_format = " %-#{padding_size}s %s\n" printf string_format, "#{name}:", summary_data[name] end puts "\n#{notices}" unless notices.empty? end |
#fetch_destination(destination_branch) ⇒ Object
242 243 244 |
# File 'lib/git_reflow.rb', line 242 def fetch_destination(destination_branch) run_command_with_label "git fetch origin #{destination_branch}" end |
#find_authors_of_open_pull_request_comments(pull_request) ⇒ Object
305 306 307 308 309 310 311 312 |
# File 'lib/git_reflow.rb', line 305 def (pull_request) # first we'll gather all the authors that have commented on the pull request pull_last_committed_at = get_commited_time(pull_request.head.sha) = (pull_request) = (pull_request, :with => LGTM, :after => pull_last_committed_at) - end |
#find_pull_request(options) ⇒ Object
268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/git_reflow.rb', line 268 def find_pull_request() existing_pull_request = nil github.pull_requests.all(remote_user, remote_repo_name, :state => 'open') do |pull_request| if pull_request.base.label == "#{remote_user}:#{[:to]}" and pull_request.head.label == "#{remote_user}:#{[:from]}" existing_pull_request = pull_request break end end existing_pull_request end |
#get_build_status(sha) ⇒ Object
292 293 294 |
# File 'lib/git_reflow.rb', line 292 def get_build_status sha github.repos.statuses.all(remote_user, remote_repo_name, sha).first end |
#get_commited_time(commit_sha) ⇒ Object
375 376 377 378 |
# File 'lib/git_reflow.rb', line 375 def get_commited_time(commit_sha) last_commit = github.repos.commits.find remote_user, remote_repo_name, commit_sha Time.parse last_commit.commit.[:date] end |
#get_first_commit_message ⇒ Object
226 227 228 |
# File 'lib/git_reflow.rb', line 226 def `git log --pretty=format:"%s" --no-merges -n 1`.strip end |
#github ⇒ Object
170 171 172 173 174 175 176 |
# File 'lib/git_reflow.rb', line 170 def github @github ||= Github.new do |config| config.oauth_token = GitReflow.github_oauth_token config.endpoint = GitReflow.github_api_endpoint config.site = GitReflow.github_site_url end end |
#github_api_endpoint ⇒ Object
178 179 180 181 |
# File 'lib/git_reflow.rb', line 178 def github_api_endpoint endpoint = `git config --get github.endpoint`.strip (endpoint.length > 0) ? endpoint : Github::Configuration::DEFAULT_ENDPOINT end |
#github_oauth_token ⇒ Object
204 205 206 |
# File 'lib/git_reflow.rb', line 204 def github_oauth_token `git config --get github.oauth-token`.strip end |
#github_site_url ⇒ Object
191 192 193 194 |
# File 'lib/git_reflow.rb', line 191 def github_site_url site_url = `git config --get github.site`.strip (site_url.length > 0) ? site_url : Github::Configuration::DEFAULT_SITE end |
#github_user ⇒ Object
212 213 214 |
# File 'lib/git_reflow.rb', line 212 def github_user `git config --get github.user`.strip end |
#has_pull_request_comments?(pull_request) ⇒ Boolean
288 289 290 |
# File 'lib/git_reflow.rb', line 288 def has_pull_request_comments?(pull_request) pull_request_comments(pull_request).count > 0 end |
#merge_feature_branch(options = {}) ⇒ Object
253 254 255 256 257 258 259 260 261 |
# File 'lib/git_reflow.rb', line 253 def merge_feature_branch( = {}) [:destination_branch] ||= 'master' = [:message] || "\nCloses ##{[:pull_request_number]}\n" run_command_with_label "git checkout #{[:destination_branch]}" run_command_with_label "git merge --squash #{[:feature_branch]}" # append pull request number to commit message () end |
#pull_request_comments(pull_request) ⇒ Object
281 282 283 284 285 286 |
# File 'lib/git_reflow.rb', line 281 def pull_request_comments(pull_request) comments = github.issues.comments.all remote_user, remote_repo_name, issue_id: pull_request.number review_comments = github.pull_requests.comments.all remote_user, remote_repo_name, request_id: pull_request.number review_comments.to_a + comments.to_a end |
#push_current_branch ⇒ Object
238 239 240 |
# File 'lib/git_reflow.rb', line 238 def push_current_branch run_command_with_label "git push origin #{current_branch}" end |
#remote_repo_name ⇒ Object
221 222 223 224 |
# File 'lib/git_reflow.rb', line 221 def remote_repo_name gh_repo = `git config --get remote.origin.url`.strip gh_repo.slice(/\/(\w|-|\.)+$/i)[1..-5] end |
#remote_user ⇒ Object
216 217 218 219 |
# File 'lib/git_reflow.rb', line 216 def remote_user gh_remote_user = `git config --get remote.origin.url`.strip gh_remote_user.slice!(/github\.com[\/:](\w|-|\.)+/i)[11..-1] end |
#review(options = {}) ⇒ Object
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 |
# File 'lib/git_reflow.rb', line 82 def review( = {}) ['base'] ||= 'master' fetch_destination ['base'] begin puts push_current_branch pull_request = github.pull_requests.create(remote_user, remote_repo_name, 'title' => ['title'], 'body' => ['body'], 'head' => "#{remote_user}:#{current_branch}", 'base' => ['base']) puts "Successfully created pull request ##{pull_request.number}: #{pull_request.title}\nPull Request URL: #{pull_request.html_url}\n" ask_to_open_in_browser(pull_request.html_url) rescue Github::Error::UnprocessableEntity => e = e.to_s if =~ /request already exists/i existing_pull_request = find_pull_request( :from => current_branch, :to => ['base'] ) puts "A pull request already exists for these branches:" display_pull_request_summary(existing_pull_request) ask_to_open_in_browser(existing_pull_request.html_url) else puts end end end |
#run_command_with_label(command, options = {}) ⇒ Object
396 397 398 399 400 |
# File 'lib/git_reflow.rb', line 396 def run_command_with_label(command, = {}) label_color = .delete(:color) || :green puts command.colorize(label_color) puts `#{command}` end |
#set_github_api_endpoint(api_endpoint, options = {local: false}) ⇒ Object
183 184 185 186 187 188 189 |
# File 'lib/git_reflow.rb', line 183 def set_github_api_endpoint(api_endpoint, = {local: false}) if [:local] `git config --replace-all github.endpoint #{api_endpoint}` else `git config --global --replace-all github.endpoint #{api_endpoint}` end end |
#set_github_site_url(site_url, options = {local: false}) ⇒ Object
196 197 198 199 200 201 202 |
# File 'lib/git_reflow.rb', line 196 def set_github_site_url(site_url, = {local: false}) if [:local] `git config --replace-all github.site #{site_url}` else `git config --global --replace-all github.site #{site_url}` end end |
#set_oauth_token(oauth_token, options = {}) ⇒ Object
230 231 232 233 234 235 236 |
# File 'lib/git_reflow.rb', line 230 def set_oauth_token(oauth_token, = {}) if .delete(:local) `git config --replace-all github.oauth-token #{oauth_token}` else `git config --global --replace-all github.oauth-token #{oauth_token}` end end |
#setup(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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/git_reflow.rb', line 16 def setup( = {}) project_only = .delete(:project_only) using_enterprise = .delete(:enterprise) gh_site_url = github_site_url gh_api_endpoint = github_api_endpoint if using_enterprise gh_site_url = ask("Please enter your Enterprise site URL (e.g. https://github.company.com):") gh_api_endpoint = ask("Please enter your Enterprise API endpoint (e.g. https://github.company.com/api/v3):") end if project_only set_github_site_url(gh_site_url, local: true) set_github_api_endpoint(gh_api_endpoint, local: true) else set_github_site_url(gh_site_url) set_github_api_endpoint(gh_api_endpoint) end gh_user = ask("Please enter your GitHub username: ") gh_password = ask("Please enter your GitHub password (we do NOT store this): ") { |q| q.echo = false } begin github = Github.new do |config| config.basic_auth = "#{gh_user}:#{gh_password}" config.endpoint = GitReflow.github_api_endpoint config.site = GitReflow.github_site_url config.adapter = :net_http config.ssl = {:verify => false} end = github.oauth.all.select {|auth| auth.note == "git-reflow (#{`hostname`.strip})" } if .any? = .last else = github.oauth.create scopes: ['repo'], note: "git-reflow (#{`hostname`.strip})" end oauth_token = .token if project_only set_oauth_token(oauth_token, local: true) else set_oauth_token(oauth_token) end rescue StandardError => e puts "\nInvalid username or password" else puts "\nYour GitHub account was successfully setup!" end end |
#status(destination_branch) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/git_reflow.rb', line 69 def status(destination_branch) pull_request = find_pull_request( :from => current_branch, :to => destination_branch ) if pull_request.nil? puts "\n[notice] No pull request exists for #{current_branch} -> #{destination_branch}" puts "[notice] Run 'git reflow review #{destination_branch}' to start the review process" else puts "Here's the status of your review:" display_pull_request_summary(pull_request) ask_to_open_in_browser(pull_request.html_url) end end |
#update_destination(destination_branch) ⇒ Object
246 247 248 249 250 251 |
# File 'lib/git_reflow.rb', line 246 def update_destination(destination_branch) origin_branch = current_branch run_command_with_label "git checkout #{destination_branch}" run_command_with_label "git pull origin #{destination_branch}" run_command_with_label "git checkout #{origin_branch}" end |