diff --git a/gclient_scm.py b/gclient_scm.py index 8810e2c49..f58c07a8c 100644 --- a/gclient_scm.py +++ b/gclient_scm.py @@ -536,6 +536,25 @@ class GitWrapper(SCMWrapper): if options.reset_patch_ref: self._Capture(['reset', '--soft', base_rev]) + def check_diff(self, previous_commit, files=None): + # type: (str, Optional[List[str]]) -> bool + """Check if a diff exists between the current commit and `previous_commit`. + + Returns True if there were diffs or if an error was encountered. + """ + cmd = ['diff', previous_commit, '--quiet'] + if files: + cmd += ['--'] + files + try: + self._Capture(cmd) + return False + except subprocess2.CalledProcessError as e: + # git diff --quiet exits with 1 if there were diffs. + if e.returncode != 1: + self.Print('git returned non-zero exit status %s:\n%s' % + (e.returncode, e.stderr.decode('utf-8'))) + return True + def update(self, options, args, file_list): """Runs git to update or transparently checkout the working copy. diff --git a/tests/gclient_scm_test.py b/tests/gclient_scm_test.py index 8185b41ef..6774f96dc 100755 --- a/tests/gclient_scm_test.py +++ b/tests/gclient_scm_test.py @@ -1482,6 +1482,54 @@ class GerritChangesTest(fake_repos.FakeReposTestBase): self.assertEqual(self.githash('repo_1', 5), self.gitrevparse(self.root_dir)) +class DepsChangesFakeRepo(fake_repos.FakeReposBase): + def populateGit(self): + self._commit_git('repo_1', {'DEPS': 'versionA', 'doesnotmatter': 'B'}) + self._commit_git('repo_1', {'DEPS': 'versionA', 'doesnotmatter': 'C'}) + + self._commit_git('repo_1', {'DEPS': 'versionB'}) + self._commit_git('repo_1', {'DEPS': 'versionA', 'doesnotmatter': 'C'}) + self._create_ref('repo_1', 'refs/heads/main', 4) + + +class CheckDiffTest(fake_repos.FakeReposTestBase): + FAKE_REPOS_CLASS = DepsChangesFakeRepo + + def setUp(self): + super(CheckDiffTest, self).setUp() + self.enabled = self.FAKE_REPOS.set_up_git() + self.options = BaseGitWrapperTestCase.OptionsObject() + self.url = self.git_base + 'repo_1' + self.mirror = None + mock.patch('sys.stdout', StringIO()).start() + self.addCleanup(mock.patch.stopall) + + def setUpMirror(self): + self.mirror = tempfile.mkdtemp() + git_cache.Mirror.SetCachePath(self.mirror) + self.addCleanup(gclient_utils.rmtree, self.mirror) + self.addCleanup(git_cache.Mirror.SetCachePath, None) + + def testCheckDiff(self): + """Correctly check for diffs.""" + scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.') + file_list = [] + + # Make sure we don't specify a revision. + self.options.revision = None + scm.update(self.options, None, file_list) + self.assertEqual(self.githash('repo_1', 4), self.gitrevparse(self.root_dir)) + + self.assertFalse(scm.check_diff(self.githash('repo_1', 1), files=['DEPS'])) + self.assertTrue(scm.check_diff(self.githash('repo_1', 1))) + self.assertTrue(scm.check_diff(self.githash('repo_1', 3), files=['DEPS'])) + + self.assertFalse( + scm.check_diff(self.githash('repo_1', 2), + files=['DEPS', 'doesnotmatter'])) + self.assertFalse(scm.check_diff(self.githash('repo_1', 2))) + + if 'unittest.util' in __import__('sys').modules: # Show full diff in self.assertEqual. __import__('sys').modules['unittest.util']._MAX_LENGTH = 999999999