Skip to content

Instantly share code, notes, and snippets.

@werkshy
Created October 22, 2013 18:49
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save werkshy/7106011 to your computer and use it in GitHub Desktop.
Save werkshy/7106011 to your computer and use it in GitHub Desktop.
Asana code review CLI
#!/usr/bin/env ruby
# cr: send an Asana ticket for code review
# It will add (or re-open) a sub-task called 'Code Review' owned
# by the specified user.
# Usage:
# cr [-a ASANA_ID] [-g GIT_COMMIT] username
#
# - If the Asana ticket ID is given, use that.
# - If the git commit hash is given, look at the commit message for Asana
# ticket IDs and use them if found.
# - If no ID is given, use git HEAD for the current directory.
require 'asana'
require 'optparse'
$api_key = ENV['ASANA_API_KEY']
$code_review_tag_id = YOUR_TAG_ID_HERE
Asana.configure do |client|
client.api_key = $api_key
end
def get_asana_from_git_commit(commit_id)
puts "Looking for asana tickets in #{commit_id}"
output = `git log --format=%B -n 1 #{commit_id}`
m = output.match(/#(\d+)/)
if m.length < 2
abort("Couldn't find Asana ticket ref in git commit '#{commit_id}'")
end
return m[1]
end
# Get all users with email addresses and pick the one we want to assign to.
def find_assignee(str)
Asana::User.all(:params => {:opt_fields => "name,email"}).each { |user|
username = user.email.split("@")[0]
if str == user.email || str == username
puts "Found user '#{user.name}'"
return user
end
}
return nil
end
def find_task(task_id)
task = Asana::Task.find(task_id)
puts "Found task: #{task_id}"
return task
end
def get_codereview_tag()
Asana::Tag.all.each { |tag|
if tag.name == "codereview"
return tag
end
}
return nil
end
def get_codereview_subtask(task)
task.subtasks.each { |subtask|
subtask.tags.each { |tag|
if tag.id == $code_review_tag_id
return subtask
end
}
}
return nil
end
def show_assigned_reviews
puts "Showing open code reviews"
query = {
:tag_id => $code_review_tag_id,
:assignee => 'me',
:include_archived => false,
:opt_fields => "completed,name,parent,projects"
}
Asana::Task.all_by_tag(:params => query).each { |task|
if task.completed
next
end
project = task.attributes["projects"][0]
puts "#{task.name}"
puts " ID: #{task.id}"
url = nil
url = "https://app.asana.com/0/#{task.id}"
unless task.parent.nil?
parent = Asana::Task.find(task.parent.id)
puts " Parent: #{parent.name}"
project = parent.attributes["projects"][0]
end
unless project.nil?
project = Asana::Project.find(project.id)
puts " Project: #{project.name}"
url = "https://app.asana.com/0/#{project.id}/#{task.id}"
end
unless url.nil?
puts " Url: #{url}"
end
puts
}
end
def parse_args
options = {}
parser = OptionParser.new do |opts|
opts.banner = "Usage: cr [OPTIONS] username"
opts.on("-g", "--git-commit COMMIT", "Git commit id (to find Asana task)") do |id|
options[:commit_id] = id
end
opts.on("-a", "--asana TASK_ID", "Asana ticket id") do |id|
options[:task_id] = id
end
opts.on("-s", "--show", "Show assigned code reviews") do |id|
show_assigned_reviews
exit
end
end
parser.parse!
unless options.has_key? :task_id
git_commit = options[:commit_id]
if git_commit.nil?
git_commit = "HEAD"
end
options[:task_id] = get_asana_from_git_commit(git_commit)
end
if ARGV.length != 1
abort(parser.help)
end
options[:assignee] = ARGV[0]
return options
end
options = parse_args
assignee = find_assignee(options[:assignee])
if assignee.nil?
abort("ERROR: Couldn't find user '#{options[:assignee]}'")
end
task = find_task(options[:task_id])
if task.nil?
abort("ERROR: could not find task ##{task_id}")
end
cr_subtask = get_codereview_subtask(task)
if cr_subtask.nil?
# Create a new subtask with parent = task
puts "Creating new subtask"
subtask = task.create_subtask(:name => "Code Review",
:assignee => assignee.id)
puts "Adding codereview tag"
subtask.add_tag($code_review_tag_id)
else
puts "Found existing subtask: #{cr_subtask.id}"
cr_subtask = Asana::Task.find(cr_subtask.id)
if cr_subtask.assignee.id != assignee.id || cr_subtask.completed == true
puts "Resetting existing cr subtask"
cr_subtask.modify(:assignee => assignee.id, :completed => false)
end
end
puts "REMINDER: move into the 'code review' section manually"
puts "https://app.asana.com/0/#{task.get("projects")[0]["id"]}/#{task.id}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment