From 4b2de693544e039bb2e28a2ffa518c613839c97b Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 10 May 2018 10:37:20 +0100 Subject: [PATCH] Scan all branches for cache generation To date, both the 'reno cache' tool and related distutils command only scanned the current branch. This resulted in an incomplete cache for projects that used multiple branches. Resolve this by including info from all enabled branches. Change-Id: Ibe92a9fa5f42b5a7160201cd64ee6a93f9a78229 Signed-off-by: Stephen Finucane Story: #1565544 Task: #14465 --- ...he-scan-all-branches-a935824a844d1d9f.yaml | 6 +++ reno/cache.py | 10 ++++- reno/scanner.py | 14 +++---- reno/tests/test_cache.py | 40 ++++++++++++++----- reno/tests/test_scanner.py | 8 ++-- 5 files changed, 57 insertions(+), 21 deletions(-) create mode 100644 releasenotes/notes/cache-scan-all-branches-a935824a844d1d9f.yaml diff --git a/releasenotes/notes/cache-scan-all-branches-a935824a844d1d9f.yaml b/releasenotes/notes/cache-scan-all-branches-a935824a844d1d9f.yaml new file mode 100644 index 0000000..0102507 --- /dev/null +++ b/releasenotes/notes/cache-scan-all-branches-a935824a844d1d9f.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + The ``reno cache`` command and ``build_reno`` setuptools command now + default to scanning to all enabled branches. This ensures the cache is + complete for projects that use multiple branches, such as stable branches. diff --git a/reno/cache.py b/reno/cache.py index 20c2a8e..326bae6 100644 --- a/reno/cache.py +++ b/reno/cache.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +import collections import os import sys @@ -21,7 +22,14 @@ from reno import scanner def build_cache_db(conf, versions_to_include): s = scanner.Scanner(conf) - notes = s.get_notes_by_version() + + branches = [conf.branch] + if not conf.branch: # if no branch requested, scan all + branches += s.get_series_branches() + + notes = collections.OrderedDict() + for branch in branches: + notes.update(s.get_notes_by_version(branch)) # Default to including all versions returned by the scanner. if not versions_to_include: diff --git a/reno/scanner.py b/reno/scanner.py index da7f88a..d1dca86 100644 --- a/reno/scanner.py +++ b/reno/scanner.py @@ -810,7 +810,7 @@ class Scanner(object): "Return true if the file exists at the given commit." return bool(self.get_file_at_commit(filename, sha)) - def _get_series_branches(self): + def get_series_branches(self): "Get branches matching the branch_name_re config option." refs = self._repo.get_refs() LOG.debug('refs %s', list(refs.keys())) @@ -846,7 +846,7 @@ class Scanner(object): if branch.startswith('origin/'): branch = branch[7:] LOG.debug('looking for the branch before %s', branch) - branch_names = self._get_series_branches() + branch_names = self.get_series_branches() if branch not in branch_names: LOG.debug('Could not find branch %r among %s', branch, branch_names) @@ -910,7 +910,7 @@ class Scanner(object): return candidate return None - def get_notes_by_version(self): + def get_notes_by_version(self, branch=None): """Return an OrderedDict mapping versions to lists of notes files. The versions are presented in reverse chronological order. @@ -918,13 +918,13 @@ class Scanner(object): Notes files are associated with the earliest version for which they were available, regardless of whether they changed later. - :param reporoot: Path to the root of the git repository. - :type reporoot: str + :param branch: The branch to scan. If not provided, using the branch + configured in ``self.conf``. """ reporoot = self.reporoot notesdir = self.conf.notespath - branch = self.conf.branch + branch = branch or self.conf.branch earliest_version = self.conf.earliest_version collapse_pre_releases = self.conf.collapse_pre_releases stop_at_branch_base = self.conf.stop_at_branch_base @@ -967,7 +967,7 @@ class Scanner(object): # On the current branch, stop at the point where the most # recent branch was created, if we can find one. LOG.debug('working on current branch without earliest_version') - branches = self._get_series_branches() + branches = self.get_series_branches() if branches: for earlier_branch in reversed(branches): LOG.debug('checking if current branch is later than %s', diff --git a/reno/tests/test_cache.py b/reno/tests/test_cache.py index abf19a2..5d158d4 100644 --- a/reno/tests/test_cache.py +++ b/reno/tests/test_cache.py @@ -12,6 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. +import collections import fixtures import textwrap @@ -24,10 +25,15 @@ from reno.tests import base class TestCache(base.TestCase): - scanner_output = { - '0.0.0': [('note1', 'shaA')], - '1.0.0': [('note2', 'shaB'), ('note3', 'shaC')], - } + scanner_output = [ + collections.OrderedDict([ # master + ('0.0.0', [('note1', 'shaA')]), + ('1.0.0', [('note2', 'shaB'), ('note3', 'shaC')]), + ]), + collections.OrderedDict([ # stable/1.0 + ('1.0.1', [('note4', 'shaD')]), + ]), + ] note_bodies = { 'note1': textwrap.dedent(""" @@ -42,7 +48,11 @@ class TestCache(base.TestCase): 'note3': textwrap.dedent(""" features: - We added a feature! - """) + """), + 'note4': textwrap.dedent(""" + fixes: + - We fixed all the bugs! + """), } def _get_note_body(self, filename, sha): @@ -57,12 +67,18 @@ class TestCache(base.TestCase): self.c = config.Config('.') @mock.patch('reno.scanner.Scanner.get_notes_by_version') - def test_build_cache_db(self, gnbv): - gnbv.return_value = self.scanner_output + @mock.patch('reno.scanner.Scanner.get_series_branches') + def test_build_cache_db(self, mock_get_branches, mock_get_notes): + mock_get_notes.side_effect = self.scanner_output + mock_get_branches.return_value = ['stable/1.0'] expected = { 'notes': [ - {'version': k, 'files': v} - for k, v in self.scanner_output.items() + {'version': '0.0.0', + 'files': [('note1', 'shaA')]}, + {'version': '1.0.0', + 'files': [('note2', 'shaB'), ('note3', 'shaC')]}, + {'version': '1.0.1', + 'files': [('note4', 'shaD')]}, ], 'file-contents': { 'note1': { @@ -77,6 +93,9 @@ class TestCache(base.TestCase): 'note3': { 'features': ['We added a feature!'], }, + 'note4': { + 'fixes': ['We fixed all the bugs!'], + }, }, } @@ -85,4 +104,7 @@ class TestCache(base.TestCase): versions_to_include=[], ) + mock_get_branches.assert_called_once() + mock_get_notes.assert_has_calls([ + mock.call(None), mock.call('stable/1.0')]) self.assertEqual(expected, db) diff --git a/reno/tests/test_scanner.py b/reno/tests/test_scanner.py index 5c7a794..297188c 100644 --- a/reno/tests/test_scanner.py +++ b/reno/tests/test_scanner.py @@ -2432,7 +2432,7 @@ class GetSeriesBranchesTest(Base): self.scanner = scanner.Scanner(self.c) self.assertEqual( [], - self.scanner._get_series_branches(), + self.scanner.get_series_branches(), ) def test_real_branches_sorted_names(self): @@ -2445,7 +2445,7 @@ class GetSeriesBranchesTest(Base): self.scanner = scanner.Scanner(self.c) self.assertEqual( ['stable/a', 'stable/b'], - self.scanner._get_series_branches(), + self.scanner.get_series_branches(), ) def test_eol_tag(self): @@ -2455,7 +2455,7 @@ class GetSeriesBranchesTest(Base): self.scanner = scanner.Scanner(self.c) self.assertEqual( ['stable/a'], - self.scanner._get_series_branches(), + self.scanner.get_series_branches(), ) def test_mix_tag_and_branch(self): @@ -2468,5 +2468,5 @@ class GetSeriesBranchesTest(Base): self.scanner = scanner.Scanner(self.c) self.assertEqual( ['stable/a', 'stable/b'], - self.scanner._get_series_branches(), + self.scanner.get_series_branches(), )