diff --git a/bin/post_version.py b/bin/post_version.py index 359cbd9012c..c4779f143d7 100755 --- a/bin/post_version.py +++ b/bin/post_version.py @@ -22,6 +22,7 @@ """Update the main page, release notes, and calendar.""" import argparse +import csv import pathlib import subprocess @@ -52,30 +53,24 @@ def update_release_notes(version: str) -> None: def update_calendar(version: str) -> None: - p = pathlib.Path('docs') / 'release-calendar.rst' + p = pathlib.Path('docs') / 'release-calendar.csv' - with open(p, 'r') as f: - calendar = f.readlines() + with p.open('r') as f: + calendar = csv.reader(f) - branch = '' - skip_line = False - new_calendar = [] - for line in calendar: - if version in line: - branch = line.split('|')[1].strip() - skip_line = True - elif skip_line: - skip_line = False - elif branch: - # Put the branch number back on the next line - new_calendar.append(line[:2] + branch + line[len(branch) + 2:]) - branch = '' - else: - new_calendar.append(line) + branch = None + for i, line in enumerate(calendar): + if line[2] == version: + if line[0]: + branch = line[0] + break + if branch is not None: + calendar[i + 1][0] = branch + del calendar[i] - with open(p, 'w') as f: - for line in new_calendar: - f.write(line) + with p.open('w') as f: + writer = csv.writer(f) + writer.writerows(calendar) subprocess.run(['git', 'add', p]) diff --git a/bin/post_version_test.py b/bin/post_version_test.py index d0794a609f4..aa008bc4cc8 100644 --- a/bin/post_version_test.py +++ b/bin/post_version_test.py @@ -19,140 +19,49 @@ # SOFTWARE. from unittest import mock -import textwrap -from lxml import html import pytest from . import post_version -# Mock out subprocess.run to avoid having git commits @mock.patch('bin.post_version.subprocess.run', mock.Mock()) class TestUpdateCalendar: - HEAD = textwrap.dedent("""\ - - - - - Release Calendar - - - - """) - - TABLE = textwrap.dedent("""\ - - - - - - - - - """) - - FOOT = "" - - TABLE_FOOT = "
BranchExpected dateReleaseRelease managerNotes
" - - def wrap_table(self, table: str) -> str: - return self.HEAD + self.TABLE + table + self.TABLE_FOOT + self.FOOT + @pytest.fixture(autouse=True) + def mock_sideffects(self) -> None: + """Mock out side effects.""" + with mock.patch('bin.post_version.subprocess.run', mock.Mock()), \ + mock.patch('bin.post_version.pathlib', mock.MagicMock()): + yield def test_basic(self): - data = self.wrap_table(textwrap.dedent("""\ - - 19.2 - 2019-11-06 - 19.2.3 - Dylan Baker - - - 2019-11-20 - 19.2.4 - Dylan Baker - - - 2019-12-04 - 19.2.5 - Dylan Baker - Last planned 19.2.x release - - """)) + data = [ + ['20.3', '2021-01-13', '20.3.3', 'Dylan Baker', None], + [None, '2021-01-27', '20.3.4', 'Dylan Baker', None], + ] - parsed = html.fromstring(data) - parsed.write = mock.Mock() + m = mock.Mock() + with mock.patch('bin.post_version.csv.reader', mock.Mock(return_value=data.copy())), \ + mock.patch('bin.post_version.csv.writer', mock.Mock(return_value=m)): + post_version.update_calendar('20.3.3') - with mock.patch('bin.post_version.html.parse', - mock.Mock(return_value=parsed)): - post_version.update_calendar('19.2.3') + m.writerows.assert_called_with([data[1]]) - assert len(parsed.findall('.//tr')) == 3 - # we need the second element becouse the first is the header + def test_two_releases(self): + data = [ + ['20.3', '2021-01-13', '20.3.3', 'Dylan Baker', None], + [None, '2021-01-27', '20.3.4', 'Dylan Baker', None], + ['21.0', '2021-01-13', '21.0.0', 'Dylan Baker', None], + [None, '2021-01-13', '21.0.1', 'Dylan Baker', None], + ] - tr = parsed.findall('.//tr')[1] - tds = tr.findall('.//td') - assert tds[0].get("rowspan") == "2" - assert tds[0].text == "19.2" - assert tds[1].text == "2019-11-20" + m = mock.Mock() + with mock.patch('bin.post_version.csv.reader', mock.Mock(return_value=data.copy())), \ + mock.patch('bin.post_version.csv.writer', mock.Mock(return_value=m)): + post_version.update_calendar('20.3.3') - @pytest.fixture - def two_releases(self) -> html.etree.ElementTree: - data = self.wrap_table(textwrap.dedent("""\ - - 19.1 - 2019-11-06 - 19.1.8 - Not Dylan Baker - - - 19.2 - 2019-11-06 - 19.2.3 - Dylan Baker - - - 2019-11-20 - 19.2.4 - Dylan Baker - - - 2019-12-04 - 19.2.5 - Dylan Baker - Last planned 19.2.x release - - """)) - - p = html.fromstring(data) - p.write = mock.Mock() - return p - - def test_two_releases(self, two_releases: html.etree.ElementTree): - with mock.patch('bin.post_version.html.parse', - mock.Mock(return_value=two_releases)): - post_version.update_calendar('19.2.3') - - assert len(two_releases.findall('.//tr')) == 4 - # we need the second element becouse the first is the header - - tr = two_releases.findall('.//tr')[2] - tds = tr.findall('.//td') - assert tds[0].get("rowspan") == "2" - assert tds[0].text == "19.2" - assert tds[1].text == "2019-11-20" - - def test_last_Release(self, two_releases: html.etree.ElementTree): - with mock.patch('bin.post_version.html.parse', - mock.Mock(return_value=two_releases)): - post_version.update_calendar('19.1.8') - - assert len(two_releases.findall('.//tr')) == 4 - # we need the second element becouse the first is the header - - tr = two_releases.findall('.//tr')[1] - tds = tr.findall('.//td') - assert tds[0].get("rowspan") == "3" - assert tds[0].text == "19.2" - assert tds[1].text == "2019-11-06" + d = data.copy() + del d[0] + d[0][0] = '20.3' + m.writerows.assert_called_with(d) diff --git a/docs/release-calendar.csv b/docs/release-calendar.csv new file mode 100644 index 00000000000..9eec289f955 --- /dev/null +++ b/docs/release-calendar.csv @@ -0,0 +1,2 @@ +20.3, 2021-01-13, 20.3.3, Dylan Baker, + , 2021-01-27, 20.3.4, Dylan Baker, diff --git a/docs/release-calendar.rst b/docs/release-calendar.rst index 6181410d98a..4b4a854c799 100644 --- a/docs/release-calendar.rst +++ b/docs/release-calendar.rst @@ -27,10 +27,8 @@ nominate a patch in the next stable release. Calendar -------- -+--------+---------------+------------+-----------------+-----------------------------------------+ -| Branch | Expected date | Release | Release manager | Notes | -+========+===============+============+=================+=========================================+ -| 20.3 | 2021-01-13 | 20.3.3 | Dylan Baker | | -| +---------------+------------+-----------------+-----------------------------------------+ -| | 2021-01-27 | 20.3.4 | Dylan Baker | | -+--------+---------------+------------+-----------------+-----------------------------------------+ +.. csv-table:: Calendar + :header: "Branch", "Expected date", "Release", "Release manager", "Notes" + :file: release-calendar.csv + :stub-columns: 1 + :widths: auto diff --git a/docs/releasing.rst b/docs/releasing.rst index 49529f26506..b1f35c597d9 100644 --- a/docs/releasing.rst +++ b/docs/releasing.rst @@ -312,7 +312,7 @@ Then run the ./bin/post_version.py X.Y.Z , where X.Y.Z is the version you just made. This will update -docs/relnotes.rst and docs/release-calendar.rst. It will then generate +docs/relnotes.rst and docs/release-calendar.csv. It will then generate a Git commit automatically. Check that everything looks correct and push: