[libcxx-commits] [libcxx] 84fa7b4 - [libc++] Improve the granularity of status tracking from Github issues
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Aug 21 13:29:29 PDT 2024
Author: Louis Dionne
Date: 2024-08-21T16:29:22-04:00
New Revision: 84fa7b438e1fba0c88b21784e716926017b9fe49
URL: https://github.com/llvm/llvm-project/commit/84fa7b438e1fba0c88b21784e716926017b9fe49
DIFF: https://github.com/llvm/llvm-project/commit/84fa7b438e1fba0c88b21784e716926017b9fe49.diff
LOG: [libc++] Improve the granularity of status tracking from Github issues
This enhances the Github - CSV synchronization script to understand
some of the idioms we use in the CSV status files, like |Nothing To Do|
and others.
Added:
Modified:
libcxx/utils/synchronize_csv_status_files.py
Removed:
################################################################################
diff --git a/libcxx/utils/synchronize_csv_status_files.py b/libcxx/utils/synchronize_csv_status_files.py
index 68df5756e884d6..5ff718e5a8f916 100755
--- a/libcxx/utils/synchronize_csv_status_files.py
+++ b/libcxx/utils/synchronize_csv_status_files.py
@@ -19,6 +19,101 @@
# Number of the 'Libc++ Standards Conformance' project on Github
LIBCXX_CONFORMANCE_PROJECT = '31'
+class PaperStatus:
+ TODO = 1
+ IN_PROGRESS = 2
+ PARTIAL = 3
+ DONE = 4
+ NOTHING_TO_DO = 5
+
+ _status: int
+
+ _original: Optional[str]
+ """
+ Optional string from which the paper status was created. This is used to carry additional
+ information from CSV rows, like any notes associated to the status.
+ """
+
+ def __init__(self, status: int, original: Optional[str] = None):
+ self._status = status
+ self._original = original
+
+ def __eq__(self, other) -> bool:
+ return self._status == other._status
+
+ def __lt__(self, other) -> bool:
+ relative_order = {
+ PaperStatus.TODO: 0,
+ PaperStatus.IN_PROGRESS: 1,
+ PaperStatus.PARTIAL: 2,
+ PaperStatus.DONE: 3,
+ PaperStatus.NOTHING_TO_DO: 3,
+ }
+ return relative_order[self._status] < relative_order[other._status]
+
+ @staticmethod
+ def from_csv_entry(entry: str):
+ """
+ Parse a paper status out of a CSV row entry. Entries can look like:
+ - '' (an empty string, which means the paper is not done yet)
+ - '|In Progress|'
+ - '|Partial|'
+ - '|Complete|'
+ - '|Nothing To Do|'
+
+ Note that since we sometimes add additional notes after the status, we only check that the entry
+ starts with the above patterns.
+ """
+ if entry == '':
+ return PaperStatus(PaperStatus.TODO, entry)
+ elif entry.startswith('|In Progress|'):
+ return PaperStatus(PaperStatus.IN_PROGRESS, entry)
+ elif entry.startswith('|Partial|'):
+ return PaperStatus(PaperStatus.PARTIAL, entry)
+ elif entry.startswith('|Complete|'):
+ return PaperStatus(PaperStatus.DONE, entry)
+ elif entry.startswith('|Nothing To Do|'):
+ return PaperStatus(PaperStatus.NOTHING_TO_DO, entry)
+ else:
+ raise RuntimeError(f'Unexpected CSV entry for status: {entry}')
+
+ @staticmethod
+ def from_github_issue(issue: Dict):
+ """
+ Parse a paper status out of a Github issue obtained from querying a Github project.
+ """
+ if 'status' not in issue:
+ return PaperStatus(PaperStatus.TODO)
+ elif issue['status'] == 'Todo':
+ return PaperStatus(PaperStatus.TODO)
+ elif issue['status'] == 'In Progress':
+ return PaperStatus(PaperStatus.IN_PROGRESS)
+ elif issue['status'] == 'Partial':
+ return PaperStatus(PaperStatus.PARTIAL)
+ elif issue['status'] == 'Done':
+ return PaperStatus(PaperStatus.DONE)
+ elif issue['status'] == 'Nothing To Do':
+ return PaperStatus(PaperStatus.NOTHING_TO_DO)
+ else:
+ raise RuntimeError(f"Received unrecognizable Github issue status: {issue['status']}")
+
+ def to_csv_entry(self) -> str:
+ """
+ Return the issue state formatted for a CSV entry. The status is formatted as '|Complete|',
+ '|In Progress|', etc.
+ """
+ mapping = {
+ PaperStatus.TODO: '',
+ PaperStatus.IN_PROGRESS: '|In Progress|',
+ PaperStatus.PARTIAL: '|Partial|',
+ PaperStatus.DONE: '|Complete|',
+ PaperStatus.NOTHING_TO_DO: '|Nothing To Do|',
+ }
+ return self._original if self._original is not None else mapping[self._status]
+
+ def is_done(self) -> bool:
+ return self._status == PaperStatus.DONE or self._status == PaperStatus.NOTHING_TO_DO
+
class PaperInfo:
paper_number: str
"""
@@ -30,15 +125,14 @@ class PaperInfo:
Plain text string representing the name of the paper.
"""
- meeting: Optional[str]
+ status: PaperStatus
"""
- Plain text string representing the meeting at which the paper/issue was voted.
+ Status of the paper/issue. This can be complete, in progress, partial, or done.
"""
- status: Optional[str]
+ meeting: Optional[str]
"""
- Status of the paper/issue. This must be '|Complete|', '|Nothing To Do|', '|In Progress|',
- '|Partial|' or 'Resolved by <something>'.
+ Plain text string representing the meeting at which the paper/issue was voted.
"""
first_released_version: Optional[str]
@@ -59,15 +153,15 @@ class PaperInfo:
"""
def __init__(self, paper_number: str, paper_name: str,
+ status: PaperStatus,
meeting: Optional[str] = None,
- status: Optional[str] = None,
first_released_version: Optional[str] = None,
labels: Optional[List[str]] = None,
original: Optional[object] = None):
self.paper_number = paper_number
self.paper_name = paper_name
- self.meeting = meeting
self.status = status
+ self.meeting = meeting
self.first_released_version = first_released_version
self.labels = labels
self.original = original
@@ -77,7 +171,7 @@ def for_printing(self) -> Tuple[str, str, str, str, str, str]:
f'`{self.paper_number} <https://wg21.link/{self.paper_number}>`__',
self.paper_name,
self.meeting if self.meeting is not None else '',
- self.status if self.status is not None else '',
+ self.status.to_csv_entry(),
self.first_released_version if self.first_released_version is not None else '',
' '.join(f'|{label}|' for label in self.labels) if self.labels is not None else '',
)
@@ -85,13 +179,6 @@ def for_printing(self) -> Tuple[str, str, str, str, str, str]:
def __repr__(self) -> str:
return repr(self.original) if self.original is not None else repr(self.for_printing())
- def is_implemented(self) -> bool:
- if self.status is None:
- return False
- if re.search(r'(in progress|partial)', self.status.lower()):
- return False
- return True
-
@staticmethod
def from_csv_row(row: Tuple[str, str, str, str, str, str]):# -> PaperInfo:
"""
@@ -105,8 +192,8 @@ def from_csv_row(row: Tuple[str, str, str, str, str, str]):# -> PaperInfo:
return PaperInfo(
paper_number=match.group(1),
paper_name=row[1],
+ status=PaperStatus.from_csv_entry(row[3]),
meeting=row[2] or None,
- status=row[3] or None,
first_released_version=row[4] or None,
labels=[l.strip('|') for l in row[5].split(' ') if l] or None,
original=row,
@@ -123,12 +210,6 @@ def from_github_issue(issue: Dict):# -> PaperInfo:
raise RuntimeError(f"Issue doesn't have a title that we know how to parse: {issue}")
paper = match.group(1)
- # Figure out the status of the paper according to the Github project information.
- #
- # Sadly, we can't make a finer-grained distiction about *how* the issue
- # was closed (such as Nothing To Do or similar).
- status = '|Complete|' if 'status' in issue and issue['status'] == 'Done' else None
-
# Handle labels
valid_labels = ('format', 'ranges', 'spaceship', 'flat_containers', 'concurrency TS', 'DR')
labels = [label for label in issue['labels'] if label in valid_labels]
@@ -136,8 +217,8 @@ def from_github_issue(issue: Dict):# -> PaperInfo:
return PaperInfo(
paper_number=paper,
paper_name=issue['title'],
+ status=PaperStatus.from_github_issue(issue),
meeting=issue.get('meeting Voted', None),
- status=status,
first_released_version=None, # TODO
labels=labels if labels else None,
original=issue,
@@ -177,30 +258,34 @@ def sync_csv(rows: List[Tuple], from_github: List[PaperInfo]) -> List[Tuple]:
paper = PaperInfo.from_csv_row(row)
- # If the row is already implemented, basically keep it unchanged but also validate that we're not
- # out-of-sync with any still-open Github issue tracking the same paper.
- if paper.is_implemented():
- dangling = [gh for gh in from_github if gh.paper_number == paper.paper_number and not gh.is_implemented()]
- if dangling:
- print(f"We found the following open tracking issues for a row which is already marked as implemented:\nrow: {row}\ntracking issues: {dangling}")
- print("The Github issue should be closed if the work has indeed been done.")
- results.append(paper.for_printing())
- else:
- # Find any Github issues tracking this paper
- tracking = [gh for gh in from_github if paper.paper_number == gh.paper_number]
+ # Find any Github issues tracking this paper. Each row must have one and exactly one Github
+ # issue tracking it, which we validate below.
+ tracking = [gh for gh in from_github if paper.paper_number == gh.paper_number]
- # If there is no tracking issue for that row in the CSV, this is an error since we're
- # missing a Github issue.
- if not tracking:
- raise RuntimeError(f"Can't find any Github issue for CSV row which isn't marked as done yet: {row}")
+ # If there is no tracking issue for that row in the CSV, this is an error since we're
+ # missing a Github issue.
+ if len(tracking) == 0:
+ print(f"Can't find any Github issue for CSV row: {row}")
+ results.append(row)
+ continue
- # If there's more than one tracking issue, something is weird too.
- if len(tracking) > 1:
- raise RuntimeError(f"Found a row with more than one tracking issue: {row}\ntracked by: {tracking}")
+ # If there's more than one tracking issue, something is weird too.
+ if len(tracking) > 1:
+ print(f"Found a row with more than one tracking issue: {row}\ntracked by: {tracking}")
+ results.append(row)
+ continue
- # If the issue is closed, synchronize the row based on the Github issue. Otherwise, use the
- # existing CSV row as-is.
- results.append(tracking[0].for_printing() if tracking[0].is_implemented() else row)
+ gh = tracking[0]
+
+ # If the CSV row has a status that is "less advanced" than the Github issue, simply update the CSV
+ # row with the newer status. Otherwise, report an error if they have a
diff erent status because
+ # something must be wrong.
+ if paper.status < gh.status:
+ results.append(gh.for_printing())
+ continue
+ elif paper.status != gh.status:
+ print(f"We found a CSV row and a Github issue with
diff erent statuses:\nrow: {row}\Github issue: {gh}")
+ results.append(row)
return results
More information about the libcxx-commits
mailing list