[libcxx-commits] [libcxx] [libc++] Add a script to synchronize status-tracking CSVs with Github issues (PR #101704)
via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Aug 2 09:19:15 PDT 2024
github-actions[bot] wrote:
<!--LLVM CODE FORMAT COMMENT: {darker}-->
:warning: Python code formatter, darker found issues in your code. :warning:
<details>
<summary>
You can test this locally with the following command:
</summary>
``````````bash
darker --check --diff -r 937cbe270e5ee4e2e4d6f5568768a55d5e383076...9213b2bcec4fe24cc710e4b0937d11bbc11bdcf2 libcxx/utils/synchronize_csv_status_files.py
``````````
</details>
<details>
<summary>
View the diff from darker here.
</summary>
``````````diff
--- synchronize_csv_status_files.py 2024-08-02 15:57:58.000000 +0000
+++ synchronize_csv_status_files.py 2024-08-02 16:18:48.860075 +0000
@@ -8,11 +8,12 @@
import pathlib
import re
import subprocess
# Number of the 'Libc++ Standards Conformance' project on Github
-LIBCXX_CONFORMANCE_PROJECT = '31'
+LIBCXX_CONFORMANCE_PROJECT = "31"
+
class PaperInfo:
paper_number: str
"""
Identifier for the paper or the LWG issue. This must be something like 'PnnnnRx', 'Nxxxxx' or 'LWGxxxxx'.
@@ -49,46 +50,58 @@
"""
Object from which this PaperInfo originated. This is used to track the CSV row or Github issue that
was used to generate this PaperInfo and is useful for error reporting purposes.
"""
- def __init__(self, paper_number: str, paper_name: str,
- meeting: Optional[str] = None,
- status: Optional[str] = None,
- first_released_version: Optional[str] = None,
- labels: Optional[List[str]] = None,
- original: Optional[object] = None):
+ def __init__(
+ self,
+ paper_number: str,
+ paper_name: str,
+ 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.first_released_version = first_released_version
self.labels = labels
self.original = original
def for_printing(self) -> Tuple[str, str, str, str, str, str]:
return (
- f'`{self.paper_number} <https://wg21.link/{self.paper_number}>`__',
+ 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.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 '',
+ self.meeting if self.meeting is not None else "",
+ self.status if self.status is not None else "",
+ 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 "",
)
def __repr__(self) -> str:
- return repr(self.original) if self.original is not None else repr(self.for_printing())
+ 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()):
+ 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:
+ def from_csv_row(row: Tuple[str, str, str, str, str, str]): # -> PaperInfo:
"""
Given a row from one of our status-tracking CSV files, create a PaperInfo object representing that row.
"""
# Extract the paper number from the first column
match = re.search(r"((P[0-9R]+)|(LWG[0-9]+)|(N[0-9]+))\s+", row[0])
@@ -99,58 +112,72 @@
paper_number=match.group(1),
paper_name=row[1],
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,
+ labels=[l.strip("|") for l in row[5].split(" ") if l] or None,
original=row,
)
@staticmethod
- def from_github_issue(issue: Dict):# -> PaperInfo:
+ def from_github_issue(issue: Dict): # -> PaperInfo:
"""
Create a PaperInfo object from the Github issue information obtained from querying a Github Project.
"""
# Extract the paper number from the issue title
- match = re.search(r"((P[0-9R]+)|(LWG[0-9]+)|(N[0-9]+)):", issue['title'])
+ match = re.search(r"((P[0-9R]+)|(LWG[0-9]+)|(N[0-9]+)):", issue["title"])
if match is None:
- raise RuntimeError(f"Issue doesn't have a title that we know how to parse: {issue}")
+ 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
+ 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]
+ valid_labels = (
+ "format",
+ "ranges",
+ "spaceship",
+ "flat_containers",
+ "concurrency TS",
+ "DR",
+ )
+ labels = [label for label in issue["labels"] if label in valid_labels]
return PaperInfo(
paper_number=paper,
- paper_name=issue['title'],
- meeting=issue.get('meeting Voted', None),
+ paper_name=issue["title"],
+ meeting=issue.get("meeting Voted", None),
status=status,
- first_released_version=None, # TODO
+ first_released_version=None, # TODO
labels=labels if labels else None,
original=issue,
)
+
def load_csv(file: pathlib.Path) -> List[Tuple]:
rows = []
- with open(file, newline='') as f:
- reader = csv.reader(f, delimiter=',')
+ with open(file, newline="") as f:
+ reader = csv.reader(f, delimiter=",")
for row in reader:
rows.append(row)
return rows
+
def write_csv(output: pathlib.Path, rows: List[Tuple]):
- with open(output, 'w', newline='') as f:
- writer = csv.writer(f, quoting=csv.QUOTE_ALL, lineterminator='\n')
+ with open(output, "w", newline="") as f:
+ writer = csv.writer(f, quoting=csv.QUOTE_ALL, lineterminator="\n")
for row in rows:
writer.writerow(row)
+
def sync_csv(rows: List[Tuple], from_github: List[PaperInfo]) -> List[Tuple]:
"""
Given a list of CSV rows representing an existing status file and a list of PaperInfos representing
up-to-date (but potentially incomplete) tracking information from Github, this function returns the
@@ -158,12 +185,12 @@
Note that this only tracks changes from 'not implemented' issues to 'implemented'. If an up-to-date
PaperInfo reports that a paper is not implemented but the existing CSV rows report it as implemented,
it is an error (i.e. the result is not a CSV row where the paper is *not* implemented).
"""
- results = [rows[0]] # Start with the header
- for row in rows[1:]: # Skip the header
+ results = [rows[0]] # Start with the header
+ for row in rows[1:]: # Skip the header
# If the row contains empty entries, this is a "separator row" between meetings.
# Preserve it as-is.
if row[0] == "":
results.append(row)
continue
@@ -171,59 +198,89 @@
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()]
+ dangling = [
+ gh
+ for gh in from_github
+ if gh.paper_number == paper.paper_number and not gh.is_implemented()
+ ]
if dangling:
- raise RuntimeError(f"We found the following open tracking issues for a row which is already marked as implemented:\nrow: {row}\ntracking issues: {dangling}")
+ raise RuntimeError(
+ f"We found the following open tracking issues for a row which is already marked as implemented:\nrow: {row}\ntracking issues: {dangling}"
+ )
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]
+ 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}")
+ raise RuntimeError(
+ f"Can't find any Github issue for CSV row which isn't marked as done yet: {row}"
+ )
# 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}")
+ raise RuntimeError(
+ f"Found a row with more than one tracking issue: {row}\ntracked by: {tracking}"
+ )
# 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)
+ results.append(
+ tracking[0].for_printing() if tracking[0].is_implemented() else row
+ )
return results
+
CSV_FILES_TO_SYNC = [
- 'Cxx14Issues.csv',
- 'Cxx17Issues.csv',
- 'Cxx17Papers.csv',
- 'Cxx20Issues.csv',
- 'Cxx20Papers.csv',
+ "Cxx14Issues.csv",
+ "Cxx17Issues.csv",
+ "Cxx17Papers.csv",
+ "Cxx20Issues.csv",
+ "Cxx20Papers.csv",
# TODO: The Github issues are not created yet.
# 'Cxx23Issues.csv',
# 'Cxx23Papers.csv',
# 'Cxx2cIssues.csv',
# 'Cxx2cPapers.csv',
]
+
def main():
- libcxx_root = pathlib.Path(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+ libcxx_root = pathlib.Path(
+ os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+ )
# Extract the list of PaperInfos from issues we're tracking on Github.
print("Loading all issues from Github")
- gh_command_line = ['gh', 'project', 'item-list', LIBCXX_CONFORMANCE_PROJECT, '--owner', 'llvm', '--format', 'json', '--limit', '9999999']
+ gh_command_line = [
+ "gh",
+ "project",
+ "item-list",
+ LIBCXX_CONFORMANCE_PROJECT,
+ "--owner",
+ "llvm",
+ "--format",
+ "json",
+ "--limit",
+ "9999999",
+ ]
project_info = json.loads(subprocess.check_output(gh_command_line))
- from_github = [PaperInfo.from_github_issue(i) for i in project_info['items']]
+ from_github = [PaperInfo.from_github_issue(i) for i in project_info["items"]]
for filename in CSV_FILES_TO_SYNC:
print(f"Synchronizing {filename} with Github issues")
- file = libcxx_root / 'docs' / 'Status' / filename
+ file = libcxx_root / "docs" / "Status" / filename
csv = load_csv(file)
synced = sync_csv(csv, from_github)
write_csv(file, synced)
-if __name__ == '__main__':
+
+if __name__ == "__main__":
main()
``````````
</details>
https://github.com/llvm/llvm-project/pull/101704
More information about the libcxx-commits
mailing list