Skip to content

Commit

Permalink
fixup! fixup! New tool: oca-port-pr
Browse files Browse the repository at this point in the history
  • Loading branch information
sebalix committed Jul 30, 2021
1 parent f66a8d9 commit bdc355c
Showing 1 changed file with 64 additions and 26 deletions.
90 changes: 64 additions & 26 deletions tools/oca_port_pr.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
The tool will also ask you if you also want to open draft pull requests against
the upstream repository.
"""
from collections import defaultdict, namedtuple
from collections import abc, defaultdict, namedtuple
import contextlib
import os
import re
Expand Down Expand Up @@ -95,7 +95,7 @@ class Commit():
"message",
)
other_equality_attrs = (
"addons",
"changes",
)
eq_strict = True

Expand Down Expand Up @@ -129,10 +129,39 @@ def __repr__(self):
return f"{self.__class__.__name__}({attrs})"


PullRequest = namedtuple(
"PullRequest",
"number url author title body merged_at",
)
class PullRequest(abc.Hashable):
eq_attrs = ("number", "url", "author", "title", "body", "merged_at")

def __init__(
self, number, url, author, title, body, merged_at,
changes=None, ported_changes=None
):
self.number = number
self.url = url
self.author = author
self.title = title
self.body = body
self.merged_at = merged_at
self.changes = set(changes) if changes else set()
self.ported_changes = set(ported_changes) if ported_changes else set()

def __eq__(self, other):
if not isinstance(other, PullRequest):
return super().__eq__(other)
return all(
[
getattr(self, attr) == getattr(other, attr)
for attr in self.__class__.eq_attrs
]
)

def __hash__(self):
attr_values = tuple(getattr(self, attr) for attr in self.eq_attrs)
return hash(attr_values)

@property
def addons_not_ported(self):
return list(self.changes - self.ported_changes)


@contextlib.contextmanager
Expand All @@ -159,7 +188,7 @@ def _fetch_branches(repo, remote, *branches):

def _new_commit_from_local_repo_data(commit):
"""Create a new Commit instance from local repository data."""
files = set(commit.stats.files.keys())
files = {f for f in set(commit.stats.files.keys()) if "=>" not in f}
return Commit(
author_name=commit.author.name,
author_email=commit.author.email,
Expand All @@ -170,11 +199,11 @@ def _new_commit_from_local_repo_data(commit):
committed_datetime=commit.committed_datetime.replace(tzinfo=None),
parents=[parent.hexsha for parent in commit.parents],
files=files,
addons={f.split("/", maxsplit=1)[0] for f in files} - {"setup"},
changes={f.split("/", maxsplit=1)[0] for f in files} - {"setup"},
)


def _new_pull_request_from_github_data(data):
def _new_pull_request_from_github_data(data, changes=None, ported_changes=None):
"""Create a new PullRequest instance from GitHub data."""
pr_number = data["number"]
pr_url = data["html_url"]
Expand All @@ -189,6 +218,8 @@ def _new_pull_request_from_github_data(data):
title=pr_title,
body=pr_body,
merged_at=pr_merge_at,
changes=changes,
ported_changes=ported_changes,
)


Expand Down Expand Up @@ -268,9 +299,15 @@ def print_diff(self, list_commits=False):
for pr in self.commits_diff:
counter += 1
lines_to_print.append(f"- {pr.url or '(w/o PR)'}: {pr.title}")
lines_to_print.append(f"\tBy {pr.author}, merged at {pr.merged_at}")
lines_to_print.append(
f"\t=> Updates {list(pr.changes)}"
)
lines_to_print.append(
f"\t=> Changes on {pr.addons_not_ported} were not ported"
)
lines_to_print.append(
f"\tBy {pr.author}, merged at {pr.merged_at} "
f"({len(self.commits_diff[pr])} commits not (fully) ported)"
f"\t=> {len(self.commits_diff[pr])} commit(s) not (fully) ported"
)
if list_commits:
for commit in self.commits_diff[pr]:
Expand All @@ -279,7 +316,7 @@ def print_diff(self, list_commits=False):
)
lines_to_print.insert(
1,
f"{counter} pull request(s) to port from "
f"{counter} pull request(s) related to '{self.path}' to port from "
f"{self.from_branch} to {self.to_branch}"
)
print("\n".join(lines_to_print))
Expand All @@ -296,27 +333,29 @@ def get_commits_diff(self):
continue
# Get related Pull Request if any
if any("github.com" in remote.url for remote in self.repo.remotes):
commit_pulls_data = _request_github(
gh_commit_pulls = _request_github(
f"repos/{self.org_name}/{self.repo_name}"
f"/commits/{commit.hexsha}/pulls"
)
full_repo_name = f"{self.org_name}/{self.repo_name}"
commit_pr_data = [
data for data in commit_pulls_data
gh_commit_pull = [
data for data in gh_commit_pulls
if data["base"]["repo"]["full_name"] == full_repo_name
]
pr = PullRequest(*[""] * 6) # Fake PR for commits w/o related PR
if commit_pr_data:
pr = _new_pull_request_from_github_data(commit_pr_data[0])
# Fake PR for commits w/o related PR
pr = PullRequest(*[""] * 6, tuple(), tuple())
if gh_commit_pull:
pr = _new_pull_request_from_github_data(gh_commit_pull[0])
# Get all commits of the related PR as they could update
# others addons than the one the user is interested in
pr_data = _request_github(
gh_pr_commits = _request_github(
f"repos/{self.org_name}/{self.repo_name}"
f"/pulls/{pr.number}/commits"
)
for pr_commit_data in pr_data:
raw_commit = self.repo.commit(pr_commit_data["sha"])
for gh_pr_commit in gh_pr_commits:
raw_commit = self.repo.commit(gh_pr_commit["sha"])
pr_commit = _new_commit_from_local_repo_data(raw_commit)
pr.changes.update(pr_commit.changes)
if _skip_commit(pr_commit):
continue
# Check that this PR commit does not change the current
Expand All @@ -327,7 +366,7 @@ def get_commits_diff(self):
# in the past (with git-format-patch), and we now want
# to port the remaining chunks.
if pr_commit not in self.to_branch_path_commits:
addons_updated = set(pr_commit.addons)
changes = set(pr_commit.changes)
# A commit could have been ported several times
# if it was impacting several addons and the
# migration has been done with git-format-patch
Expand All @@ -338,10 +377,9 @@ def get_commits_diff(self):
while pr_commit in to_branch_all_commits:
index = to_branch_all_commits.index(pr_commit)
ported_commit = to_branch_all_commits.pop(index)
addons_updated = (
addons_updated - ported_commit.addons
)
if not addons_updated:
pr.ported_changes.update(ported_commit.changes)
changes = changes - ported_commit.changes
if not changes:
# The ported commits have already updated
# the same addons than the original one,
# we can skip it.
Expand Down

0 comments on commit bdc355c

Please sign in to comment.