-
-
Save werkshy/7106011 to your computer and use it in GitHub Desktop.
Asana code review CLI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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