Skip to content

Commit

Permalink
Split main into multiple files
Browse files Browse the repository at this point in the history
  • Loading branch information
mattdailis committed Nov 8, 2023
1 parent 66841a6 commit 75a0f90
Show file tree
Hide file tree
Showing 21 changed files with 526 additions and 482 deletions.
5 changes: 5 additions & 0 deletions cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import click

@click.group()
def cli():
pass
4 changes: 4 additions & 0 deletions commands/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from os.path import dirname, basename, isfile, join
import glob
modules = glob.glob(join(dirname(__file__), "*.py"))
__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')]
37 changes: 37 additions & 0 deletions commands/backlog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import click

from cli import cli
import db
from group_by import group_by
from login_to_name import login_to_name
from print_items import print_items
from sprint_end_date import sprint_end_date
from sprint_is_active import sprint_is_active
from opt import opt

@cli.command()
@click.option("--by-assignee", is_flag=True, help="group items by assignee")
@click.option("--clipper", is_flag=True, help="show only clipper items")
@click.option("--bugs", is_flag=True, help="show only bugs")
def backlog(by_assignee, clipper, bugs):
items = db.retrieve()["project_items"]["items"]
items = [item for item in items if not ("sprint" in item and sprint_is_active(item["sprint"])) and not item["status"] == "Done"]
if clipper:
items = [item for item in items if "labels" in item and "clipper" in item["labels"]]
if bugs:
items = [item for item in items if "labels" in item and "bug" in item["labels"]]
if by_assignee:
grouped = sorted(group_by(items, opt("assignees", lambda x: map(login_to_name, x), tuple, sorted,
lambda x: ", ".join(x), default="Unassigned")).items())
else:
grouped = sorted(
group_by(
items,
opt(
"sprint",
lambda x: f"{sprint_end_date(x)} {x['title']}",
default="Backlog",
),
).items()
)
print_items(grouped, opt("milestone", "title", default="No milestone"), status_first=False)
21 changes: 21 additions & 0 deletions commands/csv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from cli import cli
import db
from opt import opt

@cli.command()
def csv():
items = db.retrieve()["project_items"]["items"]
columns = [
lambda item: opt("milestone", "title", default="No milestone")(item),
opt("title"),
lambda x: x["repository"].split("/")[-1]
+ " #"
+ str(x["content"]["number"]),
opt("labels", lambda x: ",".join(x), default=""),
opt("status")
]
import csv
with open("pm.csv", "w") as f:
writer = csv.writer(f)
for item in items:
writer.writerow(column(item) for column in columns)
60 changes: 60 additions & 0 deletions commands/fetch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import click

import gh
from cli import cli
import db
from print_issues import print_issues

from repos import repos

@cli.command()
@click.option("--items", is_flag=True, help="also fetch items. This may take a little while")
def fetch(items):
fetch_items = items
try:
issues = db.retrieve()["issues"]
prs = db.retrieve()["prs"]
except:
issues = []
prs = []

new_issues = []
new_prs = []
for repo in repos:
cached_issue_update_times = [issue["updatedAt"] for issue in issues if issue["repo"] == repo]
if cached_issue_update_times:
last_updated = max(cached_issue_update_times)
else:
last_updated = None
print(f"Fetching issues from {repo}")
for issue in gh.get_issues(f"NASA-AMMOS/{repo}", updated_after=last_updated):
issue["repo"] = repo
new_issues.append(issue)

print(f"Fetching PRs from {repo}")
for pr in gh.get_prs(f"NASA-AMMOS/{repo}", updated_after=last_updated):
pr["repo"] = repo
new_prs.append(pr)

updated_issues = {(issue["repo"], issue["number"]) for issue in new_issues}
issues = [issue for issue in issues if (issue["repo"], issue["number"]) not in updated_issues]

print(f"Updated issues ({len(new_issues)}):")
print_issues(new_issues)
issues.extend(new_issues)

updated_prs = {(pr["repo"], pr["number"]) for pr in new_prs}
prs = [pr for pr in prs if (pr["repo"], pr["number"]) not in updated_prs]

print(f"Updated PRs ({len(new_prs)}):")
print_issues(new_prs)
prs.extend(new_prs)

if fetch_items:
print("Fetching project items")
project_items = gh.get_project_items("NASA-AMMOS", 2)
else:
print("Using cached items only")
project_items = db.retrieve()["project_items"]

db.store({"issues": issues, "project_items": project_items, "prs": prs})
34 changes: 34 additions & 0 deletions commands/issues.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import click

from cli import cli
import db
from print_issues import print_issues

@cli.command()
@click.option("--show-closed", is_flag=True, help="include closed issues in output")
@click.option(
"--not-in-project", is_flag=True, help="show only issues that are not in a project"
)
def issues(show_closed, not_in_project):
issues = db.retrieve()["issues"]

if not show_closed:
issues = [issue for issue in issues if issue["state"] != "CLOSED"]

if not_in_project:
project_items = db.retrieve()["project_items"]["items"]

issues_in_project = set()

for item in project_items:
repo = item["repository"].split("/")[-1]
number = item["content"]["number"]
issues_in_project.add((repo, number))

issues = [
issue
for issue in issues
if (issue["repo"], issue["number"]) not in issues_in_project
]

print_issues(issues, show_state=show_closed)
61 changes: 61 additions & 0 deletions commands/items.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import click

from cli import cli
import db
from group_by import group_by
from opt import opt
from sorters import milestone_sorter
from print_items import print_items
from sprint_end_date import sprint_end_date


@cli.command()
@click.option("--by-milestone", is_flag=True, help="group items by milestone")
@click.option("--by-sprint", is_flag=True, help="group items by sprint")
@click.option("--show-done", is_flag=True, help="include Done items in output")
def items(by_milestone, by_sprint, show_done):
items = db.retrieve()["project_items"]["items"]
issues = db.retrieve()["issues"]

# Issues are easier to keep in sync - prefer the issue's milestone if available
issue_dict = {
(issue["repo"], issue["number"]): issue
for issue in issues
}

for item in items:
repo = item["repository"].split("/")[-1]
number = item["content"]["number"]
if (repo, number) in issue_dict:
issue = issue_dict[(repo, number)]
if "milestone" in issue:
item["milestone"] = issue["milestone"]

if not show_done:
items = [item for item in items if item["status"] != "Done"]

items = sorted(items, key=lambda item: (item["status"], item["content"]["number"]))

if by_milestone:
grouped = sorted(
group_by(items, opt("milestone", "title", default="No milestone")).items(),
key=lambda x: milestone_sorter(x[0])
)
other_column = opt("sprint", "title", default="No sprint")
else:
grouped = sorted(
group_by(
items,
opt(
"sprint",
lambda x: f"{sprint_end_date(x)} {x['title']}",
default="No Sprint",
),
).items()
)
other_column = opt("milestone", "title", default="No milestone")

print_items(grouped, other_column)



16 changes: 16 additions & 0 deletions commands/standup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from cli import cli
import db

from group_by import group_by
from login_to_name import login_to_name
from opt import opt
from print_items import print_items
from sprint_is_active import sprint_is_active


@cli.command()
def standup():
items = db.retrieve()["project_items"]["items"]
items = [item for item in items if "sprint" in item and sprint_is_active(item["sprint"])]
items_by_assignee = group_by(items, opt("assignees", lambda x: map(login_to_name, x), tuple, sorted, lambda x: ", ".join(x), default=tuple()))
print_items(sorted(items_by_assignee.items()), opt("milestone", "title", default="No milestone"), include_assignees=False)
97 changes: 97 additions & 0 deletions commands/view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import datetime

import click
from pytz import timezone
from rich.markdown import Markdown

from cli import cli
import db
from login_to_name import login_to_name
from print_issues import print_issues

from console import _console


@cli.command()
@click.argument("issue_number")
@click.option(
"-u", "--ui", is_flag=True, help="specify that this issue should be from aerie-ui"
)
@click.option(
"-a", "--aerie", is_flag=True, help="specify that this issue should be from aerie"
)
@click.option(
"-d", "--docs", is_flag=True, help="specify that this issue should be from aerie-docs"
)
def view(issue_number, ui, aerie, docs):
issues = db.retrieve()["issues"]
prs = db.retrieve()["prs"]

if issue_number.startswith("#"):
issue_number = issue_number[1:]

if ui:
issues = [issue for issue in issues if issue["repo"] == "aerie-ui"]
prs = [pr for pr in prs if pr["repo"] == "aerie-ui"]
if aerie:
issues = [issue for issue in issues if issue["repo"] == "aerie"]
prs = [pr for pr in prs if pr["repo"] == "aerie"]
if docs:
issues = [issue for issue in issues if issue["repo"] == "aerie-docs"]
prs = [pr for pr in prs if pr["repo"] == "aerie-docs"]
issues = [issue for issue in issues if issue["number"] == int(issue_number)]
prs = [pr for pr in prs if pr["number"] == int(issue_number)]
issues += prs
if not issues:
raise Exception(f"Issue #{issue_number} not found")
if len(issues) > 1:
print(f"Multiple issues found with #{issue_number}:")
print_issues(issues)
return
issue = issues[0]
header = "\n".join(
(
f'## {issue["title"]}(#{issue["number"]}) [{issue["state"]}]',
f'#### @{login_to_name(issue["author"]["login"])} on {utc_to_pdt(issue["createdAt"])}',
)
)

console = _console
with console.pager(styles=True):
render_md(console, header + "\n\n" + issue["body"])

for comment in issue["comments"]:
render_md(console, "---")
render_md(
console,
f'_@{login_to_name(comment["author"]["login"])} on {utc_to_pdt(comment["createdAt"])}_',
)
render_md(console, comment["body"])
render_md(console, "---")

console.print(issue["url"])


def render_md(console, md):
console.print(Markdown(md, hyperlinks=False), width=90)


def utc_to_pdt(utc):
# 2023-09-27T22:16:35Z
format = "%Y-%m-%dT%H:%M:%SZ"
datetime_utc = datetime.datetime.strptime(utc, format).replace(
tzinfo=datetime.timezone.utc
)
days_ago = (
datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc) - datetime_utc
).days
res = datetime_utc.astimezone(timezone("US/Pacific")).strftime(
"%A, %Y-%m-%d at %I:%M %p"
)
if days_ago == 0:
res = res + " (Today)"
elif days_ago == 1:
res = res + " (Yesterday)"
else:
res = res + f" ({days_ago} days ago)"
return res
4 changes: 4 additions & 0 deletions console.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from rich.console import Console

_console = Console()

8 changes: 8 additions & 0 deletions group_by.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
def group_by(elements, key):
res = {}
for element in elements:
value = key(element)
if value not in res:
res[value] = []
res[value].append(element)
return res
29 changes: 29 additions & 0 deletions login_to_name.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
def login_to_name(login):
logins = {
"lklyne": "Lyle Klyne",
"camargo": "Chris Camargo",
"parkerabercrombie": "Parker Abercrombie",
"bashbash": "Basak Ramaswamy",
"adrienmaillard": "Adrien Maillard",
"skovati": "Luke Jurgella",
"twisol": "Jonathan Castello",
"biqua": "Emily Winner",
"ewferg": "Eric Ferguson",
"bradNASA": "Brad Clement",
"cohansen": "Cody Hansen",
"mattdailis": "Matt Dailis",
"goetzrrGit": "Ryan Goetz",
"JoelCourtney": "Joel Courtney",
"Mythicaeda": "Theresa Kamerman",
"jmdelfa": "Juan Delfa",
"duranb": "Bryan Duran",
"AaronPlave": "Aaron Plave",
"joswig": "Chet Joswig",
"cartermak": "Carter Mak",
"jeffpamer": "Jeff Pamer",
"sschaffe": "Steve Schaffer"
}
if login in logins:
return logins[login]
else:
return login
Loading

0 comments on commit 75a0f90

Please sign in to comment.