def runInRepos(self, dRepos, xFunction, bPrint=True, bCheckTopic=True): if bCheckTopic: lBranches = set() try: for sDirPath in dRepos.values(): if os.path.isdir(sDirPath): with changeWorkingDir(sDirPath): lBranches.add( strOrDefault(git.getCurrentBranch(), "(none)")) except (subprocess.CalledProcessError, OSError) as e: raise FatalError(e) if len(lBranches) > 1: warning("Topic is not consistent across your repositories. " "Found following topics: %s" % ", ".join(lBranches)) sInput = input("Do you wish to proceed anyway? (y/n): ") if sInput != "y": raise FatalError("Operation cancelled") lErrorRepos = [] for sRepoUrl, sDirPath in dRepos.items(): sRepoName = os.path.basename(sDirPath) try: os.makedirs(sDirPath, exist_ok=True) with changeWorkingDir(sDirPath): if bPrint: highlight("\n### %s ###" % os.path.basename(os.getcwd())) xFunction(sRepoUrl) if bPrint: success("Done") except (subprocess.CalledProcessError, FatalError, OSError) as e: error("[%s] %s" % (sRepoName, e)) lErrorRepos.append(sDirPath) return lErrorRepos
def test_repoStart_onDetached(self): self.runRepo(["start", "topic"]) for sProjectFolder in self.dProjectFolders: with changeWorkingDir(sProjectFolder): assert git.getCurrentBranch() == "topic" assert git.getGitMessages() == [INITIAL_COMMIT_MSG]
def test_repoPush_whenRemoteUpdated(self): self.runRepo(["start", "topic"]) self.createCommit() iChangeNumber = self.push()[0] self.oApiClient.put("changes/%d/message" % iChangeNumber, json={"message": "Updated!"}) self.createCommit(bAmend=True) oProcess = self.runRepo(["push"], input="n", check=False) assert oProcess.returncode != 0 lOutputLines = list(filter(bool, oProcess.stdout.splitlines())) sName = os.path.basename(next(iter(self.dProjectFolders))) lExpectedOutputLines = ["### %s ###" % sName, "WARN: You are about to overwrite unknown changes.", "Continue? (y/n): ERROR: [%s] Operation aborted" % sName] assert lOutputLines[:len(lExpectedOutputLines)] == lExpectedOutputLines for iIdx, (sProjectFolder, sProjectName) in enumerate(self.dProjectFolders.items()): dJson = self.oApiClient.get("changes/?q=%s&o=ALL_REVISIONS" % quote_plus("p:%s" % sProjectName)) assert len(dJson) == 1 assert dJson[0]["project"] == sProjectName assert len(dJson[0]["revisions"]) == 2 with changeWorkingDir(sProjectFolder): sLastCommit = git.getLastCommit() if iIdx == 0: assert dJson[0]["current_revision"] != sLastCommit else: assert dJson[0]["current_revision"] == sLastCommit
def test_repoSync_checkout(self): for sProjectFolder in self.dProjectFolders: with changeWorkingDir(sProjectFolder): lBranches = git.getAllBranches() assert len(lBranches) == 1 assert re.match(r"\(HEAD detached at .*\)", lBranches[0], re.IGNORECASE) is not None assert git.getCurrentBranch() == "" assert git.getGitMessages() == [INITIAL_COMMIT_MSG]
def test_repoRename(self): self.runRepo(["start", "topic"]) self.runRepo(["rename", "renamed_topic"]) for sProjectFolder in self.dProjectFolders: with changeWorkingDir(sProjectFolder): assert git.getCurrentBranch() == "renamed_topic" assert git.getAllBranches() == ["renamed_topic"]
def push(self): self.runRepo(["push"]) lChangeNumbers = [] for sProjectFolder, sProjectName in self.dProjectFolders.items(): with changeWorkingDir(sProjectFolder): dJson = self.oApiClient.getChangeData(gerrit.getChangeId(), sProjectName) lChangeNumbers.append(dJson["_number"]) return lChangeNumbers
def test_repoEnd_whenNotActive(self): self.runRepo(["start", "topic_1"]) self.runRepo(["start", "topic_2"]) self.runRepo(["end", "topic_1"]) for sProjectFolder in self.dProjectFolders: with changeWorkingDir(sProjectFolder): assert git.getAllBranches() == ["topic_2"] assert git.getCurrentBranch() == "topic_2"
def test_repoStart_onOtherTopic(self): self.runRepo(["start", "topic_1"]) self.createCommit() self.runRepo(["start", "topic_2"]) for sProjectFolder in self.dProjectFolders: with changeWorkingDir(sProjectFolder): assert git.getCurrentBranch() == "topic_2" assert git.getGitMessages() == ["Test commit (1)", INITIAL_COMMIT_MSG] assert os.path.isfile("test_1.txt")
def test_repoSync_detach(self): self.runRepo(["start", "topic"]) self.createCommit() self.runRepo(["sync", "-d"]) for sProjectFolder in self.dProjectFolders: with changeWorkingDir(sProjectFolder): assert git.getCurrentBranch() == "" assert git.getGitMessages() == [INITIAL_COMMIT_MSG] assert not os.path.isfile("test_1.txt")
def test_repoPull(self): self.runRepo(["start", "topic"]) self.createCommit() self.push() dCommits = self.createChange(bAmend=True) self.runRepo(["pull"]) for sProjectFolder, sProjectName in self.dProjectFolders.items(): with changeWorkingDir(sProjectFolder): assert dCommits[sProjectName] == git.getLastCommit()
def test_repoTopic_whenMultipleTopic(self): with changeWorkingDir(next(iter(self.dProjectFolders))): self.runGit(["checkout", "-b", "topic_test"]) sOutput = self.runRepo(["topic"]).stdout lOutputLines = list(filter(bool, sOutput.splitlines())) lExpectedOutputLines = ["Project1 ........ topic_test", "Project2 ............ (none)", "sub_Project3 ........ (none)"] assert lOutputLines[:len(lExpectedOutputLines)] == lExpectedOutputLines
def test_repoDownload_rebase_wrongProject(self): iChangeNumber, _ = self.repoDownloadTestSetup() oProcess = self.runRepo(["download", "foobar", "%d/1" % iChangeNumber], check=False) assert oProcess.returncode != 0 for iIdx, sProjectFolder in enumerate(self.dProjectFolders): with changeWorkingDir(sProjectFolder): assert git.getCurrentBranch() == "topic_2" assert os.path.isfile("test_2.txt") assert not os.path.isfile("test_1.txt") assert git.getGitMessages() == ["Test commit (2)", INITIAL_COMMIT_MSG]
def repoDownloadTestSetup(self): self.runRepo(["start", "topic_2"]) self.runRepo(["start", "topic_1"]) self.createCommit(sId="1") self.push() self.createCommit(sId="1", bAmend=True) iChangeNumber = self.push()[0] with changeWorkingDir(next(iter(self.dProjectFolders))): sChangeId = gerrit.getChangeId() self.runRepo(["switch", "topic_2"]) self.createCommit(sId="2") return iChangeNumber, sChangeId
def test_repoEnd_whenActive(self): self.runRepo(["start", "topic"]) self.createCommit() self.runRepo(["end", "topic"]) for sProjectFolder in self.dProjectFolders: with changeWorkingDir(sProjectFolder): lBranches = git.getAllBranches() assert len(lBranches) == 1 assert re.match(r"\(HEAD detached at .*\)", lBranches[0], re.IGNORECASE) is not None assert git.getCurrentBranch() == "" assert git.getGitMessages() == [INITIAL_COMMIT_MSG] assert not os.path.isfile("test_1.txt")
def test_repoRebase_simple(self): self.runRepo(["start", "topic_2"]) self.runRepo(["start", "topic_1"]) self.createCommit(sId="1") self.runRepo(["switch", "topic_2"]) self.createCommit(sId="2") self.runRepo(["rebase", "topic_1"]) for iIdx, sProjectFolder in enumerate(self.dProjectFolders): with changeWorkingDir(sProjectFolder): assert git.getCurrentBranch() == "topic_2" assert os.path.isfile("test_1.txt") assert os.path.isfile("test_2.txt") assert git.getGitMessages() == ["Test commit (2)", "Test commit (1)", INITIAL_COMMIT_MSG]
def test_repoPull_whenAlreadyUpToDate(self): self.runRepo(["start", "topic"]) dCommits = self.createCommit() self.runRepo(["push"]) sOutput = self.runRepo(["pull"], capture_output=True, encoding="utf-8").stdout lOutputLines = list(filter(bool, sOutput.splitlines())) lExpectedOutputLines = [] for sProjectFolder in self.dProjectFolders: lExpectedOutputLines += ["### %s ###" % os.path.basename(sProjectFolder), "Already up-to-date.", "Done"] assert lOutputLines[:len(lExpectedOutputLines)] == lExpectedOutputLines for sProjectFolder, sProjectName in self.dProjectFolders.items(): with changeWorkingDir(sProjectFolder): assert dCommits[sProjectName] == git.getLastCommit()
def test_getChange(self): self.createCommit() self.push() for sProjectFolder, sProjectName in self.dProjectFolders.items(): with changeWorkingDir(sProjectFolder): sChangeId = gerrit.getChangeId() dChange = self.oApiClient.getChangeData( sChangeId, sProjectName) assert dChange is not None assert dChange["id"] == "%s~master~%s" % (quote( sProjectName, safe=""), sChangeId) assert dChange["project"] == sProjectName assert dChange["branch"] == "master" assert dChange["change_id"] == sChangeId assert dChange["status"] == "NEW"
def repoDownloadTestAssertResult(self, iPatch): for iIdx, sProjectFolder in enumerate(self.dProjectFolders): with changeWorkingDir(sProjectFolder): assert git.getCurrentBranch() == "topic_2" assert os.path.isfile("test_2.txt") if iIdx == 0: assert os.path.isfile("test_1.txt") if iPatch == 1: assert git.getGitMessages() == ["Test commit (2)", "Test commit (1)", INITIAL_COMMIT_MSG] elif iPatch == 2: assert git.getGitMessages() == ["Test commit (2)", "Amended test commit (1)", INITIAL_COMMIT_MSG] else: pytest.fail("iPatch parameter must be 1 or 2, received %d" % iPatch) else: assert not os.path.isfile("test_1.txt") assert git.getGitMessages() == ["Test commit (2)", INITIAL_COMMIT_MSG]
def test_repoDownload_detach(self): iChangeNumber, _ = self.repoDownloadTestSetup() self.runRepo(["download", "-d", next(iter(self.dProjectFolders.values())), "%d/1" % iChangeNumber]) for iIdx, sProjectFolder in enumerate(self.dProjectFolders): with changeWorkingDir(sProjectFolder): if iIdx == 0: assert git.getCurrentBranch() == "" assert os.path.isfile("test_1.txt") assert not os.path.isfile("test_2.txt") assert git.getGitMessages() == ["Test commit (1)", INITIAL_COMMIT_MSG] else: assert git.getCurrentBranch() == "topic_2" assert not os.path.isfile("test_1.txt") assert os.path.isfile("test_2.txt") assert git.getGitMessages() == ["Test commit (2)", INITIAL_COMMIT_MSG]
def test_repoRebase_complex(self): self.runRepo(["start", "topic_1"]) self.createCommit(sId="1") self.runRepo(["start", "topic_2"]) self.createCommit(sId="2") self.runRepo(["switch", "topic_1"]) self.createCommit(sId="1", bAmend=True) self.runRepo(["switch", "topic_2"]) self.runRepo(["rebase", "topic_1"]) for iIdx, sProjectFolder in enumerate(self.dProjectFolders): with changeWorkingDir(sProjectFolder): assert git.getCurrentBranch() == "topic_2" sFileName = "test_1.txt" assert os.path.isfile(sFileName) with open(sFileName, "r") as oFile: assert oFile.read() == "This is an amended test (1)." assert os.path.isfile("test_2.txt") assert git.getGitMessages() == ["Test commit (2)", "Amended test commit (1)", INITIAL_COMMIT_MSG]
def test_repoPull_whenConflict(self): self.runRepo(["start", "topic"]) self.createCommit() self.runRepo(["push"]) self.createChange(bAmend=True) dCommits = self.createCommit(bAmend=True) oProcess = self.runRepo(["pull"], capture_output=True, encoding="utf-8", check=False) assert oProcess.returncode != 0 lOutputLines = list(filter(bool, oProcess.stdout.splitlines())) lExpectedOutputLines = [] for sProjectFolder in self.dProjectFolders: sName = os.path.basename(sProjectFolder) lExpectedOutputLines += ["### %s ###" % sName, "ERROR: [%s] You have local commits unknown to Gerrit" % sName] assert lOutputLines[:len(lExpectedOutputLines)] == lExpectedOutputLines for sProjectFolder, sProjectName in self.dProjectFolders.items(): with changeWorkingDir(sProjectFolder): assert dCommits[sProjectName] == git.getLastCommit()
def test_repoPush_whenInconsistentTopics(self): self.runRepo(["start", "topic_1"]) self.createCommit() with changeWorkingDir(next(iter(self.dProjectFolders))): self.runGit(["checkout", "-b", "topic_2"]) oProcess = self.runRepo(["push"], input="n", check=False) assert oProcess.returncode != 0 lOutputLines = list(filter(bool, oProcess.stdout.splitlines())) lExpectedOutputLines1 = ["WARN: Topic is not consistent across your repositories. " "Found following topics: topic_1, topic_2", "Do you wish to proceed anyway? (y/n): ", "ERROR: Operation cancelled"] lExpectedOutputLines2 = ["WARN: Topic is not consistent across your repositories. " "Found following topics: topic_2, topic_1", "Do you wish to proceed anyway? (y/n): ", "ERROR: Operation cancelled"] assert lOutputLines[:len(lExpectedOutputLines1)] == lExpectedOutputLines1 \ or lOutputLines[:len(lExpectedOutputLines2)] == lExpectedOutputLines2 for sProjectFolder, sProjectName in self.dProjectFolders.items(): dJson = self.oApiClient.get("changes/?q=%s" % quote_plus("p:%s" % sProjectName)) assert len(dJson) == 0
def createCommit(self, sId="1", bAmend=False): dCommits = {} for sProjectFolder, sProjectName in self.dProjectFolders.items(): with changeWorkingDir(sProjectFolder): sTestFileName = "test_%s.txt" % sId with open(sTestFileName, "w") as oFile: if bAmend: oFile.write("This is an amended test (%s)." % sId) else: oFile.write("This is a test (%s)." % sId) self.runGit(["add", sTestFileName]) if bAmend: sLastCommitMsg = self.runGit( ["log", "-1", "--format=format:%B"]).stdout sNewCommitMsg = "\n".join( ["Amended test commit (%s)" % sId] + sLastCommitMsg.splitlines()[1:]) self.runGit(["commit", "--amend", "-m", sNewCommitMsg]) else: self.runGit(["commit", "-m", "Test commit (%s)" % sId]) dCommits[sProjectName] = git.getLastCommit() return dCommits
def createChange(self, sId="1", bAmend=False): dCommits = {} for sProjectFolder, sProjectName in self.dProjectFolders.items(): with changeWorkingDir(sProjectFolder): if bAmend: sChangeId = gerrit.getChangeId() dJson = {"message": "Amended test commit (%s)" % sId} self.oApiClient.put("changes/%s~master~%s/message" % (quote_plus(sProjectName), sChangeId), json=dJson) else: dJson = { "project": sProjectName, "branch": "master", "subject": "Test commit (%s)" % sId } sChangeId = self.oApiClient.post("changes/", json=dJson)["change_id"] dJson = self.oApiClient.getChangeData( sChangeId, sProjectName, lAdditionalData=["CURRENT_REVISION"]) dCommits[sProjectName] = dJson["current_revision"] return dCommits