diff --git a/releases/ghc.json b/releases/ghc.json index 4fbefa4b..94b62cff 100644 --- a/releases/ghc.json +++ b/releases/ghc.json @@ -282,4 +282,4 @@ "date": "2011-08-07" } } -} \ No newline at end of file +} diff --git a/src/ghc-wiki.py b/src/ghc-wiki.py new file mode 100644 index 00000000..f95bbadf --- /dev/null +++ b/src/ghc-wiki.py @@ -0,0 +1,86 @@ +""" +In addition to automation from git tags, +use the GHC-status wiki page on GHC gitlab +as a source for "Not recommended for use" end-of-support signals. + +TODO at some point maybe use https://gitlab.haskell.org/ghc/release/release-metadata/ + +References: + https://github.com/endoflife-date/release-data/pull/395 + https://github.com/endoflife-date/endoflife.date/pull/6287 + https://gitlab.haskell.org/ghc/ghc/-/wikis/GHC-status +""" + +import re +from typing import Any, Generator, Iterator + +from common import dates, http, releasedata + + +def parse_markdown_tables(lineiter: Iterator[str]) -> Generator[list[list[Any]], Any, None]: + """ Generator. Yields found tables until StopIteration """ + while True: + try: + #-- fast-forward to table header + while True: + line = next(lineiter) + header = maybe_markdown_table_row(line) + if header: + break + #-- underline + hr = maybe_markdown_table_row(next(lineiter)) + assert len(hr) == len(header) + assert all(set(x) == {'-'} for x in hr) + #-- rows + rows = [] + while True: + line = next(lineiter) + cells = maybe_markdown_table_row(line) + if not cells: + break + assert len(cells) == len(header) + rows.append(cells) + yield [header] + rows + except StopIteration: + return # f**ing PEP 479 + +def maybe_markdown_table_row(line: str) -> list[str] | None: + line = line.strip() + if not re.match(r'[|].*[|]', line): + return None + return [x.strip() for x in line.strip('|').split('|')] + +with releasedata.ProductData("ghc") as product: + resp = http.fetch_url("https://gitlab.haskell.org/api/v4/projects/1/wikis/GHC-Status") + resp.raise_for_status() + data = resp.json() + assert data['title'] == "GHC Status" + assert data['format'] == "markdown" + md = data['content'].splitlines() + + #-- Parse tables out of the wiki text. At time of writing, the script expects exactly two: + #-- 1. "Most recent major" with 5 columns + #-- 2. "All released versions" with 5 columns + [series_table, patch_level] = parse_markdown_tables(iter(md)) + + for row in series_table[1:]: + [series, _download_link, _most_recent, next_planned, status] = row + series = series.split(' ') [0] + series = series.replace('\\.', '.') + if series == "Nightlies": + continue + status = status.lower() + + #-- See discussion in https://github.com/endoflife-date/endoflife.date/pull/6287 + r = product.get_release(series) + #-- The clearest semblance of an EOL signal we get + r.set_eol("not recommended for use" in status or ":red_circle:" in status) + #-- eoasColumn label is "Further releases planned" + r.set_eoas(any(keyword in next_planned for keyword in ("None", "N/A"))) + + for row in patch_level[1:]: + [milestone, _download_link, date, _ticket, _manager] = row + version = milestone.lstrip('%') + version = version.split(' ') [0] + date = dates.parse_date(date) + product.declare_version(version, date)