Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 249242a

Browse files
hugovkCAM-Gerlach
andauthored
Generate release cycle chart and CSV (#988)
Co-authored-by: C.A.M. Gerlach <[email protected]>
1 parent b62b865 commit 249242a

12 files changed

+411
-6
lines changed

.github/workflows/release-cycle.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Test release cycle
2+
3+
on: [pull_request, push, workflow_dispatch]
4+
5+
env:
6+
FORCE_COLOR: 1
7+
8+
jobs:
9+
test:
10+
runs-on: ${{ matrix.os }}
11+
strategy:
12+
fail-fast: false
13+
matrix:
14+
os: [windows-latest, ubuntu-latest]
15+
16+
steps:
17+
- uses: actions/checkout@v3
18+
19+
- uses: actions/setup-python@v4
20+
with:
21+
python-version: "3"
22+
23+
- name: Generate release cycle output
24+
run: python -I -bb -X dev -X warn_default_encoding -W error _tools/generate_release_cycle.py
25+
26+
- name: Check for differences
27+
run: |
28+
git add .
29+
git status
30+
git diff --staged
31+
test $(git status --porcelain | wc -l) = 0

Makefile

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ help:
3838
@echo " linkcheck to check all external links for integrity"
3939
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
4040
@echo " check to run a check for frequent markup errors"
41+
@echo " versions to update release cycle after changing release-cycle.json"
4142

4243
.PHONY: clean
4344
clean: clean-venv
@@ -66,7 +67,7 @@ ensure-venv:
6667
fi
6768

6869
.PHONY: html
69-
html: ensure-venv
70+
html: ensure-venv versions
7071
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
7172
@echo
7273
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
@@ -186,3 +187,16 @@ check: ensure-venv
186187
serve:
187188
@echo "The 'serve' target was removed, use 'htmlview' instead" \
188189
"(see https://github.com/python/cpython/issues/80510)"
190+
191+
include/branches.csv: include/release-cycle.json
192+
$(PYTHON) _tools/generate_release_cycle.py
193+
194+
include/end-of-life.csv: include/release-cycle.json
195+
$(PYTHON) _tools/generate_release_cycle.py
196+
197+
include/release-cycle.mmd: include/release-cycle.json
198+
$(PYTHON) _tools/generate_release_cycle.py
199+
200+
.PHONY: versions
201+
versions: include/branches.csv include/end-of-life.csv include/release-cycle.mmd
202+
@echo Release cycle data generated.

_static/devguide_overrides.css

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,68 @@
55
width: 111px;
66
height: 110px;
77
}
8+
9+
/* Release cycle chart */
10+
#python-release-cycle .mermaid .active0,
11+
#python-release-cycle .mermaid .active1,
12+
#python-release-cycle .mermaid .active2,
13+
#python-release-cycle .mermaid .active3 {
14+
fill: #00dd00;
15+
stroke: darkgreen;
16+
}
17+
18+
#python-release-cycle .mermaid .done0,
19+
#python-release-cycle .mermaid .done1,
20+
#python-release-cycle .mermaid .done2,
21+
#python-release-cycle .mermaid .done3 {
22+
fill: orange;
23+
stroke: darkorange;
24+
}
25+
26+
#python-release-cycle .mermaid .task0,
27+
#python-release-cycle .mermaid .task1,
28+
#python-release-cycle .mermaid .task2,
29+
#python-release-cycle .mermaid .task3 {
30+
fill: #007acc;
31+
stroke: #004455;
32+
}
33+
34+
#python-release-cycle .mermaid .section0,
35+
#python-release-cycle .mermaid .section2 {
36+
fill: darkgrey;
37+
}
38+
39+
/* Set master colours */
40+
:root {
41+
--mermaid-section1-3: white;
42+
--mermaid-text-color: black;
43+
}
44+
45+
@media (prefers-color-scheme: dark) {
46+
body[data-theme=auto] {
47+
--mermaid-section1-3: black;
48+
--mermaid-text-color: #ffffffcc;
49+
}
50+
}
51+
body[data-theme=dark] {
52+
--mermaid-section1-3: black;
53+
--mermaid-text-color: #ffffffcc;
54+
}
55+
56+
#python-release-cycle .mermaid .section1,
57+
#python-release-cycle .mermaid .section3 {
58+
fill: var(--mermaid-section1-3);
59+
}
60+
61+
#python-release-cycle .mermaid .grid .tick text,
62+
#python-release-cycle .mermaid .sectionTitle0,
63+
#python-release-cycle .mermaid .sectionTitle1,
64+
#python-release-cycle .mermaid .sectionTitle2,
65+
#python-release-cycle .mermaid .sectionTitle3,
66+
#python-release-cycle .mermaid .taskTextOutside0,
67+
#python-release-cycle .mermaid .taskTextOutside1,
68+
#python-release-cycle .mermaid .taskTextOutside2,
69+
#python-release-cycle .mermaid .taskTextOutside3,
70+
#python-release-cycle .mermaid .titleText {
71+
fill: var(--mermaid-text-color);
72+
}

_tools/generate_release_cycle.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
"""Read in a JSON and generate two CSVs and a Mermaid file."""
2+
from __future__ import annotations
3+
4+
import csv
5+
import datetime as dt
6+
import json
7+
8+
MERMAID_HEADER = """
9+
gantt
10+
dateFormat YYYY-MM-DD
11+
title Python release cycle
12+
axisFormat %Y
13+
""".lstrip()
14+
15+
MERMAID_SECTION = """
16+
section Python {version}
17+
{release_status} :{mermaid_status} python{version}, {first_release},{eol}
18+
""" # noqa: E501
19+
20+
MERMAID_STATUS_MAPPING = {
21+
"feature": "",
22+
"bugfix": "active,",
23+
"security": "done,",
24+
"end-of-life": "crit,",
25+
}
26+
27+
28+
def csv_date(date_str: str, now_str: str) -> str:
29+
"""Format a date for CSV."""
30+
if date_str > now_str:
31+
# Future, add italics
32+
return f"*{date_str}*"
33+
return date_str
34+
35+
36+
def mermaid_date(date_str: str) -> str:
37+
"""Format a date for Mermaid."""
38+
if len(date_str) == len("yyyy-mm"):
39+
# Mermaid needs a full yyyy-mm-dd, so let's approximate
40+
date_str = f"{date_str}-01"
41+
return date_str
42+
43+
44+
class Versions:
45+
"""For converting JSON to CSV and Mermaid."""
46+
47+
def __init__(self) -> None:
48+
with open("include/release-cycle.json", encoding="UTF-8") as in_file:
49+
self.versions = json.load(in_file)
50+
self.sorted_versions = sorted(
51+
self.versions.items(),
52+
key=lambda k: [int(i) for i in k[0].split(".")],
53+
reverse=True,
54+
)
55+
56+
def write_csv(self) -> None:
57+
"""Output CSV files."""
58+
now_str = str(dt.datetime.utcnow())
59+
60+
versions_by_category = {"branches": {}, "end-of-life": {}}
61+
headers = None
62+
for version, details in self.sorted_versions:
63+
row = {
64+
"Branch": details["branch"],
65+
"Schedule": f":pep:`{details['pep']}`",
66+
"Status": details["status"],
67+
"First release": csv_date(details["first_release"], now_str),
68+
"End of life": csv_date(details["end_of_life"], now_str),
69+
"Release manager": details["release_manager"],
70+
}
71+
headers = row.keys()
72+
cat = "end-of-life" if details["status"] == "end-of-life" else "branches"
73+
versions_by_category[cat][version] = row
74+
75+
for cat, versions in versions_by_category.items():
76+
with open(f"include/{cat}.csv", "w", encoding="UTF-8", newline="") as file:
77+
csv_file = csv.DictWriter(file, fieldnames=headers, lineterminator="\n")
78+
csv_file.writeheader()
79+
csv_file.writerows(versions.values())
80+
81+
def write_mermaid(self) -> None:
82+
"""Output Mermaid file."""
83+
out = [MERMAID_HEADER]
84+
85+
for version, details in reversed(self.versions.items()):
86+
v = MERMAID_SECTION.format(
87+
version=version,
88+
first_release=details["first_release"],
89+
eol=mermaid_date(details["end_of_life"]),
90+
release_status=details["status"],
91+
mermaid_status=MERMAID_STATUS_MAPPING[details["status"]],
92+
)
93+
out.append(v)
94+
95+
with open(
96+
"include/release-cycle.mmd", "w", encoding="UTF-8", newline="\n"
97+
) as f:
98+
f.writelines(out)
99+
100+
101+
def main() -> None:
102+
versions = Versions()
103+
versions.write_csv()
104+
versions.write_mermaid()
105+
106+
107+
if __name__ == "__main__":
108+
main()

conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
'sphinx.ext.intersphinx',
1111
'sphinx.ext.todo',
1212
'sphinx_copybutton',
13+
'sphinxcontrib.mermaid',
1314
'sphinxext.opengraph',
1415
'sphinxext.rediraffe',
1516
]

include/branches.csv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
Branch,Schedule,Status,First release,End-of-life,Release manager
2-
main,:pep:`693`,features,*2023-10-02*,*2028-10*,Thomas Wouters
1+
Branch,Schedule,Status,First release,End of life,Release manager
2+
main,:pep:`693`,feature,*2023-10-02*,*2028-10*,Thomas Wouters
33
3.11,:pep:`664`,bugfix,2022-10-24,*2027-10*,Pablo Galindo Salgado
44
3.10,:pep:`619`,bugfix,2021-10-04,*2026-10*,Pablo Galindo Salgado
55
3.9,:pep:`596`,security,2020-10-05,*2025-10*,Łukasz Langa

include/end-of-life.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Branch,Schedule,Status,First release,End-of-life,Release manager
1+
Branch,Schedule,Status,First release,End of life,Release manager
22
3.6,:pep:`494`,end-of-life,2016-12-23,2021-12-23,Ned Deily
33
3.5,:pep:`478`,end-of-life,2015-09-13,2020-09-30,Larry Hastings
44
3.4,:pep:`429`,end-of-life,2014-03-16,2019-03-18,Larry Hastings

include/release-cycle.json

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
{
2+
"3.12": {
3+
"branch": "main",
4+
"pep": 693,
5+
"status": "feature",
6+
"first_release": "2023-10-02",
7+
"end_of_life": "2028-10",
8+
"release_manager": "Thomas Wouters"
9+
},
10+
"3.11": {
11+
"branch": "3.11",
12+
"pep": 664,
13+
"status": "bugfix",
14+
"first_release": "2022-10-24",
15+
"end_of_life": "2027-10",
16+
"release_manager": "Pablo Galindo Salgado"
17+
},
18+
"3.10": {
19+
"branch": "3.10",
20+
"pep": 619,
21+
"status": "bugfix",
22+
"first_release": "2021-10-04",
23+
"end_of_life": "2026-10",
24+
"release_manager": "Pablo Galindo Salgado"
25+
},
26+
"3.9": {
27+
"branch": "3.9",
28+
"pep": 596,
29+
"status": "security",
30+
"first_release": "2020-10-05",
31+
"end_of_life": "2025-10",
32+
"release_manager": "Łukasz Langa"
33+
},
34+
"3.8": {
35+
"branch": "3.8",
36+
"pep": 569,
37+
"status": "security",
38+
"first_release": "2019-10-14",
39+
"end_of_life": "2024-10",
40+
"release_manager": "Łukasz Langa"
41+
},
42+
"3.7": {
43+
"branch": "3.7",
44+
"pep": 537,
45+
"status": "security",
46+
"first_release": "2018-06-27",
47+
"end_of_life": "2023-06-27",
48+
"release_manager": "Ned Deily"
49+
},
50+
"3.6": {
51+
"branch": "3.6",
52+
"pep": 494,
53+
"status": "end-of-life",
54+
"first_release": "2016-12-23",
55+
"end_of_life": "2021-12-23",
56+
"release_manager": "Ned Deily"
57+
},
58+
"3.5": {
59+
"branch": "3.5",
60+
"pep": 478,
61+
"status": "end-of-life",
62+
"first_release": "2015-09-13",
63+
"end_of_life": "2020-09-30",
64+
"release_manager": "Larry Hastings"
65+
},
66+
"3.4": {
67+
"branch": "3.4",
68+
"pep": 429,
69+
"status": "end-of-life",
70+
"first_release": "2014-03-16",
71+
"end_of_life": "2019-03-18",
72+
"release_manager": "Larry Hastings"
73+
},
74+
"3.3": {
75+
"branch": "3.3",
76+
"pep": 398,
77+
"status": "end-of-life",
78+
"first_release": "2012-09-29",
79+
"end_of_life": "2017-09-29",
80+
"release_manager": "Georg Brandl, Ned Deily (3.3.7+)"
81+
},
82+
"3.2": {
83+
"branch": "3.2",
84+
"pep": 392,
85+
"status": "end-of-life",
86+
"first_release": "2011-02-20",
87+
"end_of_life": "2016-02-20",
88+
"release_manager": "Georg Brandl"
89+
},
90+
"2.7": {
91+
"branch": "2.7",
92+
"pep": 373,
93+
"status": "end-of-life",
94+
"first_release": "2010-07-03",
95+
"end_of_life": "2020-01-01",
96+
"release_manager": "Benjamin Peterson"
97+
},
98+
"3.1": {
99+
"branch": "3.1",
100+
"pep": 375,
101+
"status": "end-of-life",
102+
"first_release": "2009-06-27",
103+
"end_of_life": "2012-04-09",
104+
"release_manager": "Benjamin Peterson"
105+
},
106+
"3.0": {
107+
"branch": "3.0",
108+
"pep": 361,
109+
"status": "end-of-life",
110+
"first_release": "2008-12-03",
111+
"end_of_life": "2009-06-27",
112+
"release_manager": "Barry Warsaw"
113+
},
114+
"2.6": {
115+
"branch": "2.6",
116+
"pep": 361,
117+
"status": "end-of-life",
118+
"first_release": "2008-10-01",
119+
"end_of_life": "2013-10-29",
120+
"release_manager": "Barry Warsaw"
121+
}
122+
}

0 commit comments

Comments
 (0)