class Aid::Scripts::Review

Public Class Methods

description() click to toggle source
# File lib/aid/scripts/review.rb, line 12
def self.description
  "Requests a review from one or more team members"
end
help() click to toggle source
# File lib/aid/scripts/review.rb, line 16
      def self.help
        <<~HELP
          Usage: $ aid review
          Type aid review from your feature branch and follow the prompts
        HELP
      end

Public Instance Methods

run() click to toggle source
# File lib/aid/scripts/review.rb, line 23
def run
  check_for_minimum_version_of_hub!

  prompt_for_reviewers!
  run_aid_finish_if_needed!

  change_wip_to_reviewable_label!
  move_asana_task_to_pull_request_column!

  step "Marking PR ready for review" do
    pull_request.mark_ready_for_review!
    puts "✅ done"
  end

  add_reviewers_to_pr!
  ping_reviewers_on_slack!
end

Private Instance Methods

add_reviewers_to_pr!() click to toggle source
# File lib/aid/scripts/review.rb, line 88
def add_reviewers_to_pr!
  step "Assigning reviewers on Github" do
    github_client.post(
      "#{api_prefix}/pulls/#{pull_request.id}/requested_reviewers",
      json: {
        reviewers: @reviewers.map(&:github_username)
      }
    )
  end
end
api_prefix() click to toggle source
# File lib/aid/scripts/review.rb, line 167
def api_prefix
  "https://api.github.com/repos/#{repo_name}"
end
asana() click to toggle source
# File lib/aid/scripts/review.rb, line 266
def asana
  @asana ||=
    Asana::Client.new do |client|
      client.default_headers "asana-enable" => "string_ids,new_sections"
      client.authentication :access_token,
                            git_config("asana.personal-access-token")
    end
end
asana_pr_section() click to toggle source
# File lib/aid/scripts/review.rb, line 260
def asana_pr_section
  asana_sections.detect do |task|
    task.name =~ /Pull Request/i
  end
end
asana_project() click to toggle source
# File lib/aid/scripts/review.rb, line 248
def asana_project
  @asana_project ||= asana.projects.find_by_id(asana_project_id)
end
asana_project_id() click to toggle source
# File lib/aid/scripts/review.rb, line 252
def asana_project_id
  git_config("asana.project-id").to_i
end
asana_sections() click to toggle source
# File lib/aid/scripts/review.rb, line 256
def asana_sections
  asana.sections.find_by_project(project: asana_project.gid)
end
asana_task() click to toggle source
# File lib/aid/scripts/review.rb, line 244
def asana_task
  @asana_task ||= asana.tasks.find_by_id(asana_task_id)
end
asana_task_id() click to toggle source
# File lib/aid/scripts/review.rb, line 188
def asana_task_id
  @asana_task_id ||=
    begin
      result = current_branch_name.strip.match(/\d+$/)
      result && result[0]
    end
end
change_wip_to_reviewable_label!() click to toggle source
# File lib/aid/scripts/review.rb, line 150
def change_wip_to_reviewable_label!
  step "Changing WIP to reviewable label" do
    puts "Deleting WIP label..."

    github_client.delete("#{api_prefix}/issues/#{pull_request.id}/labels/wip")

    puts "Adding reviewable label..."

    github_client.post(
      "#{api_prefix}/issues/#{pull_request.id}/labels",
      json: {
        labels: ["reviewable"]
      }
    )
  end
end
check_for_minimum_version_of_hub!() click to toggle source
# File lib/aid/scripts/review.rb, line 99
def check_for_minimum_version_of_hub!
  match = `hub --version`.strip.match(/hub version (.+)$/)
  version = Gem::Version.new(match[1])
  min_version = "2.8.4"

  if version < Gem::Version.new(min_version)
    abort "aid review requires hub at #{min_version} or greater. "\
      "Run `brew upgrade hub` to upgrade."
  end
rescue StandardError
  abort "Error checking for hub version. Ensure you have it installed with "\
    "$ brew install hub"
end
current_branch_name() click to toggle source
# File lib/aid/scripts/review.rb, line 196
def current_branch_name
  `git rev-parse --abbrev-ref HEAD`.strip
end
current_user_slack_tag() click to toggle source
# File lib/aid/scripts/review.rb, line 57
def current_user_slack_tag
  member = team.members.find { |member| member.github_username == github_username }
  member&.slack_tag || git_config("user.name")
end
find_remote_github_pull_request() click to toggle source
# File lib/aid/scripts/review.rb, line 224
def find_remote_github_pull_request
  sep = "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
  cmd = %(hub pr list --format="#PR: %i\nTitle: %t\n\n%b\n#{sep}\n")

  raw_pull_requests = `#{cmd}`.strip
  pull_requests = raw_pull_requests.split(sep)
  request = pull_requests.detect { |pr| pr.include?(asana_task_id) }

  abort "Could not find a PR that matches story #{asana_task_id}" unless request

  id = request.match(/PR: #(\d+)/)[1]
  title = request.match(/Title: (.+?)\n/)[1]

  PullRequest.new(
    id: id,
    title: title,
    repo_name: repo_name
  )
end
github_auth_token() click to toggle source
# File lib/aid/scripts/review.rb, line 171
def github_auth_token
  @github_auth_token ||= load_github_auth_token
end
github_client() click to toggle source
# File lib/aid/scripts/review.rb, line 184
def github_client
  HTTP.headers("Authorization" => "token #{github_auth_token}")
end
github_username() click to toggle source
# File lib/aid/scripts/review.rb, line 53
def github_username
  git_config("github.user")
end
load_github_auth_token() click to toggle source
# File lib/aid/scripts/review.rb, line 175
def load_github_auth_token
  credential_file = "#{ENV['HOME']}/.config/hub"

  abort "No hub credentials in #{credential_file}" unless File.exist?(credential_file)

  credentials = YAML.safe_load(File.read(credential_file))
  credentials["github.com"][0]["oauth_token"]
end
local_github_pull_request() click to toggle source
# File lib/aid/scripts/review.rb, line 211
def local_github_pull_request
  id = git_config("asana.#{asana_task_id}.pull-request-id")
  title = git_config("asana.#{asana_task_id}.name")

  return nil unless id && title

  PullRequest.new(
    id: id,
    title: title,
    repo_name: repo_name
  )
end
move_asana_task_to_pull_request_column!() click to toggle source
# File lib/aid/scripts/review.rb, line 127
def move_asana_task_to_pull_request_column!
  step "Moving Asana task to Pull Request column" do
    asana_task.add_project(
      project: asana_project.gid,
      section: asana_pr_section.gid
    )
  end
end
ping_reviewers_on_slack!() click to toggle source
# File lib/aid/scripts/review.rb, line 43
def ping_reviewers_on_slack!
  step "Pinging reviewers on slack" do
    slack.ping(
      slack_message,
      username: "review-bot",
      channel: slack_channel
    )
  end
end
prompt_for_reviewers!() click to toggle source
# File lib/aid/scripts/review.rb, line 140
def prompt_for_reviewers!
  puts "Which reviewers do you want to review this PR?"
  puts

  @reviewers = team.prompt_for_members
  puts

  abort colorize(:red, "Please select a reviewer from the list") if @reviewers.empty?
end
pull_request() click to toggle source
# File lib/aid/scripts/review.rb, line 206
def pull_request
  @pull_request ||= local_github_pull_request ||
                    find_remote_github_pull_request
end
repo_name() click to toggle source
# File lib/aid/scripts/review.rb, line 200
def repo_name
  remote_url = `git remote get-url origin`.strip
  result = remote_url.match(%r{github.com[:/](?<repo_name>\w+/\w+)(?:\.git)?})
  result && result[:repo_name]
end
run_aid_finish_if_needed!() click to toggle source
# File lib/aid/scripts/review.rb, line 113
def run_aid_finish_if_needed!
  branch_commit_logs = `git log --format=full master..`.strip

  if branch_commit_logs =~ %r{Finishes:.+https://app.asana.com}mi
    step "Doing one last push to GitHub" do
      system! "git push --force-with-lease origin #{current_branch_name}"
    end
  else
    step "Running aid finish..." do
      Finish.run
    end
  end
end
slack() click to toggle source
# File lib/aid/scripts/review.rb, line 75
def slack
  @slack ||= Slack::Notifier.new(slack_webhook)
end
slack_channel() click to toggle source
# File lib/aid/scripts/review.rb, line 84
def slack_channel
  "#verisure"
end
slack_message() click to toggle source
# File lib/aid/scripts/review.rb, line 63
      def slack_message
        user_tags = @reviewers.map(&:slack_tag)

        <<~MSG
          :pray: *Review request from #{current_user_slack_tag}*
          _#{pull_request.title}_
          #{pull_request.url}

          Requested: #{user_tags.join(', ')}
        MSG
      end
slack_webhook() click to toggle source
# File lib/aid/scripts/review.rb, line 79
def slack_webhook
  "https://hooks.slack.com/services/T02A0DJMA/"\
    "BN49T3ZC0/Q536v8O5pzn1NSqDJ9BpEV3s"
end
team() click to toggle source
# File lib/aid/scripts/review.rb, line 136
def team
  @team ||= Aid::Team.from_yml("#{project_root}/.team.yml")
end