blob: 3f1484f8cf8d78aea7745e938c63955c6270259c [file] [log] [blame]
Edward Lemura877ee62019-09-03 20:23:17 +00001#!/usr/bin/env vpython3
steveblock@chromium.org93567042012-02-15 01:02:26 +00002# Copyright (c) 2012 The Chromium Authors. All rights reserved.
maruel@chromium.orgba551772010-02-03 18:21:42 +00003# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
msb@chromium.orge28e4982009-09-25 20:51:45 +00005
6"""Unit tests for gclient_scm.py."""
7
maruel@chromium.org428342a2011-11-10 15:46:33 +00008# pylint: disable=E1103
maruel@chromium.orgbf38a7e2010-12-14 18:15:54 +00009
Edward Lesmese79107e2019-10-25 22:47:33 +000010from __future__ import unicode_literals
11
Gavin Mak65c49b12023-08-24 18:06:42 +000012from io import StringIO
John Budorick0f7b2002018-01-19 15:46:17 -080013import json
maruel@chromium.org428342a2011-11-10 15:46:33 +000014import logging
15import os
szager@chromium.orgfe0d1902014-04-08 20:50:44 +000016import re
Gavin Mak65c49b12023-08-24 18:06:42 +000017from subprocess import Popen, PIPE, STDOUT
maruel@chromium.org428342a2011-11-10 15:46:33 +000018import sys
msb@chromium.orge28e4982009-09-25 20:51:45 +000019import tempfile
maruel@chromium.org389d6de2010-09-09 14:14:37 +000020import unittest
Gavin Mak65c49b12023-08-24 18:06:42 +000021from unittest import mock
msb@chromium.orge28e4982009-09-25 20:51:45 +000022
Edward Lemur979fa782019-08-13 22:44:05 +000023
maruel@chromium.org428342a2011-11-10 15:46:33 +000024sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
maruel@chromium.orgba551772010-02-03 18:21:42 +000025
msb@chromium.orge28e4982009-09-25 20:51:45 +000026import gclient_scm
Edward Lesmese79107e2019-10-25 22:47:33 +000027import gclient_utils
szager@chromium.orgb0a13a22014-06-18 00:52:25 +000028import git_cache
maruel@chromium.orgfae707b2011-09-15 18:57:58 +000029import subprocess2
Gavin Mak65c49b12023-08-24 18:06:42 +000030from testing_support import fake_repos
31from testing_support import test_case_utils
maruel@chromium.org96913eb2010-06-01 16:22:47 +000032
Edward Lesmese79107e2019-10-25 22:47:33 +000033
34GIT = 'git' if sys.platform != 'win32' else 'git.bat'
35
szager@chromium.orgb0a13a22014-06-18 00:52:25 +000036# Disable global git cache
37git_cache.Mirror.SetCachePath(None)
38
maruel@chromium.org795a8c12010-10-05 19:54:29 +000039# Shortcut since this function is used often
40join = gclient_scm.os.path.join
41
Raul Tambrea79f0e52019-09-21 07:27:39 +000042TIMESTAMP_RE = re.compile(r'\[[0-9]{1,2}:[0-9]{2}:[0-9]{2}\] (.*)', re.DOTALL)
szager@chromium.orgfe0d1902014-04-08 20:50:44 +000043def strip_timestamps(value):
44 lines = value.splitlines(True)
Edward Lemur979fa782019-08-13 22:44:05 +000045 for i in range(len(lines)):
szager@chromium.orgfe0d1902014-04-08 20:50:44 +000046 m = TIMESTAMP_RE.match(lines[i])
47 if m:
48 lines[i] = m.group(1)
49 return ''.join(lines)
maruel@chromium.org96913eb2010-06-01 16:22:47 +000050
maruel@chromium.orgd579fcf2011-12-13 20:36:03 +000051
Edward Lemur979fa782019-08-13 22:44:05 +000052class BasicTests(unittest.TestCase):
53 @mock.patch('gclient_scm.scm.GIT.Capture')
54 def testGetFirstRemoteUrl(self, mockCapture):
hinoka@chromium.orgfa2b9b42014-08-22 18:08:53 +000055 REMOTE_STRINGS = [('remote.origin.url E:\\foo\\bar', 'E:\\foo\\bar'),
56 ('remote.origin.url /b/foo/bar', '/b/foo/bar'),
57 ('remote.origin.url https://foo/bar', 'https://foo/bar'),
58 ('remote.origin.url E:\\Fo Bar\\bax', 'E:\\Fo Bar\\bax'),
59 ('remote.origin.url git://what/"do', 'git://what/"do')]
60 FAKE_PATH = '/fake/path'
Edward Lemur979fa782019-08-13 22:44:05 +000061 mockCapture.side_effect = [question for question, _ in REMOTE_STRINGS]
hinoka@chromium.orgfa2b9b42014-08-22 18:08:53 +000062
63 for _, answer in REMOTE_STRINGS:
Edward Lemur979fa782019-08-13 22:44:05 +000064 self.assertEqual(
65 gclient_scm.SCMWrapper._get_first_remote_url(FAKE_PATH), answer)
hinoka@chromium.orgfa2b9b42014-08-22 18:08:53 +000066
Edward Lemur979fa782019-08-13 22:44:05 +000067 expected_calls = [
68 mock.call(['config', '--local', '--get-regexp', r'remote.*.url'],
69 cwd=FAKE_PATH)
70 for _ in REMOTE_STRINGS
71 ]
72 self.assertEqual(mockCapture.mock_calls, expected_calls)
hinoka@chromium.orgfa2b9b42014-08-22 18:08:53 +000073
74
Edward Lemur9cafbf42019-08-15 22:03:35 +000075class BaseGitWrapperTestCase(unittest.TestCase, test_case_utils.TestCaseUtils):
maruel@chromium.org8ef5f542009-11-12 02:05:02 +000076 """This class doesn't use pymox."""
msb@chromium.orge28e4982009-09-25 20:51:45 +000077 class OptionsObject(object):
maruel@chromium.orgbf38a7e2010-12-14 18:15:54 +000078 def __init__(self, verbose=False, revision=None):
dnj@chromium.org5b23e872015-02-20 21:25:57 +000079 self.auto_rebase = False
msb@chromium.orge28e4982009-09-25 20:51:45 +000080 self.verbose = verbose
81 self.revision = revision
msb@chromium.orge28e4982009-09-25 20:51:45 +000082 self.deps_os = None
83 self.force = False
davemoore@chromium.org8bf27312010-02-19 17:29:44 +000084 self.reset = False
msb@chromium.orge28e4982009-09-25 20:51:45 +000085 self.nohooks = False
primiano@chromium.org5439ea52014-08-06 17:18:18 +000086 self.no_history = False
iannucci@chromium.orgd4fffee2013-06-28 00:35:26 +000087 self.upstream = False
iannucci@chromium.org53456aa2013-07-03 19:38:34 +000088 self.cache_dir = None
bauerb@chromium.org4dd09372011-07-22 14:41:51 +000089 self.merge = False
bratell@opera.com18fa4542013-05-21 13:30:46 +000090 self.jobs = 1
iannucci@chromium.org30a07982016-04-07 21:35:19 +000091 self.break_repo_locks = False
steveblock@chromium.org98e69452012-02-16 16:36:43 +000092 self.delete_unversioned_trees = False
Edward Lesmesc621b212018-03-21 20:26:56 -040093 self.patch_ref = None
94 self.patch_repo = None
95 self.rebase_patch_ref = True
Edward Lemurca7d8812018-07-24 17:42:45 +000096 self.reset_patch_ref = True
msb@chromium.orge28e4982009-09-25 20:51:45 +000097
98 sample_git_import = """blob
99mark :1
100data 6
101Hello
102
103blob
104mark :2
105data 4
106Bye
107
Josip Sokcevic7e133ff2021-07-13 17:44:53 +0000108reset refs/heads/main
109commit refs/heads/main
msb@chromium.orge28e4982009-09-25 20:51:45 +0000110mark :3
111author Bob <bob@example.com> 1253744361 -0700
112committer Bob <bob@example.com> 1253744361 -0700
113data 8
114A and B
115M 100644 :1 a
116M 100644 :2 b
117
118blob
119mark :4
120data 10
121Hello
122You
123
124blob
125mark :5
126data 8
127Bye
128You
129
130commit refs/heads/origin
131mark :6
132author Alice <alice@example.com> 1253744424 -0700
133committer Alice <alice@example.com> 1253744424 -0700
134data 13
135Personalized
136from :3
137M 100644 :4 a
138M 100644 :5 b
139
bauerb@chromium.org30c46d62014-01-23 12:11:56 +0000140blob
141mark :7
142data 5
143Mooh
144
145commit refs/heads/feature
146mark :8
147author Bob <bob@example.com> 1390311986 -0000
148committer Bob <bob@example.com> 1390311986 -0000
149data 6
150Add C
151from :3
152M 100644 :7 c
153
Josip Sokcevic7e133ff2021-07-13 17:44:53 +0000154reset refs/heads/main
msb@chromium.orge28e4982009-09-25 20:51:45 +0000155from :3
156"""
msb@chromium.orge28e4982009-09-25 20:51:45 +0000157 def Options(self, *args, **kwargs):
maruel@chromium.org8071c282010-09-20 19:44:19 +0000158 return self.OptionsObject(*args, **kwargs)
msb@chromium.orge28e4982009-09-25 20:51:45 +0000159
szager@chromium.orgfe0d1902014-04-08 20:50:44 +0000160 def checkstdout(self, expected):
Aravind Vasudevanc5f0cbb2022-01-24 23:56:57 +0000161 # pylint: disable=no-member
szager@chromium.orgfe0d1902014-04-08 20:50:44 +0000162 value = sys.stdout.getvalue()
163 sys.stdout.close()
Erik Chene16ffff2019-10-14 20:35:53 +0000164 # Check that the expected output appears.
Erik Chene16ffff2019-10-14 20:35:53 +0000165 self.assertIn(expected, strip_timestamps(value))
szager@chromium.orgfe0d1902014-04-08 20:50:44 +0000166
maruel@chromium.orgbf38a7e2010-12-14 18:15:54 +0000167 @staticmethod
168 def CreateGitRepo(git_import, path):
maruel@chromium.orgd5800f12009-11-12 20:03:43 +0000169 """Do it for real."""
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000170 try:
Edward Lesmese79107e2019-10-25 22:47:33 +0000171 Popen([GIT, 'init', '-q'], stdout=PIPE, stderr=STDOUT,
maruel@chromium.org8ef5f542009-11-12 02:05:02 +0000172 cwd=path).communicate()
173 except OSError:
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000174 # git is not available, skip this test.
175 return False
Edward Lesmese79107e2019-10-25 22:47:33 +0000176 Popen([GIT, 'fast-import', '--quiet'], stdin=PIPE, stdout=PIPE,
Edward Lemur979fa782019-08-13 22:44:05 +0000177 stderr=STDOUT, cwd=path).communicate(input=git_import.encode())
Edward Lesmese79107e2019-10-25 22:47:33 +0000178 Popen([GIT, 'checkout', '-q'], stdout=PIPE, stderr=STDOUT,
maruel@chromium.org389d6de2010-09-09 14:14:37 +0000179 cwd=path).communicate()
Edward Lesmese79107e2019-10-25 22:47:33 +0000180 Popen([GIT, 'remote', 'add', '-f', 'origin', '.'], stdout=PIPE,
maruel@chromium.org389d6de2010-09-09 14:14:37 +0000181 stderr=STDOUT, cwd=path).communicate()
Josip Sokcevic7e133ff2021-07-13 17:44:53 +0000182 Popen([GIT, 'checkout', '-b', 'new', 'origin/main', '-q'], stdout=PIPE,
maruel@chromium.org389d6de2010-09-09 14:14:37 +0000183 stderr=STDOUT, cwd=path).communicate()
Josip Sokcevic7e133ff2021-07-13 17:44:53 +0000184 Popen([GIT, 'push', 'origin', 'origin/origin:origin/main', '-q'],
maruel@chromium.org389d6de2010-09-09 14:14:37 +0000185 stdout=PIPE, stderr=STDOUT, cwd=path).communicate()
Edward Lesmese79107e2019-10-25 22:47:33 +0000186 Popen([GIT, 'config', '--unset', 'remote.origin.fetch'], stdout=PIPE,
maruel@chromium.org389d6de2010-09-09 14:14:37 +0000187 stderr=STDOUT, cwd=path).communicate()
Edward Lesmese79107e2019-10-25 22:47:33 +0000188 Popen([GIT, 'config', 'user.email', 'someuser@chromium.org'], stdout=PIPE,
iannucci@chromium.org1e7187a2013-02-17 20:54:05 +0000189 stderr=STDOUT, cwd=path).communicate()
Edward Lesmese79107e2019-10-25 22:47:33 +0000190 Popen([GIT, 'config', 'user.name', 'Some User'], stdout=PIPE,
iannucci@chromium.org1e7187a2013-02-17 20:54:05 +0000191 stderr=STDOUT, cwd=path).communicate()
Josip Sokcevic7e133ff2021-07-13 17:44:53 +0000192 # Set HEAD back to main
193 Popen([GIT, 'checkout', 'main', '-q'],
Josip Sokcevic091f5ac2021-01-14 23:14:21 +0000194 stdout=PIPE,
195 stderr=STDOUT,
196 cwd=path).communicate()
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000197 return True
msb@chromium.orge28e4982009-09-25 20:51:45 +0000198
bauerb@chromium.org30c46d62014-01-23 12:11:56 +0000199 def _GetAskForDataCallback(self, expected_prompt, return_value):
200 def AskForData(prompt, options):
Edward Lemur979fa782019-08-13 22:44:05 +0000201 self.assertEqual(prompt, expected_prompt)
bauerb@chromium.org30c46d62014-01-23 12:11:56 +0000202 return return_value
203 return AskForData
204
msb@chromium.orge28e4982009-09-25 20:51:45 +0000205 def setUp(self):
maruel@chromium.org389d6de2010-09-09 14:14:37 +0000206 unittest.TestCase.setUp(self)
Edward Lemur9cafbf42019-08-15 22:03:35 +0000207 test_case_utils.TestCaseUtils.setUp(self)
msb@chromium.orge28e4982009-09-25 20:51:45 +0000208 self.url = 'git://foo'
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000209 # The .git suffix allows gclient_scm to recognize the dir as a git repo
210 # when cloning it locally
211 self.root_dir = tempfile.mkdtemp('.git')
msb@chromium.orge28e4982009-09-25 20:51:45 +0000212 self.relpath = '.'
maruel@chromium.org795a8c12010-10-05 19:54:29 +0000213 self.base_path = join(self.root_dir, self.relpath)
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000214 self.enabled = self.CreateGitRepo(self.sample_git_import, self.base_path)
Edward Lemur979fa782019-08-13 22:44:05 +0000215 mock.patch('sys.stdout', StringIO()).start()
216 self.addCleanup(mock.patch.stopall)
Edward Lesmese79107e2019-10-25 22:47:33 +0000217 self.addCleanup(gclient_utils.rmtree, self.root_dir)
maruel@chromium.org1a60dca2013-11-26 14:06:26 +0000218
msb@chromium.orge28e4982009-09-25 20:51:45 +0000219
cmp@chromium.orgeb2756d2011-09-20 20:17:51 +0000220class ManagedGitWrapperTestCase(BaseGitWrapperTestCase):
msb@chromium.orge28e4982009-09-25 20:51:45 +0000221
Joanna Wang1a977bd2022-06-02 21:51:17 +0000222 @mock.patch('gclient_scm.GitWrapper._IsCog')
223 @mock.patch('gclient_scm.GitWrapper._Run', return_value=True)
224 @mock.patch('gclient_scm.GitWrapper._SetFetchConfig')
225 @mock.patch('gclient_scm.GitWrapper._GetCurrentBranch')
226 def testCloneInCog(self, mockGetCurrentBranch, mockSetFetchConfig, mockRun,
227 _mockIsCog):
228 """Test that we call the correct commands when in a cog workspace."""
229 if not self.enabled:
230 return
231 options = self.Options()
232 scm = gclient_scm.GitWrapper(self.url, self.root_dir, self.relpath)
233 scm._Clone('123123ab', self.url, options)
Joanna Wanga9467d82022-06-09 22:05:43 +0000234 mockRun.assert_called_once_with(
235 ['citc', 'clone-repo', self.url, scm.checkout_path, '123123ab'],
236 options,
237 cwd=scm._root_dir,
238 retry=True,
239 print_stdout=False,
240 filter_fn=scm.filter)
Joanna Wang1a977bd2022-06-02 21:51:17 +0000241 mockSetFetchConfig.assert_called_once()
242 mockGetCurrentBranch.assert_called_once()
243
msb@chromium.orge28e4982009-09-25 20:51:45 +0000244 def testRevertMissing(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000245 if not self.enabled:
246 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000247 options = self.Options()
maruel@chromium.org795a8c12010-10-05 19:54:29 +0000248 file_path = join(self.base_path, 'a')
John Budorick0f7b2002018-01-19 15:46:17 -0800249 scm = gclient_scm.GitWrapper(self.url, self.root_dir,
250 self.relpath)
msb@chromium.orge28e4982009-09-25 20:51:45 +0000251 file_list = []
nasser@codeaurora.orgb2b46312010-04-30 20:58:03 +0000252 scm.update(options, None, file_list)
253 gclient_scm.os.remove(file_path)
254 file_list = []
msb@chromium.orge28e4982009-09-25 20:51:45 +0000255 scm.revert(options, self.args, file_list)
Edward Lemur979fa782019-08-13 22:44:05 +0000256 self.assertEqual(file_list, [file_path])
msb@chromium.orge28e4982009-09-25 20:51:45 +0000257 file_list = []
258 scm.diff(options, self.args, file_list)
Edward Lemur979fa782019-08-13 22:44:05 +0000259 self.assertEqual(file_list, [])
szager@google.com85d3e3a2011-10-07 17:12:00 +0000260 sys.stdout.close()
msb@chromium.orge28e4982009-09-25 20:51:45 +0000261
262 def testRevertNone(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000263 if not self.enabled:
264 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000265 options = self.Options()
John Budorick0f7b2002018-01-19 15:46:17 -0800266 scm = gclient_scm.GitWrapper(self.url, self.root_dir,
267 self.relpath)
msb@chromium.orge28e4982009-09-25 20:51:45 +0000268 file_list = []
nasser@codeaurora.orgb2b46312010-04-30 20:58:03 +0000269 scm.update(options, None, file_list)
270 file_list = []
msb@chromium.orge28e4982009-09-25 20:51:45 +0000271 scm.revert(options, self.args, file_list)
Edward Lemur979fa782019-08-13 22:44:05 +0000272 self.assertEqual(file_list, [])
273 self.assertEqual(scm.revinfo(options, self.args, None),
274 'a7142dc9f0009350b96a11f372b6ea658592aa95')
maruel@chromium.orgc6ca3a12012-06-20 14:46:02 +0000275 sys.stdout.close()
msb@chromium.orge28e4982009-09-25 20:51:45 +0000276
277 def testRevertModified(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000278 if not self.enabled:
279 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000280 options = self.Options()
John Budorick0f7b2002018-01-19 15:46:17 -0800281 scm = gclient_scm.GitWrapper(self.url, self.root_dir,
282 self.relpath)
msb@chromium.orge28e4982009-09-25 20:51:45 +0000283 file_list = []
nasser@codeaurora.orgb2b46312010-04-30 20:58:03 +0000284 scm.update(options, None, file_list)
maruel@chromium.org795a8c12010-10-05 19:54:29 +0000285 file_path = join(self.base_path, 'a')
Edward Lemur979fa782019-08-13 22:44:05 +0000286 with open(file_path, 'a') as f:
287 f.writelines('touched\n')
nasser@codeaurora.orgb2b46312010-04-30 20:58:03 +0000288 file_list = []
msb@chromium.orge28e4982009-09-25 20:51:45 +0000289 scm.revert(options, self.args, file_list)
Edward Lemur979fa782019-08-13 22:44:05 +0000290 self.assertEqual(file_list, [file_path])
msb@chromium.orge28e4982009-09-25 20:51:45 +0000291 file_list = []
292 scm.diff(options, self.args, file_list)
Edward Lemur979fa782019-08-13 22:44:05 +0000293 self.assertEqual(file_list, [])
294 self.assertEqual(scm.revinfo(options, self.args, None),
nasser@codeaurora.orgb2b46312010-04-30 20:58:03 +0000295 'a7142dc9f0009350b96a11f372b6ea658592aa95')
szager@google.com85d3e3a2011-10-07 17:12:00 +0000296 sys.stdout.close()
msb@chromium.orge28e4982009-09-25 20:51:45 +0000297
298 def testRevertNew(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000299 if not self.enabled:
300 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000301 options = self.Options()
John Budorick0f7b2002018-01-19 15:46:17 -0800302 scm = gclient_scm.GitWrapper(self.url, self.root_dir,
303 self.relpath)
nasser@codeaurora.orgb2b46312010-04-30 20:58:03 +0000304 file_list = []
305 scm.update(options, None, file_list)
maruel@chromium.org795a8c12010-10-05 19:54:29 +0000306 file_path = join(self.base_path, 'c')
Edward Lemur979fa782019-08-13 22:44:05 +0000307 with open(file_path, 'w') as f:
308 f.writelines('new\n')
Edward Lesmese79107e2019-10-25 22:47:33 +0000309 Popen([GIT, 'add', 'c'], stdout=PIPE,
maruel@chromium.org8ef5f542009-11-12 02:05:02 +0000310 stderr=STDOUT, cwd=self.base_path).communicate()
msb@chromium.orge28e4982009-09-25 20:51:45 +0000311 file_list = []
312 scm.revert(options, self.args, file_list)
Edward Lemur979fa782019-08-13 22:44:05 +0000313 self.assertEqual(file_list, [file_path])
msb@chromium.orge28e4982009-09-25 20:51:45 +0000314 file_list = []
315 scm.diff(options, self.args, file_list)
Edward Lemur979fa782019-08-13 22:44:05 +0000316 self.assertEqual(file_list, [])
317 self.assertEqual(scm.revinfo(options, self.args, None),
318 'a7142dc9f0009350b96a11f372b6ea658592aa95')
szager@google.com85d3e3a2011-10-07 17:12:00 +0000319 sys.stdout.close()
msb@chromium.orge28e4982009-09-25 20:51:45 +0000320
Joanna Wanga654ff32023-07-18 23:25:19 +0000321 def testStatusRef(self):
322 if not self.enabled:
323 return
324 options = self.Options()
325 file_paths = [join(self.base_path, 'a')]
326 with open(file_paths[0], 'a') as f:
327 f.writelines('touched\n')
328 scm = gclient_scm.GitWrapper(self.url + '@refs/heads/feature',
329 self.root_dir, self.relpath)
330 file_paths.append(join(self.base_path, 'c')) # feature branch touches c
331 file_list = []
332 scm.status(options, self.args, file_list)
333 self.assertEqual(file_list, file_paths)
334 self.checkstdout(
335 ('\n________ running \'git -c core.quotePath=false diff --name-status '
336 'refs/remotes/origin/feature\' in \'%s\'\n\nM\ta\n') %
337 join(self.root_dir, '.'))
338
msb@chromium.orge28e4982009-09-25 20:51:45 +0000339 def testStatusNew(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000340 if not self.enabled:
341 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000342 options = self.Options()
maruel@chromium.org795a8c12010-10-05 19:54:29 +0000343 file_path = join(self.base_path, 'a')
Edward Lemur979fa782019-08-13 22:44:05 +0000344 with open(file_path, 'a') as f:
345 f.writelines('touched\n')
Anthony Politobb457342019-11-15 22:26:01 +0000346 scm = gclient_scm.GitWrapper(
347 self.url + '@069c602044c5388d2d15c3f875b057c852003458', self.root_dir,
348 self.relpath)
msb@chromium.orge28e4982009-09-25 20:51:45 +0000349 file_list = []
350 scm.status(options, self.args, file_list)
Edward Lemur979fa782019-08-13 22:44:05 +0000351 self.assertEqual(file_list, [file_path])
maruel@chromium.org389d6de2010-09-09 14:14:37 +0000352 self.checkstdout(
Aaron Gablef4068aa2017-12-12 15:14:09 -0800353 ('\n________ running \'git -c core.quotePath=false diff --name-status '
Edward Lemur24146be2019-08-01 21:44:52 +0000354 '069c602044c5388d2d15c3f875b057c852003458\' in \'%s\'\n\nM\ta\n') %
maruel@chromium.org795a8c12010-10-05 19:54:29 +0000355 join(self.root_dir, '.'))
msb@chromium.orge28e4982009-09-25 20:51:45 +0000356
Anthony Politobb457342019-11-15 22:26:01 +0000357
358 def testStatusNewNoBaseRev(self):
359 if not self.enabled:
360 return
361 options = self.Options()
362 file_path = join(self.base_path, 'a')
363 with open(file_path, 'a') as f:
364 f.writelines('touched\n')
365 scm = gclient_scm.GitWrapper(self.url, self.root_dir, self.relpath)
366 file_list = []
367 scm.status(options, self.args, file_list)
368 self.assertEqual(file_list, [file_path])
369 self.checkstdout(
370 ('\n________ running \'git -c core.quotePath=false diff --name-status'
371 '\' in \'%s\'\n\nM\ta\n') % join(self.root_dir, '.'))
372
msb@chromium.orge28e4982009-09-25 20:51:45 +0000373 def testStatus2New(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000374 if not self.enabled:
375 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000376 options = self.Options()
377 expected_file_list = []
378 for f in ['a', 'b']:
maruel@chromium.orgbf38a7e2010-12-14 18:15:54 +0000379 file_path = join(self.base_path, f)
Edward Lemur979fa782019-08-13 22:44:05 +0000380 with open(file_path, 'a') as f:
381 f.writelines('touched\n')
maruel@chromium.orgbf38a7e2010-12-14 18:15:54 +0000382 expected_file_list.extend([file_path])
Anthony Politobb457342019-11-15 22:26:01 +0000383 scm = gclient_scm.GitWrapper(
384 self.url + '@069c602044c5388d2d15c3f875b057c852003458', self.root_dir,
385 self.relpath)
msb@chromium.orge28e4982009-09-25 20:51:45 +0000386 file_list = []
387 scm.status(options, self.args, file_list)
maruel@chromium.org795a8c12010-10-05 19:54:29 +0000388 expected_file_list = [join(self.base_path, x) for x in ['a', 'b']]
Edward Lemur979fa782019-08-13 22:44:05 +0000389 self.assertEqual(sorted(file_list), expected_file_list)
maruel@chromium.org389d6de2010-09-09 14:14:37 +0000390 self.checkstdout(
Aaron Gablef4068aa2017-12-12 15:14:09 -0800391 ('\n________ running \'git -c core.quotePath=false diff --name-status '
Edward Lemur24146be2019-08-01 21:44:52 +0000392 '069c602044c5388d2d15c3f875b057c852003458\' in \'%s\'\n\nM\ta\nM\tb\n')
393 % join(self.root_dir, '.'))
msb@chromium.orge28e4982009-09-25 20:51:45 +0000394
msb@chromium.orge28e4982009-09-25 20:51:45 +0000395 def testUpdateUpdate(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000396 if not self.enabled:
397 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000398 options = self.Options()
maruel@chromium.org795a8c12010-10-05 19:54:29 +0000399 expected_file_list = [join(self.base_path, x) for x in ['a', 'b']]
John Budorick0f7b2002018-01-19 15:46:17 -0800400 scm = gclient_scm.GitWrapper(self.url, self.root_dir,
401 self.relpath)
msb@chromium.orge28e4982009-09-25 20:51:45 +0000402 file_list = []
Joanna Wang4e6c1072023-08-17 18:46:24 +0000403
msb@chromium.orge28e4982009-09-25 20:51:45 +0000404 scm.update(options, (), file_list)
Edward Lemur979fa782019-08-13 22:44:05 +0000405 self.assertEqual(file_list, expected_file_list)
406 self.assertEqual(scm.revinfo(options, (), None),
msb@chromium.orge28e4982009-09-25 20:51:45 +0000407 'a7142dc9f0009350b96a11f372b6ea658592aa95')
Joanna Wangd9ea0722023-08-18 20:05:53 +0000408 self.assertEqual(scm._Capture(['config', '--get', 'diff.ignoreSubmodules']),
409 'dirty')
Josip Sokcevic84c0bba2023-08-10 00:52:15 +0000410 self.assertEqual(
411 scm._Capture(['config', '--get', 'fetch.recurseSubmodules']), 'off')
maruel@chromium.orgc6ca3a12012-06-20 14:46:02 +0000412 sys.stdout.close()
msb@chromium.orge28e4982009-09-25 20:51:45 +0000413
bauerb@chromium.org30c46d62014-01-23 12:11:56 +0000414 def testUpdateMerge(self):
415 if not self.enabled:
416 return
417 options = self.Options()
418 options.merge = True
John Budorick0f7b2002018-01-19 15:46:17 -0800419 scm = gclient_scm.GitWrapper(self.url, self.root_dir,
420 self.relpath)
bauerb@chromium.org30c46d62014-01-23 12:11:56 +0000421 scm._Run(['checkout', '-q', 'feature'], options)
422 rev = scm.revinfo(options, (), None)
423 file_list = []
424 scm.update(options, (), file_list)
Edward Lemur979fa782019-08-13 22:44:05 +0000425 self.assertEqual(file_list, [join(self.base_path, x)
426 for x in ['a', 'b', 'c']])
bauerb@chromium.org30c46d62014-01-23 12:11:56 +0000427 # The actual commit that is created is unstable, so we verify its tree and
428 # parents instead.
Edward Lemur979fa782019-08-13 22:44:05 +0000429 self.assertEqual(scm._Capture(['rev-parse', 'HEAD:']),
430 'd2e35c10ac24d6c621e14a1fcadceb533155627d')
Edward Lesmese79107e2019-10-25 22:47:33 +0000431 parent = 'HEAD^' if sys.platform != 'win32' else 'HEAD^^'
432 self.assertEqual(scm._Capture(['rev-parse', parent + '1']), rev)
433 self.assertEqual(scm._Capture(['rev-parse', parent + '2']),
Josip Sokcevic7e133ff2021-07-13 17:44:53 +0000434 scm._Capture(['rev-parse', 'origin/main']))
bauerb@chromium.org30c46d62014-01-23 12:11:56 +0000435 sys.stdout.close()
436
437 def testUpdateRebase(self):
438 if not self.enabled:
439 return
440 options = self.Options()
John Budorick0f7b2002018-01-19 15:46:17 -0800441 scm = gclient_scm.GitWrapper(self.url, self.root_dir,
442 self.relpath)
bauerb@chromium.org30c46d62014-01-23 12:11:56 +0000443 scm._Run(['checkout', '-q', 'feature'], options)
444 file_list = []
445 # Fake a 'y' key press.
446 scm._AskForData = self._GetAskForDataCallback(
447 'Cannot fast-forward merge, attempt to rebase? '
448 '(y)es / (q)uit / (s)kip : ', 'y')
449 scm.update(options, (), file_list)
Edward Lemur979fa782019-08-13 22:44:05 +0000450 self.assertEqual(file_list, [join(self.base_path, x)
451 for x in ['a', 'b', 'c']])
bauerb@chromium.org30c46d62014-01-23 12:11:56 +0000452 # The actual commit that is created is unstable, so we verify its tree and
453 # parent instead.
Edward Lemur979fa782019-08-13 22:44:05 +0000454 self.assertEqual(scm._Capture(['rev-parse', 'HEAD:']),
455 'd2e35c10ac24d6c621e14a1fcadceb533155627d')
Edward Lesmese79107e2019-10-25 22:47:33 +0000456 parent = 'HEAD^' if sys.platform != 'win32' else 'HEAD^^'
457 self.assertEqual(scm._Capture(['rev-parse', parent + '1']),
Josip Sokcevic7e133ff2021-07-13 17:44:53 +0000458 scm._Capture(['rev-parse', 'origin/main']))
bauerb@chromium.org30c46d62014-01-23 12:11:56 +0000459 sys.stdout.close()
460
steveblock@chromium.org98e69452012-02-16 16:36:43 +0000461 def testUpdateReset(self):
462 if not self.enabled:
463 return
464 options = self.Options()
465 options.reset = True
466
467 dir_path = join(self.base_path, 'c')
468 os.mkdir(dir_path)
Edward Lemur979fa782019-08-13 22:44:05 +0000469 with open(join(dir_path, 'nested'), 'w') as f:
470 f.writelines('new\n')
steveblock@chromium.org98e69452012-02-16 16:36:43 +0000471
472 file_path = join(self.base_path, 'file')
Edward Lemur979fa782019-08-13 22:44:05 +0000473 with open(file_path, 'w') as f:
474 f.writelines('new\n')
steveblock@chromium.org98e69452012-02-16 16:36:43 +0000475
John Budorick0f7b2002018-01-19 15:46:17 -0800476 scm = gclient_scm.GitWrapper(self.url, self.root_dir,
477 self.relpath)
steveblock@chromium.org98e69452012-02-16 16:36:43 +0000478 file_list = []
479 scm.update(options, (), file_list)
480 self.assert_(gclient_scm.os.path.isdir(dir_path))
481 self.assert_(gclient_scm.os.path.isfile(file_path))
maruel@chromium.orgc6ca3a12012-06-20 14:46:02 +0000482 sys.stdout.close()
steveblock@chromium.org98e69452012-02-16 16:36:43 +0000483
Edward Lemur579c9862018-07-13 23:17:51 +0000484 def testUpdateResetUnsetsFetchConfig(self):
485 if not self.enabled:
486 return
487 options = self.Options()
488 options.reset = True
489
490 scm = gclient_scm.GitWrapper(self.url, self.root_dir,
491 self.relpath)
492 scm._Run(['config', 'remote.origin.fetch',
493 '+refs/heads/bad/ref:refs/remotes/origin/bad/ref'], options)
494
495 file_list = []
496 scm.update(options, (), file_list)
Edward Lemur979fa782019-08-13 22:44:05 +0000497 self.assertEqual(scm.revinfo(options, (), None),
498 '069c602044c5388d2d15c3f875b057c852003458')
Edward Lemur579c9862018-07-13 23:17:51 +0000499 sys.stdout.close()
500
steveblock@chromium.org98e69452012-02-16 16:36:43 +0000501 def testUpdateResetDeleteUnversionedTrees(self):
502 if not self.enabled:
503 return
504 options = self.Options()
505 options.reset = True
506 options.delete_unversioned_trees = True
507
508 dir_path = join(self.base_path, 'dir')
509 os.mkdir(dir_path)
Edward Lemur979fa782019-08-13 22:44:05 +0000510 with open(join(dir_path, 'nested'), 'w') as f:
511 f.writelines('new\n')
steveblock@chromium.org98e69452012-02-16 16:36:43 +0000512
513 file_path = join(self.base_path, 'file')
Edward Lemur979fa782019-08-13 22:44:05 +0000514 with open(file_path, 'w') as f:
515 f.writelines('new\n')
steveblock@chromium.org98e69452012-02-16 16:36:43 +0000516
John Budorick0f7b2002018-01-19 15:46:17 -0800517 scm = gclient_scm.GitWrapper(self.url, self.root_dir,
518 self.relpath)
steveblock@chromium.org98e69452012-02-16 16:36:43 +0000519 file_list = []
520 scm.update(options, (), file_list)
521 self.assert_(not gclient_scm.os.path.isdir(dir_path))
522 self.assert_(gclient_scm.os.path.isfile(file_path))
maruel@chromium.orgc6ca3a12012-06-20 14:46:02 +0000523 sys.stdout.close()
steveblock@chromium.org98e69452012-02-16 16:36:43 +0000524
nasser@codeaurora.orgd90ba3f2010-02-23 14:42:57 +0000525 def testUpdateUnstagedConflict(self):
526 if not self.enabled:
527 return
528 options = self.Options()
John Budorick0f7b2002018-01-19 15:46:17 -0800529 scm = gclient_scm.GitWrapper(self.url, self.root_dir,
530 self.relpath)
maruel@chromium.org795a8c12010-10-05 19:54:29 +0000531 file_path = join(self.base_path, 'b')
Edward Lemur979fa782019-08-13 22:44:05 +0000532 with open(file_path, 'w') as f:
533 f.writelines('conflict\n')
maruel@chromium.orgcdbecc42011-02-09 04:31:47 +0000534 try:
535 scm.update(options, (), [])
536 self.fail()
maruel@chromium.orgfae707b2011-09-15 18:57:58 +0000537 except (gclient_scm.gclient_utils.Error, subprocess2.CalledProcessError):
maruel@chromium.orgcdbecc42011-02-09 04:31:47 +0000538 # The exact exception text varies across git versions so it's not worth
539 # verifying it. It's fine as long as it throws.
540 pass
541 # Manually flush stdout since we can't verify it's content accurately across
542 # git versions.
543 sys.stdout.getvalue()
544 sys.stdout.close()
nasser@codeaurora.orgd90ba3f2010-02-23 14:42:57 +0000545
Mike Stipicevice992b612016-12-02 15:32:55 -0800546 @unittest.skip('Skipping until crbug.com/670884 is resolved.')
iannucci@chromium.org30a07982016-04-07 21:35:19 +0000547 def testUpdateLocked(self):
548 if not self.enabled:
549 return
550 options = self.Options()
John Budorick0f7b2002018-01-19 15:46:17 -0800551 scm = gclient_scm.GitWrapper(self.url, self.root_dir,
552 self.relpath)
iannucci@chromium.org30a07982016-04-07 21:35:19 +0000553 file_path = join(self.base_path, '.git', 'index.lock')
554 with open(file_path, 'w'):
555 pass
Robert Iannucci53f35552016-12-15 19:09:16 -0800556 with self.assertRaises(subprocess2.CalledProcessError):
iannucci@chromium.org30a07982016-04-07 21:35:19 +0000557 scm.update(options, (), [])
558 sys.stdout.close()
559
560 def testUpdateLockedBreak(self):
561 if not self.enabled:
562 return
563 options = self.Options()
564 options.break_repo_locks = True
John Budorick0f7b2002018-01-19 15:46:17 -0800565 scm = gclient_scm.GitWrapper(self.url, self.root_dir,
566 self.relpath)
iannucci@chromium.org30a07982016-04-07 21:35:19 +0000567 file_path = join(self.base_path, '.git', 'index.lock')
568 with open(file_path, 'w'):
569 pass
570 scm.update(options, (), [])
571 self.assertRegexpMatches(sys.stdout.getvalue(),
Raul Tambrea79f0e52019-09-21 07:27:39 +0000572 r'breaking lock.*\.git[/|\\]index\.lock')
iannucci@chromium.org30a07982016-04-07 21:35:19 +0000573 self.assertFalse(os.path.exists(file_path))
574 sys.stdout.close()
575
msb@chromium.org5bde4852009-12-14 16:47:12 +0000576 def testUpdateConflict(self):
577 if not self.enabled:
578 return
579 options = self.Options()
John Budorick0f7b2002018-01-19 15:46:17 -0800580 scm = gclient_scm.GitWrapper(self.url, self.root_dir,
581 self.relpath)
maruel@chromium.org795a8c12010-10-05 19:54:29 +0000582 file_path = join(self.base_path, 'b')
Edward Lemur979fa782019-08-13 22:44:05 +0000583 with open(file_path, 'w') as f:
584 f.writelines('conflict\n')
maruel@chromium.org389d6de2010-09-09 14:14:37 +0000585 scm._Run(['commit', '-am', 'test'], options)
bauerb@chromium.org30c46d62014-01-23 12:11:56 +0000586 scm._AskForData = self._GetAskForDataCallback(
587 'Cannot fast-forward merge, attempt to rebase? '
588 '(y)es / (q)uit / (s)kip : ', 'y')
Edward Lemur979fa782019-08-13 22:44:05 +0000589
590 with self.assertRaises(gclient_scm.gclient_utils.Error) as e:
591 scm.update(options, (), [])
592 self.assertEqual(
593 e.exception.args[0],
594 'Conflict while rebasing this branch.\n'
595 'Fix the conflict and run gclient again.\n'
596 'See \'man git-rebase\' for details.\n')
597
598 with self.assertRaises(gclient_scm.gclient_utils.Error) as e:
599 scm.update(options, (), [])
600 self.assertEqual(
601 e.exception.args[0],
Josip Sokcevic7e133ff2021-07-13 17:44:53 +0000602 '\n____ . at refs/remotes/origin/main\n'
Edward Lemur979fa782019-08-13 22:44:05 +0000603 '\tYou have unstaged changes.\n'
604 '\tPlease commit, stash, or reset.\n')
605
maruel@chromium.orgcb2985f2010-11-03 14:08:31 +0000606 sys.stdout.close()
msb@chromium.org5bde4852009-12-14 16:47:12 +0000607
msb@chromium.org0f282062009-11-06 20:14:02 +0000608 def testRevinfo(self):
609 if not self.enabled:
610 return
611 options = self.Options()
John Budorick0f7b2002018-01-19 15:46:17 -0800612 scm = gclient_scm.GitWrapper(self.url, self.root_dir,
613 self.relpath)
msb@chromium.org0f282062009-11-06 20:14:02 +0000614 rev_info = scm.revinfo(options, (), None)
Edward Lemur979fa782019-08-13 22:44:05 +0000615 self.assertEqual(rev_info, '069c602044c5388d2d15c3f875b057c852003458')
msb@chromium.org0f282062009-11-06 20:14:02 +0000616
msb@chromium.orge28e4982009-09-25 20:51:45 +0000617
Edward Lemur979fa782019-08-13 22:44:05 +0000618class ManagedGitWrapperTestCaseMock(unittest.TestCase):
dbeam@chromium.orge5d1e612011-12-19 19:49:19 +0000619 class OptionsObject(object):
620 def __init__(self, verbose=False, revision=None, force=False):
621 self.verbose = verbose
622 self.revision = revision
623 self.deps_os = None
624 self.force = force
625 self.reset = False
626 self.nohooks = False
iannucci@chromium.org30a07982016-04-07 21:35:19 +0000627 self.break_repo_locks = False
dbeam@chromium.orge5d1e612011-12-19 19:49:19 +0000628 # TODO(maruel): Test --jobs > 1.
629 self.jobs = 1
Edward Lesmesc621b212018-03-21 20:26:56 -0400630 self.patch_ref = None
631 self.patch_repo = None
632 self.rebase_patch_ref = True
dbeam@chromium.orge5d1e612011-12-19 19:49:19 +0000633
634 def Options(self, *args, **kwargs):
635 return self.OptionsObject(*args, **kwargs)
636
borenet@google.comb09097a2014-04-09 19:09:08 +0000637 def checkstdout(self, expected):
Aravind Vasudevanc5f0cbb2022-01-24 23:56:57 +0000638 # pylint: disable=no-member
borenet@google.comb09097a2014-04-09 19:09:08 +0000639 value = sys.stdout.getvalue()
primiano@chromium.org5439ea52014-08-06 17:18:18 +0000640 sys.stdout.close()
Erik Chene16ffff2019-10-14 20:35:53 +0000641 # Check that the expected output appears.
Erik Chene16ffff2019-10-14 20:35:53 +0000642 self.assertIn(expected, strip_timestamps(value))
borenet@google.comb09097a2014-04-09 19:09:08 +0000643
dbeam@chromium.orge5d1e612011-12-19 19:49:19 +0000644 def setUp(self):
dbeam@chromium.orge5d1e612011-12-19 19:49:19 +0000645 self.fake_hash_1 = 't0ta11yf4k3'
646 self.fake_hash_2 = '3v3nf4k3r'
647 self.url = 'git://foo'
maruel@chromium.org97170132013-05-08 14:58:34 +0000648 self.root_dir = '/tmp' if sys.platform != 'win32' else 't:\\tmp'
dbeam@chromium.orge5d1e612011-12-19 19:49:19 +0000649 self.relpath = 'fake'
650 self.base_path = os.path.join(self.root_dir, self.relpath)
primiano@chromium.org1c127382015-02-17 11:15:40 +0000651 self.backup_base_path = os.path.join(self.root_dir,
652 'old_%s.git' % self.relpath)
Edward Lemur979fa782019-08-13 22:44:05 +0000653 mock.patch('gclient_scm.scm.GIT.ApplyEnvVars').start()
654 mock.patch('gclient_scm.GitWrapper._CheckMinVersion').start()
655 mock.patch('gclient_scm.GitWrapper._Fetch').start()
656 mock.patch('gclient_scm.GitWrapper._DeleteOrMove').start()
657 mock.patch('sys.stdout', StringIO()).start()
658 self.addCleanup(mock.patch.stopall)
dbeam@chromium.orge5d1e612011-12-19 19:49:19 +0000659
Josip Sokcevic7958e302023-03-01 23:02:21 +0000660 @mock.patch('scm.GIT.IsValidRevision')
Edward Lemur979fa782019-08-13 22:44:05 +0000661 @mock.patch('os.path.isdir', lambda _: True)
662 def testGetUsableRevGit(self, mockIsValidRevision):
Quinten Yearsleyb2cc4a92016-12-15 13:53:26 -0800663 # pylint: disable=no-member
smutae7ea312016-07-18 11:59:41 -0700664 options = self.Options(verbose=True)
665
Edward Lemur979fa782019-08-13 22:44:05 +0000666 mockIsValidRevision.side_effect = lambda cwd, rev: rev != '1'
smutae7ea312016-07-18 11:59:41 -0700667
John Budorick0f7b2002018-01-19 15:46:17 -0800668 git_scm = gclient_scm.GitWrapper(self.url, self.root_dir,
669 self.relpath)
smutae7ea312016-07-18 11:59:41 -0700670 # A [fake] git sha1 with a git repo should work (this is in the case that
671 # the LKGR gets flipped to git sha1's some day).
Edward Lemur979fa782019-08-13 22:44:05 +0000672 self.assertEqual(git_scm.GetUsableRev(self.fake_hash_1, options),
673 self.fake_hash_1)
smutae7ea312016-07-18 11:59:41 -0700674 # An SVN rev with an existing purely git repo should raise an exception.
675 self.assertRaises(gclient_scm.gclient_utils.Error,
676 git_scm.GetUsableRev, '1', options)
677
Edward Lemur979fa782019-08-13 22:44:05 +0000678 @mock.patch('gclient_scm.GitWrapper._Clone')
679 @mock.patch('os.path.isdir')
680 @mock.patch('os.path.exists')
681 @mock.patch('subprocess2.check_output')
682 def testUpdateNoDotGit(
683 self, mockCheckOutput, mockExists, mockIsdir, mockClone):
684 mockIsdir.side_effect = lambda path: path == self.base_path
685 mockExists.side_effect = lambda path: path == self.base_path
Josip Sokcevic091f5ac2021-01-14 23:14:21 +0000686 mockCheckOutput.side_effect = [b'refs/remotes/origin/main', b'', b'']
Edward Lemur979fa782019-08-13 22:44:05 +0000687
borenet@google.comb09097a2014-04-09 19:09:08 +0000688 options = self.Options()
Edward Lemur979fa782019-08-13 22:44:05 +0000689 scm = gclient_scm.GitWrapper(
690 self.url, self.root_dir, self.relpath)
borenet@google.comb09097a2014-04-09 19:09:08 +0000691 scm.update(options, None, [])
Edward Lemur979fa782019-08-13 22:44:05 +0000692
693 env = gclient_scm.scm.GIT.ApplyEnvVars({})
Josip Sokcevic091f5ac2021-01-14 23:14:21 +0000694 self.assertEqual(mockCheckOutput.mock_calls, [
695 mock.call(['git', 'symbolic-ref', 'refs/remotes/origin/HEAD'],
696 cwd=self.base_path,
697 env=env,
698 stderr=-1),
699 mock.call(['git', '-c', 'core.quotePath=false', 'ls-files'],
700 cwd=self.base_path,
701 env=env,
702 stderr=-1),
703 mock.call(['git', 'rev-parse', '--verify', 'HEAD'],
704 cwd=self.base_path,
705 env=env,
706 stderr=-1),
707 ])
708 mockClone.assert_called_with('refs/remotes/origin/main', self.url, options)
borenet@google.comb09097a2014-04-09 19:09:08 +0000709 self.checkstdout('\n')
710
Edward Lemur979fa782019-08-13 22:44:05 +0000711 @mock.patch('gclient_scm.GitWrapper._Clone')
712 @mock.patch('os.path.isdir')
713 @mock.patch('os.path.exists')
714 @mock.patch('subprocess2.check_output')
715 def testUpdateConflict(
716 self, mockCheckOutput, mockExists, mockIsdir, mockClone):
717 mockIsdir.side_effect = lambda path: path == self.base_path
718 mockExists.side_effect = lambda path: path == self.base_path
Josip Sokcevic091f5ac2021-01-14 23:14:21 +0000719 mockCheckOutput.side_effect = [b'refs/remotes/origin/main', b'', b'']
Edward Lemur979fa782019-08-13 22:44:05 +0000720 mockClone.side_effect = [
721 gclient_scm.subprocess2.CalledProcessError(
722 None, None, None, None, None),
723 None,
724 ]
725
borenet@google.com90fe58b2014-05-01 18:22:00 +0000726 options = self.Options()
Edward Lemur979fa782019-08-13 22:44:05 +0000727 scm = gclient_scm.GitWrapper(self.url, self.root_dir,
John Budorick0f7b2002018-01-19 15:46:17 -0800728 self.relpath)
borenet@google.comb09097a2014-04-09 19:09:08 +0000729 scm.update(options, None, [])
Edward Lemur979fa782019-08-13 22:44:05 +0000730
731 env = gclient_scm.scm.GIT.ApplyEnvVars({})
Josip Sokcevic091f5ac2021-01-14 23:14:21 +0000732 self.assertEqual(mockCheckOutput.mock_calls, [
733 mock.call(['git', 'symbolic-ref', 'refs/remotes/origin/HEAD'],
734 cwd=self.base_path,
735 env=env,
736 stderr=-1),
737 mock.call(['git', '-c', 'core.quotePath=false', 'ls-files'],
738 cwd=self.base_path,
739 env=env,
740 stderr=-1),
741 mock.call(['git', 'rev-parse', '--verify', 'HEAD'],
742 cwd=self.base_path,
743 env=env,
744 stderr=-1),
745 ])
746 mockClone.assert_called_with('refs/remotes/origin/main', self.url, options)
borenet@google.comb09097a2014-04-09 19:09:08 +0000747 self.checkstdout('\n')
748
dbeam@chromium.orge5d1e612011-12-19 19:49:19 +0000749
cmp@chromium.orgeb2756d2011-09-20 20:17:51 +0000750class UnmanagedGitWrapperTestCase(BaseGitWrapperTestCase):
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000751 def checkInStdout(self, expected):
Aravind Vasudevanc5f0cbb2022-01-24 23:56:57 +0000752 # pylint: disable=no-member
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000753 value = sys.stdout.getvalue()
754 sys.stdout.close()
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000755 self.assertIn(expected, value)
756
757 def checkNotInStdout(self, expected):
Aravind Vasudevanc5f0cbb2022-01-24 23:56:57 +0000758 # pylint: disable=no-member
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000759 value = sys.stdout.getvalue()
760 sys.stdout.close()
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000761 self.assertNotIn(expected, value)
762
smut@google.com27c9c8a2014-09-11 19:57:55 +0000763 def getCurrentBranch(self):
764 # Returns name of current branch or HEAD for detached HEAD
765 branch = gclient_scm.scm.GIT.Capture(['rev-parse', '--abbrev-ref', 'HEAD'],
766 cwd=self.base_path)
767 if branch == 'HEAD':
768 return None
769 return branch
770
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000771 def testUpdateClone(self):
772 if not self.enabled:
773 return
774 options = self.Options()
775
776 origin_root_dir = self.root_dir
Edward Lesmese79107e2019-10-25 22:47:33 +0000777 self.addCleanup(gclient_utils.rmtree, origin_root_dir)
778
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000779 self.root_dir = tempfile.mkdtemp()
780 self.relpath = '.'
781 self.base_path = join(self.root_dir, self.relpath)
782
John Budorick0f7b2002018-01-19 15:46:17 -0800783 scm = gclient_scm.GitWrapper(origin_root_dir,
784 self.root_dir,
785 self.relpath)
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000786
szager@chromium.org3dc5cb72014-06-17 15:06:05 +0000787 expected_file_list = [join(self.base_path, "a"),
788 join(self.base_path, "b")]
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000789 file_list = []
790 options.revision = 'unmanaged'
791 scm.update(options, (), file_list)
792
Edward Lemur979fa782019-08-13 22:44:05 +0000793 self.assertEqual(file_list, expected_file_list)
794 self.assertEqual(scm.revinfo(options, (), None),
795 '069c602044c5388d2d15c3f875b057c852003458')
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000796 # indicates detached HEAD
Edward Lemur979fa782019-08-13 22:44:05 +0000797 self.assertEqual(self.getCurrentBranch(), None)
szager@chromium.org3dc5cb72014-06-17 15:06:05 +0000798 self.checkInStdout(
Josip Sokcevic7e133ff2021-07-13 17:44:53 +0000799 'Checked out refs/remotes/origin/main to a detached HEAD')
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000800
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000801
802 def testUpdateCloneOnCommit(self):
803 if not self.enabled:
804 return
805 options = self.Options()
806
807 origin_root_dir = self.root_dir
Edward Lesmese79107e2019-10-25 22:47:33 +0000808 self.addCleanup(gclient_utils.rmtree, origin_root_dir)
809
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000810 self.root_dir = tempfile.mkdtemp()
811 self.relpath = '.'
812 self.base_path = join(self.root_dir, self.relpath)
813 url_with_commit_ref = origin_root_dir +\
814 '@a7142dc9f0009350b96a11f372b6ea658592aa95'
815
John Budorick0f7b2002018-01-19 15:46:17 -0800816 scm = gclient_scm.GitWrapper(url_with_commit_ref,
817 self.root_dir,
818 self.relpath)
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000819
szager@chromium.org3dc5cb72014-06-17 15:06:05 +0000820 expected_file_list = [join(self.base_path, "a"),
821 join(self.base_path, "b")]
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000822 file_list = []
823 options.revision = 'unmanaged'
824 scm.update(options, (), file_list)
825
Edward Lemur979fa782019-08-13 22:44:05 +0000826 self.assertEqual(file_list, expected_file_list)
827 self.assertEqual(scm.revinfo(options, (), None),
828 'a7142dc9f0009350b96a11f372b6ea658592aa95')
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000829 # indicates detached HEAD
Edward Lemur979fa782019-08-13 22:44:05 +0000830 self.assertEqual(self.getCurrentBranch(), None)
szager@chromium.org3dc5cb72014-06-17 15:06:05 +0000831 self.checkInStdout(
832 'Checked out a7142dc9f0009350b96a11f372b6ea658592aa95 to a detached HEAD')
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000833
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000834 def testUpdateCloneOnBranch(self):
835 if not self.enabled:
836 return
837 options = self.Options()
838
839 origin_root_dir = self.root_dir
Edward Lesmese79107e2019-10-25 22:47:33 +0000840 self.addCleanup(gclient_utils.rmtree, origin_root_dir)
841
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000842 self.root_dir = tempfile.mkdtemp()
843 self.relpath = '.'
844 self.base_path = join(self.root_dir, self.relpath)
845 url_with_branch_ref = origin_root_dir + '@feature'
846
John Budorick0f7b2002018-01-19 15:46:17 -0800847 scm = gclient_scm.GitWrapper(url_with_branch_ref,
848 self.root_dir,
849 self.relpath)
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000850
szager@chromium.org3dc5cb72014-06-17 15:06:05 +0000851 expected_file_list = [join(self.base_path, "a"),
852 join(self.base_path, "b"),
John Budorick882c91e2018-07-12 22:11:41 +0000853 join(self.base_path, "c")]
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000854 file_list = []
855 options.revision = 'unmanaged'
856 scm.update(options, (), file_list)
857
Edward Lemur979fa782019-08-13 22:44:05 +0000858 self.assertEqual(file_list, expected_file_list)
859 self.assertEqual(scm.revinfo(options, (), None),
860 '9a51244740b25fa2ded5252ca00a3178d3f665a9')
Paweł Hajdan, Jr63b8c2a2017-09-05 17:59:08 +0200861 # indicates detached HEAD
Edward Lemur979fa782019-08-13 22:44:05 +0000862 self.assertEqual(self.getCurrentBranch(), None)
Paweł Hajdan, Jr63b8c2a2017-09-05 17:59:08 +0200863 self.checkInStdout(
John Budorick882c91e2018-07-12 22:11:41 +0000864 'Checked out 9a51244740b25fa2ded5252ca00a3178d3f665a9 '
Paweł Hajdan, Jr63b8c2a2017-09-05 17:59:08 +0200865 'to a detached HEAD')
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000866
mmoss@chromium.org6e7202b2014-09-09 18:23:39 +0000867 def testUpdateCloneOnFetchedRemoteBranch(self):
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000868 if not self.enabled:
869 return
870 options = self.Options()
871
872 origin_root_dir = self.root_dir
Edward Lesmese79107e2019-10-25 22:47:33 +0000873 self.addCleanup(gclient_utils.rmtree, origin_root_dir)
874
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000875 self.root_dir = tempfile.mkdtemp()
876 self.relpath = '.'
877 self.base_path = join(self.root_dir, self.relpath)
878 url_with_branch_ref = origin_root_dir + '@refs/remotes/origin/feature'
879
John Budorick0f7b2002018-01-19 15:46:17 -0800880 scm = gclient_scm.GitWrapper(url_with_branch_ref,
881 self.root_dir,
882 self.relpath)
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000883
szager@chromium.org3dc5cb72014-06-17 15:06:05 +0000884 expected_file_list = [join(self.base_path, "a"),
885 join(self.base_path, "b"),
John Budorick882c91e2018-07-12 22:11:41 +0000886 join(self.base_path, "c")]
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000887 file_list = []
888 options.revision = 'unmanaged'
szager@chromium.org3dc5cb72014-06-17 15:06:05 +0000889 scm.update(options, (), file_list)
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000890
Edward Lemur979fa782019-08-13 22:44:05 +0000891 self.assertEqual(file_list, expected_file_list)
892 self.assertEqual(scm.revinfo(options, (), None),
893 '9a51244740b25fa2ded5252ca00a3178d3f665a9')
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000894 # indicates detached HEAD
Edward Lemur979fa782019-08-13 22:44:05 +0000895 self.assertEqual(self.getCurrentBranch(), None)
szager@chromium.org3dc5cb72014-06-17 15:06:05 +0000896 self.checkInStdout(
897 'Checked out refs/remotes/origin/feature to a detached HEAD')
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000898
mmoss@chromium.org6e7202b2014-09-09 18:23:39 +0000899 def testUpdateCloneOnTrueRemoteBranch(self):
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000900 if not self.enabled:
901 return
902 options = self.Options()
903
904 origin_root_dir = self.root_dir
Edward Lesmese79107e2019-10-25 22:47:33 +0000905 self.addCleanup(gclient_utils.rmtree, origin_root_dir)
906
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000907 self.root_dir = tempfile.mkdtemp()
908 self.relpath = '.'
909 self.base_path = join(self.root_dir, self.relpath)
910 url_with_branch_ref = origin_root_dir + '@refs/heads/feature'
911
John Budorick0f7b2002018-01-19 15:46:17 -0800912 scm = gclient_scm.GitWrapper(url_with_branch_ref,
913 self.root_dir,
914 self.relpath)
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000915
szager@chromium.org3dc5cb72014-06-17 15:06:05 +0000916 expected_file_list = [join(self.base_path, "a"),
917 join(self.base_path, "b"),
John Budorick882c91e2018-07-12 22:11:41 +0000918 join(self.base_path, "c")]
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000919 file_list = []
920 options.revision = 'unmanaged'
921 scm.update(options, (), file_list)
922
Edward Lemur979fa782019-08-13 22:44:05 +0000923 self.assertEqual(file_list, expected_file_list)
924 self.assertEqual(scm.revinfo(options, (), None),
925 '9a51244740b25fa2ded5252ca00a3178d3f665a9')
John Budorick882c91e2018-07-12 22:11:41 +0000926 # @refs/heads/feature is AKA @refs/remotes/origin/feature in the clone, so
mmoss@chromium.org6e7202b2014-09-09 18:23:39 +0000927 # should be treated as such by gclient.
928 # TODO(mmoss): Though really, we should only allow DEPS to specify branches
929 # as they are known in the upstream repo, since the mapping into the local
930 # repo can be modified by users (or we might even want to change the gclient
931 # defaults at some point). But that will take more work to stop using
932 # refs/remotes/ everywhere that we do (and to stop assuming a DEPS ref will
933 # always resolve locally, like when passing them to show-ref or rev-list).
Edward Lemur979fa782019-08-13 22:44:05 +0000934 self.assertEqual(self.getCurrentBranch(), None)
mmoss@chromium.org6e7202b2014-09-09 18:23:39 +0000935 self.checkInStdout(
936 'Checked out refs/remotes/origin/feature to a detached HEAD')
romain.pokrzywka@gmail.com483a0ba2014-05-30 00:06:07 +0000937
cmp@chromium.orgeb2756d2011-09-20 20:17:51 +0000938 def testUpdateUpdate(self):
939 if not self.enabled:
940 return
941 options = self.Options()
942 expected_file_list = []
John Budorick0f7b2002018-01-19 15:46:17 -0800943 scm = gclient_scm.GitWrapper(self.url, self.root_dir,
944 self.relpath)
cmp@chromium.orgeb2756d2011-09-20 20:17:51 +0000945 file_list = []
946 options.revision = 'unmanaged'
947 scm.update(options, (), file_list)
Edward Lemur979fa782019-08-13 22:44:05 +0000948 self.assertEqual(file_list, expected_file_list)
949 self.assertEqual(scm.revinfo(options, (), None),
950 '069c602044c5388d2d15c3f875b057c852003458')
cmp@chromium.orgeb2756d2011-09-20 20:17:51 +0000951 self.checkstdout('________ unmanaged solution; skipping .\n')
952
953
Edward Lemur979fa782019-08-13 22:44:05 +0000954class CipdWrapperTestCase(unittest.TestCase):
John Budorick0f7b2002018-01-19 15:46:17 -0800955
956 def setUp(self):
957 # Create this before setting up mocks.
958 self._cipd_root_dir = tempfile.mkdtemp()
959 self._workdir = tempfile.mkdtemp()
John Budorick0f7b2002018-01-19 15:46:17 -0800960
961 self._cipd_instance_url = 'https://chrome-infra-packages.appspot.com'
962 self._cipd_root = gclient_scm.CipdRoot(
963 self._cipd_root_dir,
964 self._cipd_instance_url)
965 self._cipd_packages = [
966 self._cipd_root.add_package('f', 'foo_package', 'foo_version'),
967 self._cipd_root.add_package('b', 'bar_package', 'bar_version'),
968 self._cipd_root.add_package('b', 'baz_package', 'baz_version'),
969 ]
Edward Lemur979fa782019-08-13 22:44:05 +0000970 mock.patch('tempfile.mkdtemp', lambda: self._workdir).start()
971 mock.patch('gclient_scm.CipdRoot.add_package').start()
972 mock.patch('gclient_scm.CipdRoot.clobber').start()
Dan Le Febvre456d0852023-05-24 23:43:40 +0000973 mock.patch('gclient_scm.CipdRoot.ensure_file_resolve').start()
Edward Lemur979fa782019-08-13 22:44:05 +0000974 mock.patch('gclient_scm.CipdRoot.ensure').start()
975 self.addCleanup(mock.patch.stopall)
Edward Lesmese79107e2019-10-25 22:47:33 +0000976 self.addCleanup(gclient_utils.rmtree, self._cipd_root_dir)
977 self.addCleanup(gclient_utils.rmtree, self._workdir)
John Budorick0f7b2002018-01-19 15:46:17 -0800978
979 def createScmWithPackageThatSatisfies(self, condition):
980 return gclient_scm.CipdWrapper(
981 url=self._cipd_instance_url,
982 root_dir=self._cipd_root_dir,
983 relpath='fake_relpath',
984 root=self._cipd_root,
985 package=self.getPackageThatSatisfies(condition))
986
987 def getPackageThatSatisfies(self, condition):
988 for p in self._cipd_packages:
989 if condition(p):
990 return p
991
992 self.fail('Unable to find a satisfactory package.')
993
John Budorick0f7b2002018-01-19 15:46:17 -0800994 def testRevert(self):
John Budorickd3ba72b2018-03-20 12:27:42 -0700995 """Checks that revert does nothing."""
Edward Lemur979fa782019-08-13 22:44:05 +0000996 scm = self.createScmWithPackageThatSatisfies(lambda _: True)
John Budorick0f7b2002018-01-19 15:46:17 -0800997 scm.revert(None, (), [])
998
Edward Lemur979fa782019-08-13 22:44:05 +0000999 @mock.patch('gclient_scm.gclient_utils.CheckCallAndFilter')
1000 @mock.patch('gclient_scm.gclient_utils.rmtree')
1001 def testRevinfo(self, mockRmtree, mockCheckCallAndFilter):
John Budorick0f7b2002018-01-19 15:46:17 -08001002 """Checks that revinfo uses the JSON from cipd describe."""
1003 scm = self.createScmWithPackageThatSatisfies(lambda _: True)
1004
1005 expected_revinfo = '0123456789abcdef0123456789abcdef01234567'
1006 json_contents = {
1007 'result': {
1008 'pin': {
1009 'instance_id': expected_revinfo,
1010 }
1011 }
1012 }
1013 describe_json_path = join(self._workdir, 'describe.json')
1014 with open(describe_json_path, 'w') as describe_json:
1015 json.dump(json_contents, describe_json)
1016
Edward Lemur979fa782019-08-13 22:44:05 +00001017 revinfo = scm.revinfo(None, (), [])
1018 self.assertEqual(revinfo, expected_revinfo)
1019
1020 mockRmtree.assert_called_with(self._workdir)
1021 mockCheckCallAndFilter.assert_called_with([
John Budorick0f7b2002018-01-19 15:46:17 -08001022 'cipd', 'describe', 'foo_package',
1023 '-log-level', 'error',
1024 '-version', 'foo_version',
1025 '-json-output', describe_json_path,
Edward Lemur979fa782019-08-13 22:44:05 +00001026 ])
John Budorick0f7b2002018-01-19 15:46:17 -08001027
1028 def testUpdate(self):
John Budorickd3ba72b2018-03-20 12:27:42 -07001029 """Checks that update does nothing."""
Edward Lemur979fa782019-08-13 22:44:05 +00001030 scm = self.createScmWithPackageThatSatisfies(lambda _: True)
John Budorick0f7b2002018-01-19 15:46:17 -08001031 scm.update(None, (), [])
1032
1033
Edward Lesmes8073a502020-04-15 02:11:14 +00001034class BranchHeadsFakeRepo(fake_repos.FakeReposBase):
1035 def populateGit(self):
1036 # Creates a tree that looks like this:
1037 #
1038 # 5 refs/branch-heads/5
1039 # |
1040 # 4
1041 # |
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001042 # 1--2--3 refs/heads/main
Edward Lesmes8073a502020-04-15 02:11:14 +00001043 self._commit_git('repo_1', {'commit 1': 'touched'})
1044 self._commit_git('repo_1', {'commit 2': 'touched'})
1045 self._commit_git('repo_1', {'commit 3': 'touched'})
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001046 self._create_ref('repo_1', 'refs/heads/main', 3)
Edward Lesmes8073a502020-04-15 02:11:14 +00001047
1048 self._commit_git('repo_1', {'commit 4': 'touched'}, base=2)
1049 self._commit_git('repo_1', {'commit 5': 'touched'}, base=2)
1050 self._create_ref('repo_1', 'refs/branch-heads/5', 5)
1051
1052
1053class BranchHeadsTest(fake_repos.FakeReposTestBase):
1054 FAKE_REPOS_CLASS = BranchHeadsFakeRepo
1055
1056 def setUp(self):
1057 super(BranchHeadsTest, self).setUp()
1058 self.enabled = self.FAKE_REPOS.set_up_git()
1059 self.options = BaseGitWrapperTestCase.OptionsObject()
1060 self.url = self.git_base + 'repo_1'
1061 self.mirror = None
Ben Pastened410c662020-08-26 17:07:03 +00001062 mock.patch('sys.stdout', StringIO()).start()
Edward Lesmes8073a502020-04-15 02:11:14 +00001063 self.addCleanup(mock.patch.stopall)
1064
1065 def setUpMirror(self):
1066 self.mirror = tempfile.mkdtemp('mirror')
1067 git_cache.Mirror.SetCachePath(self.mirror)
1068 self.addCleanup(gclient_utils.rmtree, self.mirror)
1069 self.addCleanup(git_cache.Mirror.SetCachePath, None)
1070
1071 def testCheckoutBranchHeads(self):
1072 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1073 file_list = []
1074
1075 self.options.revision = 'refs/branch-heads/5'
1076 scm.update(self.options, None, file_list)
1077 self.assertEqual(self.githash('repo_1', 5), self.gitrevparse(self.root_dir))
1078
1079 def testCheckoutUpdatedBranchHeads(self):
1080 # Travel back in time, and set refs/branch-heads/5 to its parent.
1081 subprocess2.check_call(
1082 ['git', 'update-ref', 'refs/branch-heads/5', self.githash('repo_1', 4)],
1083 cwd=self.url)
1084
1085 # Sync to refs/branch-heads/5
1086 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1087 self.options.revision = 'refs/branch-heads/5'
1088 scm.update(self.options, None, [])
1089
1090 # Set refs/branch-heads/5 back to its original value.
1091 subprocess2.check_call(
1092 ['git', 'update-ref', 'refs/branch-heads/5', self.githash('repo_1', 5)],
1093 cwd=self.url)
1094
1095 # Attempt to sync to refs/branch-heads/5 again.
1096 self.testCheckoutBranchHeads()
1097
1098 def testCheckoutBranchHeadsMirror(self):
1099 self.setUpMirror()
1100 self.testCheckoutBranchHeads()
1101
1102 def testCheckoutUpdatedBranchHeadsMirror(self):
1103 self.setUpMirror()
1104 self.testCheckoutUpdatedBranchHeads()
1105
1106
Edward Lemurd64781e2018-07-11 23:09:55 +00001107class GerritChangesFakeRepo(fake_repos.FakeReposBase):
1108 def populateGit(self):
1109 # Creates a tree that looks like this:
1110 #
Edward Lemurca7d8812018-07-24 17:42:45 +00001111 # 6 refs/changes/35/1235/1
1112 # |
1113 # 5 refs/changes/34/1234/1
1114 # |
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001115 # 1--2--3--4 refs/heads/main
Edward Lemurca7d8812018-07-24 17:42:45 +00001116 # | |
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001117 # | 11(5)--12 refs/heads/main-with-5
Edward Lemurca7d8812018-07-24 17:42:45 +00001118 # |
1119 # 7--8--9 refs/heads/feature
1120 # |
1121 # 10 refs/changes/36/1236/1
1122 #
Edward Lemurd64781e2018-07-11 23:09:55 +00001123
1124 self._commit_git('repo_1', {'commit 1': 'touched'})
1125 self._commit_git('repo_1', {'commit 2': 'touched'})
1126 self._commit_git('repo_1', {'commit 3': 'touched'})
1127 self._commit_git('repo_1', {'commit 4': 'touched'})
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001128 self._create_ref('repo_1', 'refs/heads/main', 4)
Edward Lemurd64781e2018-07-11 23:09:55 +00001129
1130 # Create a change on top of commit 3 that consists of two commits.
1131 self._commit_git('repo_1',
1132 {'commit 5': 'touched',
1133 'change': '1234'},
1134 base=3)
1135 self._create_ref('repo_1', 'refs/changes/34/1234/1', 5)
1136 self._commit_git('repo_1',
1137 {'commit 6': 'touched',
1138 'change': '1235'})
1139 self._create_ref('repo_1', 'refs/changes/35/1235/1', 6)
1140
Edward Lemurca7d8812018-07-24 17:42:45 +00001141 # Create a refs/heads/feature branch on top of commit 2, consisting of three
1142 # commits.
1143 self._commit_git('repo_1', {'commit 7': 'touched'}, base=2)
1144 self._commit_git('repo_1', {'commit 8': 'touched'})
1145 self._commit_git('repo_1', {'commit 9': 'touched'})
1146 self._create_ref('repo_1', 'refs/heads/feature', 9)
1147
1148 # Create a change of top of commit 8.
1149 self._commit_git('repo_1',
1150 {'commit 10': 'touched',
1151 'change': '1236'},
1152 base=8)
1153 self._create_ref('repo_1', 'refs/changes/36/1236/1', 10)
1154
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001155 # Create a refs/heads/main-with-5 on top of commit 3 which is a branch
Edward Lemurca7d8812018-07-24 17:42:45 +00001156 # where refs/changes/34/1234/1 (commit 5) has already landed as commit 11.
1157 self._commit_git('repo_1',
1158 # This is really commit 11, but has the changes of commit 5
1159 {'commit 5': 'touched',
1160 'change': '1234'},
1161 base=3)
1162 self._commit_git('repo_1', {'commit 12': 'touched'})
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001163 self._create_ref('repo_1', 'refs/heads/main-with-5', 12)
Edward Lemurca7d8812018-07-24 17:42:45 +00001164
Edward Lemurd64781e2018-07-11 23:09:55 +00001165
1166class GerritChangesTest(fake_repos.FakeReposTestBase):
1167 FAKE_REPOS_CLASS = GerritChangesFakeRepo
1168
1169 def setUp(self):
1170 super(GerritChangesTest, self).setUp()
1171 self.enabled = self.FAKE_REPOS.set_up_git()
1172 self.options = BaseGitWrapperTestCase.OptionsObject()
1173 self.url = self.git_base + 'repo_1'
1174 self.mirror = None
Ben Pastened410c662020-08-26 17:07:03 +00001175 mock.patch('sys.stdout', StringIO()).start()
Edward Lesmese79107e2019-10-25 22:47:33 +00001176 self.addCleanup(mock.patch.stopall)
Edward Lemurd64781e2018-07-11 23:09:55 +00001177
1178 def setUpMirror(self):
1179 self.mirror = tempfile.mkdtemp()
1180 git_cache.Mirror.SetCachePath(self.mirror)
Edward Lesmese79107e2019-10-25 22:47:33 +00001181 self.addCleanup(gclient_utils.rmtree, self.mirror)
Edward Lemurd64781e2018-07-11 23:09:55 +00001182 self.addCleanup(git_cache.Mirror.SetCachePath, None)
1183
Edward Lemurca7d8812018-07-24 17:42:45 +00001184 def assertCommits(self, commits):
1185 """Check that all, and only |commits| are present in the current checkout.
1186 """
1187 for i in commits:
1188 name = os.path.join(self.root_dir, 'commit ' + str(i))
Edward Lemur6a4e31b2018-08-10 19:59:02 +00001189 self.assertTrue(os.path.exists(name), 'Commit not found: %s' % name)
Edward Lemurca7d8812018-07-24 17:42:45 +00001190
1191 all_commits = set(range(1, len(self.FAKE_REPOS.git_hashes['repo_1'])))
1192 for i in all_commits - set(commits):
1193 name = os.path.join(self.root_dir, 'commit ' + str(i))
Edward Lemur6a4e31b2018-08-10 19:59:02 +00001194 self.assertFalse(os.path.exists(name), 'Unexpected commit: %s' % name)
Edward Lemurca7d8812018-07-24 17:42:45 +00001195
Edward Lemurd64781e2018-07-11 23:09:55 +00001196 def testCanCloneGerritChange(self):
1197 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1198 file_list = []
1199
1200 self.options.revision = 'refs/changes/35/1235/1'
1201 scm.update(self.options, None, file_list)
1202 self.assertEqual(self.githash('repo_1', 6), self.gitrevparse(self.root_dir))
1203
1204 def testCanSyncToGerritChange(self):
1205 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1206 file_list = []
1207
1208 self.options.revision = self.githash('repo_1', 1)
1209 scm.update(self.options, None, file_list)
1210 self.assertEqual(self.githash('repo_1', 1), self.gitrevparse(self.root_dir))
1211
1212 self.options.revision = 'refs/changes/35/1235/1'
1213 scm.update(self.options, None, file_list)
1214 self.assertEqual(self.githash('repo_1', 6), self.gitrevparse(self.root_dir))
1215
1216 def testCanCloneGerritChangeMirror(self):
1217 self.setUpMirror()
1218 self.testCanCloneGerritChange()
1219
1220 def testCanSyncToGerritChangeMirror(self):
1221 self.setUpMirror()
1222 self.testCanSyncToGerritChange()
1223
Edward Lesmese79107e2019-10-25 22:47:33 +00001224 def testMirrorPushUrl(self):
1225 self.setUpMirror()
1226
1227 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1228 file_list = []
1229 self.assertIsNotNone(scm._GetMirror(self.url, self.options))
1230
1231 scm.update(self.options, None, file_list)
1232
1233 fetch_url = scm._Capture(['remote', 'get-url', 'origin'])
1234 self.assertTrue(
1235 fetch_url.startswith(self.mirror),
1236 msg='\n'.join([
1237 'Repository fetch url should be in the git cache mirror directory.',
1238 ' fetch_url: %s' % fetch_url,
1239 ' mirror: %s' % self.mirror]))
1240 push_url = scm._Capture(['remote', 'get-url', '--push', 'origin'])
1241 self.assertEqual(push_url, self.url)
1242
Edward Lemurca7d8812018-07-24 17:42:45 +00001243 def testAppliesPatchOnTopOfMasterByDefault(self):
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001244 """Test the default case, where we apply a patch on top of main."""
Edward Lemurca7d8812018-07-24 17:42:45 +00001245 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1246 file_list = []
1247
1248 # Make sure we don't specify a revision.
1249 self.options.revision = None
1250 scm.update(self.options, None, file_list)
1251 self.assertEqual(self.githash('repo_1', 4), self.gitrevparse(self.root_dir))
1252
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001253 scm.apply_patch_ref(
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001254 self.url, 'refs/changes/35/1235/1', 'refs/heads/main', self.options,
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001255 file_list)
Edward Lemurca7d8812018-07-24 17:42:45 +00001256
1257 self.assertCommits([1, 2, 3, 4, 5, 6])
1258 self.assertEqual(self.githash('repo_1', 4), self.gitrevparse(self.root_dir))
1259
1260 def testCheckoutOlderThanPatchBase(self):
1261 """Test applying a patch on an old checkout.
1262
1263 We first checkout commit 1, and try to patch refs/changes/35/1235/1, which
1264 contains commits 5 and 6, and is based on top of commit 3.
1265 The final result should contain commits 1, 5 and 6, but not commits 2 or 3.
1266 """
1267 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1268 file_list = []
1269
1270 # Sync to commit 1
1271 self.options.revision = self.githash('repo_1', 1)
1272 scm.update(self.options, None, file_list)
1273 self.assertEqual(self.githash('repo_1', 1), self.gitrevparse(self.root_dir))
1274
1275 # Apply the change on top of that.
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001276 scm.apply_patch_ref(
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001277 self.url, 'refs/changes/35/1235/1', 'refs/heads/main', self.options,
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001278 file_list)
Edward Lemurca7d8812018-07-24 17:42:45 +00001279
1280 self.assertCommits([1, 5, 6])
1281 self.assertEqual(self.githash('repo_1', 1), self.gitrevparse(self.root_dir))
1282
1283 def testCheckoutOriginFeature(self):
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001284 """Tests that we can apply a patch on a branch other than main."""
Edward Lemurca7d8812018-07-24 17:42:45 +00001285 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1286 file_list = []
1287
Edward Lemur8c665652019-05-08 20:23:33 +00001288 # Sync to remote's refs/heads/feature
1289 self.options.revision = 'refs/heads/feature'
Edward Lemurca7d8812018-07-24 17:42:45 +00001290 scm.update(self.options, None, file_list)
1291 self.assertEqual(self.githash('repo_1', 9), self.gitrevparse(self.root_dir))
1292
1293 # Apply the change on top of that.
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001294 scm.apply_patch_ref(
1295 self.url, 'refs/changes/36/1236/1', 'refs/heads/feature', self.options,
1296 file_list)
Edward Lemurca7d8812018-07-24 17:42:45 +00001297
1298 self.assertCommits([1, 2, 7, 8, 9, 10])
1299 self.assertEqual(self.githash('repo_1', 9), self.gitrevparse(self.root_dir))
1300
1301 def testCheckoutOriginFeatureOnOldRevision(self):
1302 """Tests that we can apply a patch on an old checkout, on a branch other
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001303 than main."""
Edward Lemurca7d8812018-07-24 17:42:45 +00001304 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1305 file_list = []
1306
Edward Lemur8c665652019-05-08 20:23:33 +00001307 # Sync to remote's refs/heads/feature on an old revision
Edward Lemurca7d8812018-07-24 17:42:45 +00001308 self.options.revision = self.githash('repo_1', 7)
1309 scm.update(self.options, None, file_list)
1310 self.assertEqual(self.githash('repo_1', 7), self.gitrevparse(self.root_dir))
1311
1312 # Apply the change on top of that.
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001313 scm.apply_patch_ref(
1314 self.url, 'refs/changes/36/1236/1', 'refs/heads/feature', self.options,
1315 file_list)
Edward Lemurca7d8812018-07-24 17:42:45 +00001316
1317 # We shouldn't have rebased on top of 2 (which is the merge base between
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001318 # remote's main branch and the change) but on top of 7 (which is the
Edward Lemur8c665652019-05-08 20:23:33 +00001319 # merge base between remote's feature branch and the change).
Edward Lemurca7d8812018-07-24 17:42:45 +00001320 self.assertCommits([1, 2, 7, 10])
1321 self.assertEqual(self.githash('repo_1', 7), self.gitrevparse(self.root_dir))
1322
Edward Lemur6a4e31b2018-08-10 19:59:02 +00001323 def testCheckoutOriginFeaturePatchBranch(self):
1324 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1325 file_list = []
1326
Edward Lemur8c665652019-05-08 20:23:33 +00001327 # Sync to the hash instead of remote's refs/heads/feature.
Edward Lemur6a4e31b2018-08-10 19:59:02 +00001328 self.options.revision = self.githash('repo_1', 9)
1329 scm.update(self.options, None, file_list)
1330 self.assertEqual(self.githash('repo_1', 9), self.gitrevparse(self.root_dir))
1331
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001332 # Apply refs/changes/34/1234/1, created for remote's main branch on top of
Edward Lemur8c665652019-05-08 20:23:33 +00001333 # remote's feature branch.
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001334 scm.apply_patch_ref(
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001335 self.url, 'refs/changes/35/1235/1', 'refs/heads/main', self.options,
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001336 file_list)
Edward Lemur6a4e31b2018-08-10 19:59:02 +00001337
1338 # Commits 5 and 6 are part of the patch, and commits 1, 2, 7, 8 and 9 are
Edward Lemur8c665652019-05-08 20:23:33 +00001339 # part of remote's feature branch.
Edward Lemur6a4e31b2018-08-10 19:59:02 +00001340 self.assertCommits([1, 2, 5, 6, 7, 8, 9])
1341 self.assertEqual(self.githash('repo_1', 9), self.gitrevparse(self.root_dir))
Edward Lemurca7d8812018-07-24 17:42:45 +00001342
1343 def testDoesntRebasePatchMaster(self):
1344 """Tests that we can apply a patch without rebasing it.
1345 """
1346 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1347 file_list = []
1348
1349 self.options.rebase_patch_ref = False
1350 scm.update(self.options, None, file_list)
1351 self.assertEqual(self.githash('repo_1', 4), self.gitrevparse(self.root_dir))
1352
1353 # Apply the change on top of that.
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001354 scm.apply_patch_ref(
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001355 self.url, 'refs/changes/35/1235/1', 'refs/heads/main', self.options,
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001356 file_list)
Edward Lemurca7d8812018-07-24 17:42:45 +00001357
1358 self.assertCommits([1, 2, 3, 5, 6])
Robert Iannuccic39a7782019-11-01 18:30:33 +00001359 self.assertEqual(self.githash('repo_1', 5), self.gitrevparse(self.root_dir))
Edward Lemurca7d8812018-07-24 17:42:45 +00001360
1361 def testDoesntRebasePatchOldCheckout(self):
1362 """Tests that we can apply a patch without rebasing it on an old checkout.
1363 """
1364 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1365 file_list = []
1366
1367 # Sync to commit 1
1368 self.options.revision = self.githash('repo_1', 1)
1369 self.options.rebase_patch_ref = False
1370 scm.update(self.options, None, file_list)
1371 self.assertEqual(self.githash('repo_1', 1), self.gitrevparse(self.root_dir))
1372
1373 # Apply the change on top of that.
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001374 scm.apply_patch_ref(
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001375 self.url, 'refs/changes/35/1235/1', 'refs/heads/main', self.options,
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001376 file_list)
Edward Lemurca7d8812018-07-24 17:42:45 +00001377
1378 self.assertCommits([1, 2, 3, 5, 6])
Robert Iannuccic39a7782019-11-01 18:30:33 +00001379 self.assertEqual(self.githash('repo_1', 5), self.gitrevparse(self.root_dir))
Edward Lemurca7d8812018-07-24 17:42:45 +00001380
1381 def testDoesntSoftResetIfNotAskedTo(self):
1382 """Test that we can apply a patch without doing a soft reset."""
1383 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1384 file_list = []
1385
1386 self.options.reset_patch_ref = False
1387 scm.update(self.options, None, file_list)
1388 self.assertEqual(self.githash('repo_1', 4), self.gitrevparse(self.root_dir))
1389
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001390 scm.apply_patch_ref(
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001391 self.url, 'refs/changes/35/1235/1', 'refs/heads/main', self.options,
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001392 file_list)
Edward Lemurca7d8812018-07-24 17:42:45 +00001393
1394 self.assertCommits([1, 2, 3, 4, 5, 6])
1395 # The commit hash after cherry-picking is not known, but it must be
1396 # different from what the repo was synced at before patching.
1397 self.assertNotEqual(self.githash('repo_1', 4),
1398 self.gitrevparse(self.root_dir))
1399
Ravi Mistryecda7822022-02-28 16:22:20 +00001400 @mock.patch('gerrit_util.GetChange', return_value={'topic': 'test_topic'})
1401 @mock.patch('gerrit_util.QueryChanges', return_value=[
1402 {'_number': 1234},
1403 {'_number': 1235, 'current_revision': 'abc',
1404 'revisions': {'abc': {'ref': 'refs/changes/35/1235/1'}}}])
1405 def testDownloadTopics(self, query_changes_mock, get_change_mock):
1406 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1407 file_list = []
1408
1409 self.options.revision = 'refs/changes/34/1234/1'
1410 scm.update(self.options, None, file_list)
1411 self.assertEqual(self.githash('repo_1', 5), self.gitrevparse(self.root_dir))
1412
1413 # pylint: disable=attribute-defined-outside-init
1414 self.options.download_topics = True
Ravi Mistryc848a4e2022-03-10 18:19:59 +00001415 scm.url = 'https://test-repo.googlesource.com/repo_1.git'
Ravi Mistryecda7822022-02-28 16:22:20 +00001416 scm.apply_patch_ref(
1417 self.url, 'refs/changes/34/1234/1', 'refs/heads/main', self.options,
1418 file_list)
1419
1420 get_change_mock.assert_called_once_with(
1421 mock.ANY, '1234')
1422 query_changes_mock.assert_called_once_with(
1423 mock.ANY,
1424 [('topic', 'test_topic'), ('status', 'open'), ('repo', 'repo_1')],
1425 o_params=['ALL_REVISIONS'])
1426
1427 self.assertCommits([1, 2, 3, 5, 6])
1428 # The commit hash after the two cherry-picks is not known, but it must be
1429 # different from what the repo was synced at before patching.
1430 self.assertNotEqual(self.githash('repo_1', 4),
1431 self.gitrevparse(self.root_dir))
1432
Edward Lemurca7d8812018-07-24 17:42:45 +00001433 def testRecoversAfterPatchFailure(self):
1434 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1435 file_list = []
1436
1437 self.options.revision = 'refs/changes/34/1234/1'
1438 scm.update(self.options, None, file_list)
1439 self.assertEqual(self.githash('repo_1', 5), self.gitrevparse(self.root_dir))
1440
1441 # Checkout 'refs/changes/34/1234/1' modifies the 'change' file, so trying to
1442 # patch 'refs/changes/36/1236/1' creates a patch failure.
1443 with self.assertRaises(subprocess2.CalledProcessError) as cm:
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001444 scm.apply_patch_ref(
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001445 self.url, 'refs/changes/36/1236/1', 'refs/heads/main', self.options,
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001446 file_list)
Edward Lemurca7d8812018-07-24 17:42:45 +00001447 self.assertEqual(cm.exception.cmd[:2], ['git', 'cherry-pick'])
Edward Lemur979fa782019-08-13 22:44:05 +00001448 self.assertIn(b'error: could not apply', cm.exception.stderr)
Edward Lemurca7d8812018-07-24 17:42:45 +00001449
1450 # Try to apply 'refs/changes/35/1235/1', which doesn't have a merge
1451 # conflict.
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001452 scm.apply_patch_ref(
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001453 self.url, 'refs/changes/35/1235/1', 'refs/heads/main', self.options,
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001454 file_list)
Edward Lemurca7d8812018-07-24 17:42:45 +00001455 self.assertCommits([1, 2, 3, 5, 6])
1456 self.assertEqual(self.githash('repo_1', 5), self.gitrevparse(self.root_dir))
1457
1458 def testIgnoresAlreadyMergedCommits(self):
1459 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1460 file_list = []
1461
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001462 self.options.revision = 'refs/heads/main-with-5'
Edward Lemurca7d8812018-07-24 17:42:45 +00001463 scm.update(self.options, None, file_list)
1464 self.assertEqual(self.githash('repo_1', 12),
1465 self.gitrevparse(self.root_dir))
1466
1467 # When we try 'refs/changes/35/1235/1' on top of 'refs/heads/feature',
1468 # 'refs/changes/34/1234/1' will be an empty commit, since the changes were
1469 # already present in the tree as commit 11.
1470 # Make sure we deal with this gracefully.
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001471 scm.apply_patch_ref(
1472 self.url, 'refs/changes/35/1235/1', 'refs/heads/feature', self.options,
1473 file_list)
Edward Lemurca7d8812018-07-24 17:42:45 +00001474 self.assertCommits([1, 2, 3, 5, 6, 12])
1475 self.assertEqual(self.githash('repo_1', 12),
1476 self.gitrevparse(self.root_dir))
1477
1478 def testRecoversFromExistingCherryPick(self):
1479 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1480 file_list = []
1481
1482 self.options.revision = 'refs/changes/34/1234/1'
1483 scm.update(self.options, None, file_list)
1484 self.assertEqual(self.githash('repo_1', 5), self.gitrevparse(self.root_dir))
1485
1486 # Checkout 'refs/changes/34/1234/1' modifies the 'change' file, so trying to
1487 # cherry-pick 'refs/changes/36/1236/1' raises an error.
1488 scm._Run(['fetch', 'origin', 'refs/changes/36/1236/1'], self.options)
1489 with self.assertRaises(subprocess2.CalledProcessError) as cm:
1490 scm._Run(['cherry-pick', 'FETCH_HEAD'], self.options)
1491 self.assertEqual(cm.exception.cmd[:2], ['git', 'cherry-pick'])
1492
1493 # Try to apply 'refs/changes/35/1235/1', which doesn't have a merge
1494 # conflict.
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001495 scm.apply_patch_ref(
Josip Sokcevic7e133ff2021-07-13 17:44:53 +00001496 self.url, 'refs/changes/35/1235/1', 'refs/heads/main', self.options,
Edward Lemur4c5c8ab2019-06-07 15:58:13 +00001497 file_list)
Edward Lemurca7d8812018-07-24 17:42:45 +00001498 self.assertCommits([1, 2, 3, 5, 6])
1499 self.assertEqual(self.githash('repo_1', 5), self.gitrevparse(self.root_dir))
1500
Edward Lemurd64781e2018-07-11 23:09:55 +00001501
Joanna Wang5a7c8242022-07-01 19:09:00 +00001502class DepsChangesFakeRepo(fake_repos.FakeReposBase):
1503 def populateGit(self):
1504 self._commit_git('repo_1', {'DEPS': 'versionA', 'doesnotmatter': 'B'})
1505 self._commit_git('repo_1', {'DEPS': 'versionA', 'doesnotmatter': 'C'})
1506
1507 self._commit_git('repo_1', {'DEPS': 'versionB'})
1508 self._commit_git('repo_1', {'DEPS': 'versionA', 'doesnotmatter': 'C'})
1509 self._create_ref('repo_1', 'refs/heads/main', 4)
1510
1511
1512class CheckDiffTest(fake_repos.FakeReposTestBase):
1513 FAKE_REPOS_CLASS = DepsChangesFakeRepo
1514
1515 def setUp(self):
1516 super(CheckDiffTest, self).setUp()
1517 self.enabled = self.FAKE_REPOS.set_up_git()
1518 self.options = BaseGitWrapperTestCase.OptionsObject()
1519 self.url = self.git_base + 'repo_1'
1520 self.mirror = None
1521 mock.patch('sys.stdout', StringIO()).start()
1522 self.addCleanup(mock.patch.stopall)
1523
1524 def setUpMirror(self):
1525 self.mirror = tempfile.mkdtemp()
1526 git_cache.Mirror.SetCachePath(self.mirror)
1527 self.addCleanup(gclient_utils.rmtree, self.mirror)
1528 self.addCleanup(git_cache.Mirror.SetCachePath, None)
1529
1530 def testCheckDiff(self):
1531 """Correctly check for diffs."""
1532 scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
1533 file_list = []
1534
1535 # Make sure we don't specify a revision.
1536 self.options.revision = None
1537 scm.update(self.options, None, file_list)
1538 self.assertEqual(self.githash('repo_1', 4), self.gitrevparse(self.root_dir))
1539
1540 self.assertFalse(scm.check_diff(self.githash('repo_1', 1), files=['DEPS']))
1541 self.assertTrue(scm.check_diff(self.githash('repo_1', 1)))
1542 self.assertTrue(scm.check_diff(self.githash('repo_1', 3), files=['DEPS']))
1543
1544 self.assertFalse(
1545 scm.check_diff(self.githash('repo_1', 2),
1546 files=['DEPS', 'doesnotmatter']))
1547 self.assertFalse(scm.check_diff(self.githash('repo_1', 2)))
1548
1549
Joanna Wang1a977bd2022-06-02 21:51:17 +00001550if 'unittest.util' in __import__('sys').modules:
1551 # Show full diff in self.assertEqual.
1552 __import__('sys').modules['unittest.util']._MAX_LENGTH = 999999999
1553
msb@chromium.orge28e4982009-09-25 20:51:45 +00001554if __name__ == '__main__':
szager@chromium.orgb0a13a22014-06-18 00:52:25 +00001555 level = logging.DEBUG if '-v' in sys.argv else logging.FATAL
1556 logging.basicConfig(
1557 level=level,
1558 format='%(asctime).19s %(levelname)s %(filename)s:'
1559 '%(lineno)s %(message)s')
msb@chromium.orge28e4982009-09-25 20:51:45 +00001560 unittest.main()
1561
1562# vim: ts=2:sw=2:tw=80:et: