Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate release cycle chart and CSV #988

Merged
merged 21 commits into from
Dec 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/release-cycle.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Test release cycle

on: [pull_request, push, workflow_dispatch]

env:
FORCE_COLOR: 1

jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-latest, ubuntu-latest]

steps:
- uses: actions/checkout@v3

- uses: actions/setup-python@v4
with:
python-version: "3"

- name: Generate release cycle output
run: python -I -bb -X dev -X warn_default_encoding -W error _tools/generate_release_cycle.py

- name: Check for differences
run: |
git add .
git status
git diff --staged
test $(git status --porcelain | wc -l) = 0
16 changes: 15 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ help:
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " check to run a check for frequent markup errors"
@echo " versions to update release cycle after changing release-cycle.json"

.PHONY: clean
clean: clean-venv
Expand Down Expand Up @@ -66,7 +67,7 @@ ensure-venv:
fi

.PHONY: html
html: ensure-venv
html: ensure-venv versions
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
Expand Down Expand Up @@ -186,3 +187,16 @@ check: ensure-venv
serve:
@echo "The 'serve' target was removed, use 'htmlview' instead" \
"(see https://github.com/python/cpython/issues/80510)"

include/branches.csv: include/release-cycle.json
$(PYTHON) _tools/generate_release_cycle.py

include/end-of-life.csv: include/release-cycle.json
$(PYTHON) _tools/generate_release_cycle.py

include/release-cycle.mmd: include/release-cycle.json
$(PYTHON) _tools/generate_release_cycle.py

.PHONY: versions
versions: include/branches.csv include/end-of-life.csv include/release-cycle.mmd
@echo Release cycle data generated.
65 changes: 65 additions & 0 deletions _static/devguide_overrides.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,68 @@
width: 111px;
height: 110px;
}

/* Release cycle chart */
#python-release-cycle .mermaid .active0,
#python-release-cycle .mermaid .active1,
#python-release-cycle .mermaid .active2,
#python-release-cycle .mermaid .active3 {
fill: #00dd00;
stroke: darkgreen;
}

#python-release-cycle .mermaid .done0,
#python-release-cycle .mermaid .done1,
#python-release-cycle .mermaid .done2,
#python-release-cycle .mermaid .done3 {
fill: orange;
stroke: darkorange;
}

#python-release-cycle .mermaid .task0,
#python-release-cycle .mermaid .task1,
#python-release-cycle .mermaid .task2,
#python-release-cycle .mermaid .task3 {
fill: #007acc;
stroke: #004455;
}

#python-release-cycle .mermaid .section0,
#python-release-cycle .mermaid .section2 {
fill: darkgrey;
}

/* Set master colours */
:root {
--mermaid-section1-3: white;
--mermaid-text-color: black;
}

@media (prefers-color-scheme: dark) {
body[data-theme=auto] {
--mermaid-section1-3: black;
--mermaid-text-color: #ffffffcc;
}
}
body[data-theme=dark] {
--mermaid-section1-3: black;
--mermaid-text-color: #ffffffcc;
}

#python-release-cycle .mermaid .section1,
#python-release-cycle .mermaid .section3 {
fill: var(--mermaid-section1-3);
}

#python-release-cycle .mermaid .grid .tick text,
#python-release-cycle .mermaid .sectionTitle0,
#python-release-cycle .mermaid .sectionTitle1,
#python-release-cycle .mermaid .sectionTitle2,
#python-release-cycle .mermaid .sectionTitle3,
#python-release-cycle .mermaid .taskTextOutside0,
#python-release-cycle .mermaid .taskTextOutside1,
#python-release-cycle .mermaid .taskTextOutside2,
#python-release-cycle .mermaid .taskTextOutside3,
#python-release-cycle .mermaid .titleText {
fill: var(--mermaid-text-color);
}
108 changes: 108 additions & 0 deletions _tools/generate_release_cycle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"""Read in a JSON and generate two CSVs and a Mermaid file."""
from __future__ import annotations

import csv
import datetime as dt
import json

MERMAID_HEADER = """
gantt
dateFormat YYYY-MM-DD
title Python release cycle
axisFormat %Y
""".lstrip()

MERMAID_SECTION = """
section Python {version}
{release_status} :{mermaid_status} python{version}, {first_release},{eol}
""" # noqa: E501

MERMAID_STATUS_MAPPING = {
"feature": "",
"bugfix": "active,",
"security": "done,",
"end-of-life": "crit,",
}


def csv_date(date_str: str, now_str: str) -> str:
"""Format a date for CSV."""
if date_str > now_str:
# Future, add italics
return f"*{date_str}*"
return date_str


def mermaid_date(date_str: str) -> str:
"""Format a date for Mermaid."""
if len(date_str) == len("yyyy-mm"):
# Mermaid needs a full yyyy-mm-dd, so let's approximate
date_str = f"{date_str}-01"
return date_str


class Versions:
"""For converting JSON to CSV and Mermaid."""

def __init__(self) -> None:
with open("include/release-cycle.json", encoding="UTF-8") as in_file:
self.versions = json.load(in_file)
self.sorted_versions = sorted(
self.versions.items(),
key=lambda k: [int(i) for i in k[0].split(".")],
reverse=True,
)

def write_csv(self) -> None:
"""Output CSV files."""
now_str = str(dt.datetime.utcnow())

versions_by_category = {"branches": {}, "end-of-life": {}}
headers = None
for version, details in self.sorted_versions:
row = {
"Branch": details["branch"],
"Schedule": f":pep:`{details['pep']}`",
"Status": details["status"],
"First release": csv_date(details["first_release"], now_str),
"End of life": csv_date(details["end_of_life"], now_str),
"Release manager": details["release_manager"],
}
headers = row.keys()
cat = "end-of-life" if details["status"] == "end-of-life" else "branches"
versions_by_category[cat][version] = row

for cat, versions in versions_by_category.items():
with open(f"include/{cat}.csv", "w", encoding="UTF-8", newline="") as file:
csv_file = csv.DictWriter(file, fieldnames=headers, lineterminator="\n")
csv_file.writeheader()
csv_file.writerows(versions.values())

def write_mermaid(self) -> None:
"""Output Mermaid file."""
out = [MERMAID_HEADER]

for version, details in reversed(self.versions.items()):
v = MERMAID_SECTION.format(
version=version,
first_release=details["first_release"],
eol=mermaid_date(details["end_of_life"]),
release_status=details["status"],
mermaid_status=MERMAID_STATUS_MAPPING[details["status"]],
)
out.append(v)

with open(
"include/release-cycle.mmd", "w", encoding="UTF-8", newline="\n"
) as f:
f.writelines(out)


def main() -> None:
versions = Versions()
versions.write_csv()
versions.write_mermaid()


if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
'sphinx.ext.intersphinx',
'sphinx.ext.todo',
'sphinx_copybutton',
'sphinxcontrib.mermaid',
'sphinxext.opengraph',
'sphinxext.rediraffe',
]
Expand Down
4 changes: 2 additions & 2 deletions include/branches.csv
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Branch,Schedule,Status,First release,End-of-life,Release manager
main,:pep:`693`,features,*2023-10-02*,*2028-10*,Thomas Wouters
Branch,Schedule,Status,First release,End of life,Release manager
main,:pep:`693`,feature,*2023-10-02*,*2028-10*,Thomas Wouters
3.11,:pep:`664`,bugfix,2022-10-24,*2027-10*,Pablo Galindo Salgado
3.10,:pep:`619`,bugfix,2021-10-04,*2026-10*,Pablo Galindo Salgado
3.9,:pep:`596`,security,2020-10-05,*2025-10*,Łukasz Langa
Expand Down
2 changes: 1 addition & 1 deletion include/end-of-life.csv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Branch,Schedule,Status,First release,End-of-life,Release manager
Branch,Schedule,Status,First release,End of life,Release manager
3.6,:pep:`494`,end-of-life,2016-12-23,2021-12-23,Ned Deily
3.5,:pep:`478`,end-of-life,2015-09-13,2020-09-30,Larry Hastings
3.4,:pep:`429`,end-of-life,2014-03-16,2019-03-18,Larry Hastings
Expand Down
122 changes: 122 additions & 0 deletions include/release-cycle.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
{
"3.12": {
"branch": "main",
"pep": 693,
"status": "feature",
"first_release": "2023-10-02",
"end_of_life": "2028-10",
"release_manager": "Thomas Wouters"
},
"3.11": {
"branch": "3.11",
"pep": 664,
"status": "bugfix",
"first_release": "2022-10-24",
"end_of_life": "2027-10",
"release_manager": "Pablo Galindo Salgado"
},
"3.10": {
"branch": "3.10",
"pep": 619,
"status": "bugfix",
"first_release": "2021-10-04",
"end_of_life": "2026-10",
"release_manager": "Pablo Galindo Salgado"
},
"3.9": {
"branch": "3.9",
"pep": 596,
"status": "security",
"first_release": "2020-10-05",
"end_of_life": "2025-10",
"release_manager": "Łukasz Langa"
},
"3.8": {
"branch": "3.8",
"pep": 569,
"status": "security",
"first_release": "2019-10-14",
"end_of_life": "2024-10",
"release_manager": "Łukasz Langa"
},
"3.7": {
"branch": "3.7",
"pep": 537,
"status": "security",
"first_release": "2018-06-27",
"end_of_life": "2023-06-27",
"release_manager": "Ned Deily"
},
"3.6": {
"branch": "3.6",
"pep": 494,
"status": "end-of-life",
"first_release": "2016-12-23",
"end_of_life": "2021-12-23",
"release_manager": "Ned Deily"
},
"3.5": {
"branch": "3.5",
"pep": 478,
"status": "end-of-life",
"first_release": "2015-09-13",
"end_of_life": "2020-09-30",
"release_manager": "Larry Hastings"
},
"3.4": {
"branch": "3.4",
"pep": 429,
"status": "end-of-life",
"first_release": "2014-03-16",
"end_of_life": "2019-03-18",
"release_manager": "Larry Hastings"
},
"3.3": {
"branch": "3.3",
"pep": 398,
"status": "end-of-life",
"first_release": "2012-09-29",
"end_of_life": "2017-09-29",
"release_manager": "Georg Brandl, Ned Deily (3.3.7+)"
},
"3.2": {
"branch": "3.2",
"pep": 392,
"status": "end-of-life",
"first_release": "2011-02-20",
"end_of_life": "2016-02-20",
"release_manager": "Georg Brandl"
},
"2.7": {
"branch": "2.7",
"pep": 373,
"status": "end-of-life",
"first_release": "2010-07-03",
"end_of_life": "2020-01-01",
"release_manager": "Benjamin Peterson"
},
"3.1": {
"branch": "3.1",
"pep": 375,
"status": "end-of-life",
"first_release": "2009-06-27",
"end_of_life": "2012-04-09",
"release_manager": "Benjamin Peterson"
},
"3.0": {
"branch": "3.0",
"pep": 361,
"status": "end-of-life",
"first_release": "2008-12-03",
"end_of_life": "2009-06-27",
"release_manager": "Barry Warsaw"
},
"2.6": {
"branch": "2.6",
"pep": 361,
"status": "end-of-life",
"first_release": "2008-10-01",
"end_of_life": "2013-10-29",
"release_manager": "Barry Warsaw"
}
}
Loading