Skip to content

Commit

Permalink
Updated submit and status UX
Browse files Browse the repository at this point in the history
---
fel-version: 0.3.2
fel-stack: devel
fel-stack-index: 1
fel-branch: fel/devel/1
fel-amended-from: 7e08230
fel-pr: 32
  • Loading branch information
Zabot committed Jun 10, 2021
1 parent f47297a commit 75922b4
Show file tree
Hide file tree
Showing 10 changed files with 635 additions and 142 deletions.
104 changes: 65 additions & 39 deletions fel/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,33 @@

from . import __version__
from .config import load_config
from .submit import submit
from .submit import submit, submit_stack
from .land import land
from .stack import render_stack
from .stack import Stack, StackProgress
from .pr import update_prs
from .meta import parse_meta
from .mergeability import is_mergeable
from .style import *
from .stack_spinner import Spinner, ThreadGroup
import time

def _submit(repo, gh_repo, _, config):
submit(repo,
repo.head.commit,
gh_repo,
repo.heads[config['upstream']],
config['branch_prefix'])
stack = Stack(repo, repo.head.commit, repo.heads[config['upstream']])
with Spinner('') as spinner:
sp = StackProgress(stack, spinner.print)
spinner.label = sp

tree = render_stack(repo,
repo.head.commit,
repo.heads[config['upstream']])
# Update each commit with an index in the stack
stack.annotate(sp)

update_prs(tree, gh_repo)
# Update and push all of the stack branches
stack.push(sp)

# Update the PR for each commit in the stack
submit_stack(gh_repo, stack, sp)

# Rewrite the PRs to include the fel stack
update_prs(gh_repo, stack, sp)

def _land(repo, gh_repo, args, config):
land(repo,
Expand All @@ -43,42 +51,54 @@ def _land(repo, gh_repo, args, config):

repo.remote().fetch(prune=True)

def _stack(repo, gh_repo, args, config):
s = Stack(repo, repo.head.commit, repo.heads[config['upstream']])
s.annotate()
s.push()

def _status(repo, gh_repo, __, config):
upstream = config['upstream']
tree = render_stack(repo,
repo.head.commit,
repo.heads[upstream])
stack = Stack(repo, repo.head.commit, repo.heads[config['upstream']])

with Spinner('') as spinner:
sp = StackProgress(stack, spinner.print)
spinner.label = sp

with sp.start('Fetching PR Info'):
def get_status(commit, pr_num):
"""Retrieve the status of a pull request"""
pr = gh_repo.get_pull(pr_num)

for prefix, commit in tree:
# If there is no commit for this line, print it without changes
if commit is None:
print("\033[33m{}\033[0m".format(prefix))
continue
mergeable, message, temp = is_mergeable(gh_repo, pr, config['upstream'])

# If there is a commit, get the PR from it
try:
_, meta = parse_meta(commit.message)
pr_num = meta['fel-pr']
icon = ""
if mergeable:
icon = ok + '✓'
elif temp:
icon = warn + '• '
else:
icon = fail + '✖ '

pr = gh_repo.get_pull(pr_num)
status = f"{icon}{message}{default}"

mergeable, message, temp = is_mergeable(gh_repo, pr, upstream)
sp[commit] = f"{context}#{pr_num}{default} {status} {commit.summary} {dull}{pr_link}{default}"

m = ""
if mergeable:
m = '\033[32m ✓'
elif temp:
m = '\033[33m • '
else:
m = '\033[31m ✖ '
with ThreadGroup() as tasks:
for commit in stack.commits():
_, meta = parse_meta(commit.message)
try:
pr_num = meta['fel-pr']
pr_link = f"{gh_repo.html_url}/pull/{pr_num}"

m += message + '\033[0m'
tasks.do(get_status, commit, pr_num)
sp[commit] = f"{context}#{pr_num}{default} {info}{{spinner}} Fetching PR info{default} {commit.summary} {dull}{pr_link}{default}"

print("\033[33m{}#{}\033[0m{} {}".format(prefix, pr_num, m, commit.summary))
except KeyError:
try:
branch = meta['fel-branch']
sp[commit] = f"{context}{branch}{default} {commit.summary}"

except KeyError:
# Skip commits that haven't been published
logging.info("ignoring unpublished commit %s", commit)
except KeyError:
sp[commit] = f"{context}{commit.hexsha[:8]}{default} {commit.summary}"

def main():
parser = argparse.ArgumentParser()
Expand Down Expand Up @@ -117,8 +137,12 @@ def main():
status_parser = subparsers.add_parser('status')
status_parser.set_defaults(func=_status)

stack_parser = subparsers.add_parser('stack')
stack_parser.set_defaults(func=_stack)

args = parser.parse_args()


try:
config = load_config(args.config)
except IOError as ex:
Expand Down Expand Up @@ -168,7 +192,9 @@ def main():

except ValueError as ex:
logging.error("Could not find remote repo: %s", ex)
return 3

# Run the sub command
args.func(repo, None, args, config)

except UnknownObjectException as ex:
logging.error("Could not find remote repo on github: %s", ex)
Expand Down
28 changes: 24 additions & 4 deletions fel/meta.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
import git

known_metadata = {
'fel-stack': None,
'fel-stack-index': int,
'fel-pr': int,
'fel-branch': None,
'fel-amended-from': None,
'fel-version': None,
}

def parse_meta(message):
sections = message.split("\n---\n")
if len(sections) == 1:
Expand All @@ -6,17 +17,26 @@ def parse_meta(message):
assert len(sections) == 2

meta_lines = sections[1].strip().split('\n')
# print([kv.split(': ') for kv in meta_lines])
metadata = dict([kv.split(': ') for kv in meta_lines])

metadata['fel-pr'] = int(metadata['fel-pr'])
for key in metadata:
try:
parser = known_metadata[key]
if parser is not None:
metadata[key] = parser(metadata[key])
except KeyError:
raise KeyError("Unknown metadata key: %s", key)

return sections[0], metadata


def dump_meta(message, meta):

message = [message, '\n---']
message = [message, '---']
for key, value in meta.items():
message.append("{}: {}".format(key, value))

return '\n'.join(message)

def meta(commit, key):
_, meta = parse_meta(commit.message)
return meta[key]
102 changes: 48 additions & 54 deletions fel/pr.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,50 @@
import logging

from .meta import parse_meta

def update_prs(tree, gh_repo):
commits = []
lines = []
for prefix, commit in tree:
# If there is no commit for this line, print it without changes
if commit is None:
lines.append(prefix)
continue

# If there is a commit, get the PR from it
try:
_, meta = parse_meta(commit.message)
pr_num = meta['fel-pr']

lines.append("{prefix}<a href=\"{pr}\">#{pr} {summary}</a>"
.format(prefix = prefix,
pr = pr_num,
summary=commit.summary))

commits.append(commit)

except KeyError:
# Skip commits that haven't been published
logging.info("ignoring unpublished commit %s", commit)

for commit in commits:
if commit is None:
continue

_, meta = parse_meta(commit.message)
pr_num = meta['fel-pr']
pr = gh_repo.get_pull(pr_num)

separator = '[#]:fel'
try:
block_start = pr.body.index(separator)
body = pr.body[0: block_start].strip()
except ValueError:
body = pr.body

body = ("{original_body}"
"\n\n{separator}\n\n"
"---\n"
"This diff is part of a [fel stack](https://github.com/zabot/fel)\n"
"<pre>\n"
"{tree}\n"
"</pre>\n").format(
original_body=body,
separator=separator,
tree='\n'.join(lines))

pr.edit(body = body)
from .stack_spinner import ThreadGroup
from .meta import meta
from .stack import StackProgress
from .style import *
import time

def update_prs(gh_repo, stack, progress):
with progress.start('Rewriting PRs'):
with ThreadGroup() as tg:
stack_string = StackProgress(stack, None, None)
for commit in stack.commits():
pr_num = meta(commit, 'fel-pr')
stack_string[commit] = f"<a href=\"{pr_num}\">#{pr_num} {commit.summary}</a>"

for commit in stack.commits():
def update_pr(commit, pr_num):
try:
progress[commit] = f"{context}#{pr_num} {info}{{spinner}} Rewriting PRs{default} {commit.summary}"

pr = gh_repo.get_pull(pr_num)

separator = '[#]:fel'
try:
block_start = pr.body.index(separator)
body = pr.body[0: block_start].strip()
except ValueError:
body = pr.body

new_body = (f"{body}"
f"\n\n{separator}\n\n"
f"---\n"
f"This diff is part of a [fel stack](https://github.com/zabot/fel)\n"
f"<pre>\n"
f"{stack_string}\n"
f"</pre>\n")

# Github API uses DOS EOL, strip those so we can compare
if pr.body.replace('\r\n', '\n') != new_body:
pr.edit(body = new_body)
progress[commit] = f"{context}#{pr_num} {warn}[updated body]{default} {commit.summary}"
else:
progress[commit] = f"{context}#{pr_num} {ok}[up to date]{default} {commit.summary}"

except KeyError:
progress[commit] = f"{context}{info}[skipped]{default} {commit.summary}"

pr_num = meta(commit, 'fel-pr')
tg.do(update_pr, commit, pr_num)
Loading

0 comments on commit 75922b4

Please sign in to comment.