From 3868499790fa833f685a5f64c5a4f68bbe226bbf Mon Sep 17 00:00:00 2001 From: Stan Brunau Date: Mon, 10 Feb 2025 15:32:01 +0100 Subject: [PATCH 1/3] Add path option to only show commits for a specific directory --- sphinx_git/__init__.py | 10 ++++++---- tests/test_git_changelog.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/sphinx_git/__init__.py b/sphinx_git/__init__.py index 958e189..4854a1a 100644 --- a/sphinx_git/__init__.py +++ b/sphinx_git/__init__.py @@ -119,6 +119,7 @@ class GitChangelog(GitDirectiveBase): 'hide_date': bool, 'hide_details': bool, 'repo-dir': six.text_type, + 'path': directives.path, } def run(self): @@ -138,10 +139,11 @@ def _commits_to_display(self): return commits def _filter_commits(self, repo): - if 'rev-list' in self.options: - commits = repo.iter_commits(rev=self.options['rev-list']) - else: - commits = repo.iter_commits() + commits = repo.iter_commits( + rev=self.options.get('rev-list', None), + paths=self.options.get('path', ''), + ) + if 'rev-list' not in self.options: revisions_to_display = self.options.get('revisions', 10) commits = list(commits)[:revisions_to_display] if 'filename_filter' in self.options: diff --git a/tests/test_git_changelog.py b/tests/test_git_changelog.py index fd92774..9013a5c 100644 --- a/tests/test_git_changelog.py +++ b/tests/test_git_changelog.py @@ -280,6 +280,37 @@ def test_single_commit_message_hide_date(self): assert_not_in(' at ', par_children[1].text) assert_in(' by ', par_children[1].text) + def test_path_filter(self): + self.repo.index.commit('initial') + dirnames = ['dir1', 'dir2'] + for dirname in dirnames: + full_dir_path = os.path.join(self.repo.working_tree_dir, dirname) + os.mkdir(full_dir_path) + full_file_path = os.path.join(full_dir_path, 'test.txt') + f = open(full_file_path, 'w+') + f.close() + self.repo.index.add([full_file_path]) + self.repo.index.commit('commit to file in {}'.format(dirname)) + self.repo.index.commit('commit without file in a specific directory') + + dirname_ut = dirnames[0] + self.changelog.options.update({'path': "{}/".format(dirname_ut)}) + nodes = self.changelog.run() + assert_equal(1, len(nodes)) + list_markup = BeautifulSoup(str(nodes[0]), features='xml') + assert_equal(1, len(list_markup.findAll('bullet_list'))) + + bullet_list = list_markup.bullet_list + assert_equal(1, len(bullet_list.findAll('list_item')), nodes) + + item = list_markup.bullet_list.list_item + children = list(item.childGenerator()) + assert_equal(1, len(children)) + par_children = list(item.paragraph.childGenerator()) + assert_equal(5, len(par_children)) + assert_equal('commit to file in {}'.format(dirname_ut), + par_children[0].text) + class TestWithOtherRepository(TestWithRepository): """ From debf05a5f88a747aa54d04651bd566e964393a6d Mon Sep 17 00:00:00 2001 From: Stan Brunau Date: Mon, 10 Feb 2025 15:36:57 +0100 Subject: [PATCH 2/3] Add first_parent and no_merges options --- sphinx_git/__init__.py | 7 +++++ tests/test_git_changelog.py | 51 +++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/sphinx_git/__init__.py b/sphinx_git/__init__.py index 4854a1a..41333a4 100644 --- a/sphinx_git/__init__.py +++ b/sphinx_git/__init__.py @@ -120,6 +120,8 @@ class GitChangelog(GitDirectiveBase): 'hide_details': bool, 'repo-dir': six.text_type, 'path': directives.path, + 'first_parent': bool, + 'no_merges': bool, } def run(self): @@ -139,9 +141,14 @@ def _commits_to_display(self): return commits def _filter_commits(self, repo): + first_parent = 'first_parent' in self.options + no_merges = 'no_merges' in self.options + commits = repo.iter_commits( rev=self.options.get('rev-list', None), paths=self.options.get('path', ''), + first_parent=first_parent, + no_merges=no_merges, ) if 'rev-list' not in self.options: revisions_to_display = self.options.get('revisions', 10) diff --git a/tests/test_git_changelog.py b/tests/test_git_changelog.py index 9013a5c..13e5677 100644 --- a/tests/test_git_changelog.py +++ b/tests/test_git_changelog.py @@ -311,6 +311,57 @@ def test_path_filter(self): assert_equal('commit to file in {}'.format(dirname_ut), par_children[0].text) + def _merge_test_setup(self): + self.repo.index.commit('initial') + original_branch = self.repo.active_branch + + # Create a new branch and add a commit to it + new_branch = self.repo.create_head('newbranch') + new_branch.checkout() + file_path = os.path.join(self.repo.working_tree_dir, 'test.txt') + f = open(file_path, 'w+') + f.close() + self.repo.index.add([file_path]) + self.repo.index.commit('regular commit') + + # Merge the new branch into the original branch + original_branch.checkout() + base = self.repo.merge_base(original_branch, new_branch) + self.repo.index.merge_tree(new_branch, base=base) + parent_commits = (original_branch.commit, new_branch.commit) + self.repo.index.commit('merge commit', parent_commits=parent_commits) + + def test_merge_commit_show_first_parent_only(self): + self._merge_test_setup() + + self.changelog.options.update({'first_parent': True}) + nodes = self.changelog.run() + assert_equal(1, len(nodes)) + list_markup = BeautifulSoup(str(nodes[0]), features='xml') + assert_equal(1, len(list_markup.findAll('bullet_list'))) + bullet_list = list_markup.bullet_list + # Expect the initial commit & the merge commit + assert_equal(2, len(bullet_list.findAll('list_item'))) + # Verify the regular commit is not in the changelog + for child in bullet_list.childGenerator(): + assert_not_in('regular commit', child.text) + + def test_merge_commit_show_no_merges(self): + self._merge_test_setup() + + # Test git changelog + self.changelog.options.update({'no_merges': True}) + nodes = self.changelog.run() + assert_equal(1, len(nodes)) + list_markup = BeautifulSoup(str(nodes[0]), features='xml') + assert_equal(1, len(list_markup.findAll('bullet_list'))) + bullet_list = list_markup.bullet_list + # Expect the initial commit & the regular commit + assert_equal(2, len(bullet_list.findAll('list_item'))) + # Verify the merge commit is not in the changelog + for child in bullet_list.childGenerator(): + assert_not_in('merge commit', child.text) + class TestWithOtherRepository(TestWithRepository): """ From cc1dacad522c3b3608f184e22b439b0da9a68a7a Mon Sep 17 00:00:00 2001 From: Stan Brunau Date: Mon, 10 Feb 2025 16:10:19 +0100 Subject: [PATCH 3/3] Add documentation for the path, first_parent and no_merges options --- docs/using.rst | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index d0b94f0..42c8a72 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -78,8 +78,23 @@ will accept. See `the man page`_ for details. Sphinx will output a warning if you specify both. -Filter Revisons to Matching Only Certain Files Based on Filenames -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Filter Revisions to Match Only a Single Directory or File +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you only want to see the changelog regarding to a certain directory or file +you can use the ``:path:`` argument with ``git_changelog``. +``:path:`` expects a path to the directory or file you want to filter on, either +as an absolute path or as a relative path from the working directory. So:: + + .. git_changelog:: + :path: doc/ + +will show all commits that modified files in the ``doc/`` directory. + + +Filter Revisions to Matching Only Certain Files Based on Filenames +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you only want to see the changelog regarding certain files (eg. for devops reasons you need to have both SaSS and CSS in your repository or you only want @@ -158,6 +173,32 @@ for example: :detailed-message-strong: False +Hiding merge commits +~~~~~~~~~~~~~~~~~~~~ + +If you want to hide merge commits from the changelog, +then you can add the ``:no_merges:`` argument. So:: + + .. git_changelog:: + :no_merges: + +will hide all commits that have more than one parent. + + +Showing only the first parent commits +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you want the changelog to only display the first parents of commits +(e.g. your main branch has been merged into a lot and you don't want to +see the individual commits that came from other branches), then you can +add the ``:first_parent:`` argument. So:: + + .. git_changelog:: + :first_parent: + +will only show the first parent of merge commits. + + git_commit_detail Directive ---------------------------