def test_commit_in_master_branch(): gr = GitRepository('test-repos/git-2/') assert gr.get_head().hash == '29e929fbc5dc6a2e9c620069b24e2a143af4285f' gr.checkout('8986af2a679759e5a15794f6d56e6d46c3f302f1') git_to_change_head = GitRepository('test-repos/git-2/') commit = git_to_change_head.get_commit( '8169f76a3d7add54b4fc7bca7160d1f1eede6eda') assert commit.in_main_branch is False commit = git_to_change_head.get_commit( '168b3aab057ed61a769acf336a4ef5e64f76c9fd') assert commit.in_main_branch is True gr.reset() assert gr.get_head().hash == '29e929fbc5dc6a2e9c620069b24e2a143af4285f'
def test_get_head(): gr = GitRepository('test-repos/test1/') assert gr is not None cs = gr.get_head() assert cs is not None assert cs.hash == 'da39b1326dbc2edfe518b90672734a08f3c13458' assert cs.author_date.timestamp() == 1522164679
def test_checkout_consecutive_commits(): gr = GitRepository('test-repos/git-1/') gr.checkout('a7053a4dcd627f5f4f213dc9aa002eb1caf926f8') gr.checkout('f0dd1308bd904a9b108a6a40865166ee962af3d4') gr.checkout('9e71dd5726d775fb4a5f08506a539216e878adbb') files3 = gr.files() assert len(files3) == 3 gr.reset()
def test_get_commit_from_tag(): gr = GitRepository('test-repos/test1/') commit = gr.get_commit_from_tag('v1.4') assert commit.hash == '09f6182cef737db02a085e1d018963c7a29bde5a' with pytest.raises(IndexError): gr.get_commit_from_tag('v1.5')
def test_get_commits_last_modified_lines_rename_simple(): gr = GitRepository('test-repos/test5/') buggy_commits = gr.get_commits_last_modified_lines( gr.get_commit('45ba0a61ccc448625bce0fea0301cf0c1ab32696')) assert len(buggy_commits) == 1 assert 'e358878a00e78aca8366264d61a7319d00dd8186' in buggy_commits
def test_get_commits_last_modified_lines_simple(): gr = GitRepository('test-repos/test5/') buggy_commits = gr.get_commits_last_modified_lines( gr.get_commit('e6d3b38a9ef683e8184eac10a0471075c2808bbd')) assert len(buggy_commits) == 1 assert '540c7f31c18664a38190fafb6721b5174ff4a166' in buggy_commits
def test_number_of_modifications(): gr = GitRepository('test-repos/git-1/') commit = gr.get_commit('866e997a9e44cb4ddd9e00efe49361420aff2559') assert commit.modifications[0].added == 62 assert commit.modifications[0].removed == 0 commit = gr.get_commit('d11dd6734ff4e60cac3a7b58d9267f138c9e05c7') assert commit.modifications[0].added == 1 assert commit.modifications[0].removed == 1
def test_detail_rename(): gr = GitRepository('test-repos/git-1/') commit = gr.get_commit('f0dd1308bd904a9b108a6a40865166ee962af3d4') assert commit.author.name == "Maurício Aniche" assert commit.author.email == "*****@*****.**" assert commit.modifications[0].new_path == "Matricula.javax" assert commit.modifications[0].old_path == "Matricula.java"
def test_get_commits_modified_file(): gr = GitRepository('test-repos/test1/') commits = gr.get_commits_modified_file('file2.java') assert len(commits) == 3 assert '09f6182cef737db02a085e1d018963c7a29bde5a' in commits assert '6411e3096dd2070438a17b225f44475136e54e3a' in commits assert 'a88c84ddf42066611e76e6cb690144e5357d132c' in commits
def test_get_commits_last_modified_lines_multiple(): gr = GitRepository('test-repos/test5/') buggy_commits = gr.get_commits_last_modified_lines(gr.get_commit('9942ee9dcdd1103e5808d544a84e6bc8cade0e54')) assert len(buggy_commits) == 3 assert '2eb905e5e7be414fd184d6b4f1571b142621f4de' in buggy_commits assert '20a40688521c1802569e60f9d55342c3bfdd772c' in buggy_commits assert '22505e97dca6f843549b3a484b3609be4e3acf17' in buggy_commits
def test_get_tagged_commits(): gr = GitRepository('test-repos/git-8/') tagged_commits = gr.get_tagged_commits() assert len(tagged_commits) == 3 assert '6bb9e2c6a8080e6b5b34e6e316c894b2ddbf7fcd' == tagged_commits[0] assert '4638730126d40716e230c2040751a13153fb1556' == tagged_commits[1] assert '627e1ad917a188a861c9fedf6e5858b79edbe439' == tagged_commits[2]
def test_filepahs(): gr = GitRepository('test-repos/test7') c = gr.get_commit('f0f8aea2db50ed9f16332d86af3629ff7780583e') mod0 = c.modifications[0] assert mod0.filename == 'a.java' assert mod0.new_path == str(Path('dir2/a.java')) assert mod0.old_path == str(Path('dir2/a.java'))
def traverse_commits(self) -> Generator[Commit, None, None]: """ Analyze all the specified commits (all of them by default), returning a generator of commits. """ for path_repo in self._conf.get('path_to_repos'): # if it is a remote repo, clone it first in a temporary folder! if self._is_remote(path_repo): if self._conf.get('clone_repo_to'): clone_folder = str(Path(self._conf.get('clone_repo_to'))) if not os.path.isdir(clone_folder): raise Exception( "Not a directory: {0}".format(clone_folder)) path_repo = self._clone_remote_repos( clone_folder, path_repo) else: tmp_folder = tempfile.TemporaryDirectory() path_repo = self._clone_remote_repos( tmp_folder.name, path_repo) git_repo = GitRepository(path_repo, self._conf) self._conf.set_value("git_repo", git_repo) self._conf.sanity_check_filters() logger.info('Analyzing git repository in %s', git_repo.path) # Get the commits that modified the filepath. In this case, we can not use # git rev-list since it doesn't have the option --follow, necessary to follow # the renames. Hence, we manually call git log instead if self._conf.get('filepath') is not None: self._conf.set_value( 'filepath_commits', git_repo.get_commits_modified_file( self._conf.get('filepath'))) # Gets only the commits that are tagged if self._conf.get('only_releases'): self._conf.set_value('tagged_commits', git_repo.get_tagged_commits()) # Build the arguments to pass to git rev-list. rev, kwargs = self._conf.build_args() # Iterate over all the commits returned by git rev-list for commit in git_repo.get_list_commits(rev, **kwargs): logger.info('Commit #%s in %s from %s', commit.hash, commit.committer_date, commit.author.name) if self._conf.is_commit_filtered(commit): logger.info('Commit #%s filtered', commit.hash) continue yield commit # cleaning, this is necessary since GitPython issues on memory leaks self._conf.set_value("git_repo", None) git_repo.clear()
def test_modification_status(): gr = GitRepository('test-repos/git-1/') commit = gr.get_commit('866e997a9e44cb4ddd9e00efe49361420aff2559') assert ModificationType.ADD == commit.modifications[0].change_type commit = gr.get_commit('57dbd017d1a744b949e7ca0b1c1a3b3dd4c1cbc1') assert ModificationType.MODIFY == commit.modifications[0].change_type commit = gr.get_commit('ffccf1e7497eb8136fd66ed5e42bef29677c4b71') assert ModificationType.DELETE == commit.modifications[0].change_type
def test_tags(): gr = GitRepository('test-repos/git-8/') commit = gr.get_commit_from_tag('tag1') assert commit.hash == '6bb9e2c6a8080e6b5b34e6e316c894b2ddbf7fcd' commit = gr.get_commit_from_tag('tag2') assert commit.hash == '4638730126d40716e230c2040751a13153fb1556' with pytest.raises(IndexError): gr.get_commit_from_tag('tag4')
def test_merge_commits(): gr = GitRepository('test-repos/git-2/') commit = gr.get_commit("168b3aab057ed61a769acf336a4ef5e64f76c9fd") assert commit.merge is False commit = gr.get_commit("8169f76a3d7add54b4fc7bca7160d1f1eede6eda") assert commit.merge is False commit = gr.get_commit("29e929fbc5dc6a2e9c620069b24e2a143af4285f") assert commit.merge is True
def test_parent_commits(): gr = GitRepository('test-repos/git-5/') merge_commit = gr.get_commit('5d9d79607d7e82b6f236aa29be4ba89a28fb4f15') assert len(merge_commit.parents) == 2 assert 'fa8217c324e7fb46c80e1ddf907f4e141449637e' in merge_commit.parents assert 'ff663cf1931a67d5e47b75fc77dcea432c728052' in merge_commit.parents normal_commit = gr.get_commit('ff663cf1931a67d5e47b75fc77dcea432c728052') assert len(normal_commit.parents) == 1 assert '4a17f31c0d1285477a3a467d0bc3cb38e775097d' in normal_commit.parents
def test_eq_commit(): gr = GitRepository('test-repos/git-11') c1 = gr.get_commit('1734d6da01378bad3aade12b52bb4aa8954835dc') c2 = gr.get_commit('2c1327f957ba3b2a5e86eaed097b0a425236719e') c3 = gr.get_commit('1734d6da01378bad3aade12b52bb4aa8954835dc') m1 = gr.get_commit('1734d6da01378bad3aade12b52bb4aa8954835dc' '').modifications[0] assert c1 == c3 assert c1 == c1 assert c1 != m1 assert c1 != c2
def traverse_commits(self) -> Generator[Commit, None, None]: """ Analyze all the specified commits (all of them by default), returning a generator of commits. """ for path_repo in self._conf.get('path_to_repos'): if self._is_remote(path_repo): path_repo = self._clone_remote_repos(self._clone_folder(), path_repo) git_repo = GitRepository(path_repo, self._conf) # saving the GitRepository object for further use self._conf.set_value("git_repo", git_repo) # when multiple repos are given in input, this variable will serve as a reminder # of which one we are currently analyzing self._conf.set_value('path_to_repo', path_repo) # checking that the filters are set correctly self._conf.sanity_check_filters() logger.info('Analyzing git repository in %s', git_repo.path) # Get the commits that modified the filepath. In this case, we can not use # git rev-list since it doesn't have the option --follow, necessary to follow # the renames. Hence, we manually call git log instead if self._conf.get('filepath') is not None: self._conf.set_value( 'filepath_commits', git_repo.get_commits_modified_file( self._conf.get('filepath'))) # Gets only the commits that are tagged if self._conf.get('only_releases'): self._conf.set_value('tagged_commits', git_repo.get_tagged_commits()) # Build the arguments to pass to git rev-list. rev, kwargs = self._conf.build_args() # Iterate over all the commits returned by git rev-list for commit in git_repo.get_list_commits(rev, **kwargs): logger.info('Commit #%s in %s from %s', commit.hash, commit.committer_date, commit.author.name) if self._conf.is_commit_filtered(commit): logger.info('Commit #%s filtered', commit.hash) continue yield commit # cleaning, this is necessary since GitPython issues on memory leaks self._conf.set_value("git_repo", None) git_repo.clear()
def test_commit_in_master_branch(repo: GitRepository): assert repo.get_head().hash == '29e929fbc5dc6a2e9c620069b24e2a143af4285f' repo.checkout('8986af2a679759e5a15794f6d56e6d46c3f302f1') git_to_change_head = GitRepository('test-repos/branches_merged') commit = git_to_change_head.get_commit('8169f76a3d7add54b4fc7bca7160d1f1eede6eda') assert commit.in_main_branch is False repo.reset() assert repo.get_head().hash == '29e929fbc5dc6a2e9c620069b24e2a143af4285f'
def test_get_commits_last_modified_lines_for_single_file(): gr = GitRepository('test-repos/test5/') commit = gr.get_commit('0f726924f96621e4965039123098ba83e39ffba6') buggy_commits = None for mod in commit.modifications: if mod.filename == 'A.java': buggy_commits = gr.get_commits_last_modified_lines(commit, mod) assert len(buggy_commits) == 1 assert 'e2ed043eb96c05ebde653a44ae733ded9ef90750' in buggy_commits
def test_get_commits_last_modified_lines_rename_simple_more_commits(): gr = GitRepository('test-repos/test5/') buggy_commits = gr.get_commits_last_modified_lines( gr.get_commit('04fadd3e68c58281db6cf15119f9769880ac1cbc')) assert len(buggy_commits) == 2 assert '9b373199c270f9b24c37fee70f9e2b3ee9b816e3' in buggy_commits[ 'A.java'] assert '9b373199c270f9b24c37fee70f9e2b3ee9b816e3' in buggy_commits[ 'B.java']
def test_branches_from_commit(): gr = GitRepository('test-repos/git-1/') commit = gr.get_commit('a997e9d400f742003dea601bb05a9315d14d1124') assert len(commit.branches) == 1 assert 'b2' in commit.branches commit = gr.get_commit('866e997a9e44cb4ddd9e00efe49361420aff2559') assert len(commit.branches) == 2 assert 'master' in commit.branches assert 'b2' in commit.branches
def test_get_commits_last_modified_lines_hyper_blame_unblamable(tmp_path): p = tmp_path / "ignore.txt" p.write_text("540c7f31c18664a38190fafb6721b5174ff4a166") gr = GitRepository('test-repos/test5/') buggy_commits = gr.get_commits_last_modified_lines( gr.get_commit('e6d3b38a9ef683e8184eac10a0471075c2808bbd'), hashes_to_ignore_path=str(p)) assert len(buggy_commits) == 0
def test_get_commits_last_modified_lines_hyper_blame_with_renaming(): gr = GitRepository('test-repos/test5/') buggy_commits = gr.get_commits_last_modified_lines( gr.get_commit('be0772cbaa2eba32bf97aae885199d1a357ddc93')) assert len(buggy_commits) == 2 assert '9568d20856728304ab0b4d2d02fb9e81d0e5156d' in buggy_commits[ 'A.java'] assert '9568d20856728304ab0b4d2d02fb9e81d0e5156d' in buggy_commits[ 'H.java']
def test_get_commit(): gr = GitRepository('test-repos/test1/') c = gr.get_commit('09f6182cef737db02a085e1d018963c7a29bde5a') to_zone = timezone(timedelta(hours=1)) assert '09f6182cef737db02a085e1d018963c7a29bde5a' == c.hash assert 'ishepard' == c.author.name assert 'ishepard' == c.committer.name assert datetime(2018, 3, 22, 10, 42, 3, tzinfo=to_zone).timestamp() == c.author_date.timestamp() assert 1 == len(c.modifications) assert 'Ooops file2' == c.msg assert c.in_main_branch is True
def test_get_first_commit(): gr = GitRepository('test-repos/test1/') c = gr.get_commit('a88c84ddf42066611e76e6cb690144e5357d132c') to_zone = timezone(timedelta(hours=1)) assert 'a88c84ddf42066611e76e6cb690144e5357d132c' == c.hash assert 'ishepard' == c.author.name assert 'ishepard' == c.committer.name assert datetime(2018,3,22,10,41,11,tzinfo=to_zone).timestamp() == c.author_date.timestamp() assert 2 == len(c.modifications) assert 'First commit adding 2 files' == c.msg assert c.in_main_branch is True
def test_changed_methods(): gr = GitRepository("test-repos/diff") # add a new method mod = gr.get_commit( 'ea95227e0fd128aa69c7ab6a8ac485f72251b3ed').modifications[0] assert len(mod.changed_methods) == 1 assert mod.changed_methods[ 0].name == 'GitRepository::singleProjectThirdMethod' # add 2 new methods mod = gr.get_commit( 'd8eb8e80b671246a43c98d97b05f6d1c5ada14fb').modifications[0] assert len(mod.changed_methods) == 2 # remove one method mod = gr.get_commit( '0c8f9fdec926785198b399a2c49adb5884aa952c').modifications[0] assert len(mod.changed_methods) == 1 # add and remove one one method at different locations mod = gr.get_commit( 'd8bb142c5616041b71cbfaa11eeb768d9a1a296e').modifications[0] assert len(mod.changed_methods) == 2 # add and remove one one method at the same location # this is equivalent to replacing a method - although we expect 2 methods mod = gr.get_commit( '9e9473d5ca310b7663e9df93c402302b6b7f24aa').modifications[0] assert len(mod.changed_methods) == 2 # update a method mod = gr.get_commit( 'b267a14e0503fdac36d280422f16360d1f661f12').modifications[0] assert len(mod.changed_methods) == 1 # update and add a new method mod = gr.get_commit( '2489099dfd90edb99ddc2c82b62524b66c07c687').modifications[0] assert len(mod.changed_methods) == 2 # update and delete methods mod = gr.get_commit( '5aebeb30e0238543a93e5bed806639481460cd9a').modifications[0] assert len(mod.changed_methods) == 2 # delete 3 methods (test cleanup - revert the test file to its # initial set of methods) mod = gr.get_commit( '9f6ddc2aac740a257af59a76860590cb8a84c77b').modifications[0] assert len(mod.changed_methods) == 3
def test_checkout_with_commit_not_fully_merged_to_master(): gr = GitRepository('test-repos/git-9/') gr.checkout('developing') files1 = gr.files() assert len(files1) == 2 gr.reset() assert 4, "temp branch should be cleared." == len(gr.repo.branches) files2 = gr.files() assert len(files2) == 1 gr.checkout('developing') files1 = gr.files() assert len(files1) == 2 gr.reset()
def test_files(): gr = GitRepository('test-repos/test2') all = gr.files() assert len(all) == 8 assert str(Path('test-repos/test2/tmp1.py')) in all assert str(Path('test-repos/test2/tmp2.py')) in all assert str(Path('test-repos/test2/fold1/tmp3.py')) in all assert str(Path('test-repos/test2/fold1/tmp4.py')) in all assert str(Path('test-repos/test2/fold2/tmp5.py')) in all assert str(Path('test-repos/test2/fold2/tmp6.py')) in all assert str(Path('test-repos/test2/fold2/fold3/tmp7.py')) in all assert str(Path('test-repos/test2/fold2/fold3/tmp8.py')) in all