Created
October 20, 2022 18:08
-
-
Save BKDaugherty/a1b689ac118f42c48f6c5f4edfc10b9b to your computer and use it in GitHub Desktop.
A quick click CLI tool to generate a DOT file from an asana project
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
import asana | |
import click | |
import logging | |
import graphviz | |
import os | |
def get_client(): | |
access_token = os.environ["ASANA_ACCESS_TOKEN"] | |
client = asana.Client.access_token(access_token) | |
return client | |
@click.command() | |
@click.option("--project-id", help="find this in the URL of the asana project") | |
@click.option( | |
"--output-filename", type=click.Path(exists=False), default="./asana-project.gv" | |
) | |
def build_diagram(project_id, output_filename): | |
asana_client = get_client() | |
logging.info("Getting the tasks in the project") | |
all_tasks_in_project = list(asana_client.tasks.get_tasks({"project": project_id})) | |
task_info = {} | |
task_parent_map = {} | |
task_children_map = {} | |
logging.info("Gathering info on tasks in the project") | |
for task in all_tasks_in_project: | |
task_id = task["gid"] | |
full_task = asana_client.tasks.get_task( | |
task_id, | |
opt_field=["dependencies", "dependents", "completed", "assignee", "name"], | |
) | |
task_info[task_id] = { | |
"completed": full_task["completed"], | |
"name": full_task["name"], | |
} | |
parents = [ | |
x["gid"] for x in asana_client.tasks.get_dependencies_for_task(task_id) | |
] | |
children = [ | |
x["gid"] for x in asana_client.tasks.get_dependents_for_task(task_id) | |
] | |
task_parent_map[task_id] = parents | |
task_children_map[task_id] = children | |
# Iterate through dependencies and dependents to get full task info | |
logging.info("Gathering info on dependencies") | |
for task, dep_task_ids in task_parent_map.items(): | |
for task_id in dep_task_ids: | |
if task_id in task_info: | |
continue | |
full_task = asana_client.tasks.get_task( | |
task_id, | |
opt_field=[ | |
"dependencies", | |
"dependents", | |
"completed", | |
"assignee", | |
"name", | |
], | |
) | |
task_info[task_id] = { | |
"completed": full_task["completed"], | |
"name": full_task["name"], | |
} | |
for task, dep_task_ids in task_children_map.items(): | |
for task_id in dep_task_ids: | |
if task_id in task_info: | |
continue | |
full_task = asana_client.tasks.get_task( | |
task_id, | |
opt_field=[ | |
"dependencies", | |
"dependents", | |
"completed", | |
"assignee", | |
"name", | |
], | |
) | |
task_info[task_id] = { | |
"completed": full_task["completed"], | |
"name": full_task["name"], | |
} | |
# Create graphviz | |
logging.info("Building a visualization") | |
edge_existence = set() | |
dot = graphviz.Digraph(comment="my project") | |
for task_id, task in task_info.items(): | |
dot.node(task_id, task["name"]) | |
for source, dests in task_children_map.items(): | |
for dest in dests: | |
if (source, dest) not in edge_existence: | |
dot.edge(source, dest) | |
edge_existence.add((source, dest)) | |
for source, dests in task_parent_map.items(): | |
for dest in dests: | |
if (dest, source) not in edge_existence: | |
dot.edge(dest, source) | |
edge_existence.add((dest, source)) | |
file_path = dot.render(output_filename).replace("\\", "/") | |
logging.info(f"Find your diagram at {file_path}!") | |
if __name__ == "__main__": | |
build_diagram() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment