From b2176373255e552e3a432f402aefb03a4d9e2711 Mon Sep 17 00:00:00 2001 From: "Jason M. Gates" Date: Thu, 26 Oct 2017 12:22:58 -0600 Subject: [PATCH] gitdist: Add Default Development Branch... (#235) Here's an initial implementation that allows a user to add default development branches to the .gitdist file in the form . master otherRepo develop thirdRepo master If those default development branches aren't specified, master is assumed. The user can then pass _DEFAULT_BRANCH_ to any command that accepts a reference and gitdist should replace _DEFAULT_BRANCH_ with the appropriate branch from the .gitdist file. The documentation for this feature can be accessed with --dist-help=default-branch. --- test/python_utils/gitdist_UnitTests.py | 73 +++++++++++++++++++- tribits/python_utils/gitdist.py | 95 +++++++++++++++++++++++--- 2 files changed, 157 insertions(+), 11 deletions(-) diff --git a/test/python_utils/gitdist_UnitTests.py b/test/python_utils/gitdist_UnitTests.py index e4d55357f..71aec9cb6 100644 --- a/test/python_utils/gitdist_UnitTests.py +++ b/test/python_utils/gitdist_UnitTests.py @@ -676,7 +676,7 @@ def test_dist_help_all_help(self): # Tet that --dist-help --help prints nice error message def test_dist_help_help(self): cmndOut = getCmndOutput(gitdistPath+" --dist-help --help") - cmndOut_expected = "gitdist: error: option --dist-help: invalid choice: '--help' (choose from '', 'overview', 'repo-selection-and-setup', 'dist-repo-status', 'repo-versions', 'aliases', 'usage-tips', 'script-dependencies', 'all')\n" + cmndOut_expected = "gitdist: error: option --dist-help: invalid choice: '--help' (choose from '', 'overview', 'repo-selection-and-setup', 'dist-repo-status', 'repo-versions', 'aliases', 'usage-tips', 'script-dependencies', 'default-branch', 'all')\n" self.assertEqual(s(cmndOut), s(cmndOut_expected)) @@ -684,7 +684,7 @@ def test_dist_help_help(self): def test_dist_help_invalid_pick_help(self): cmndOut = getCmndOutput(gitdistPath+" --dist-help=invalid-pick --help") assertContainsGitdistHelpHeader(self, cmndOut) - errorToFind = "gitdist: error: option --dist-help: invalid choice: 'invalid-pick' (choose from '', 'overview', 'repo-selection-and-setup', 'dist-repo-status', 'repo-versions', 'aliases', 'usage-tips', 'script-dependencies', 'all')" + errorToFind = "gitdist: error: option --dist-help: invalid choice: 'invalid-pick' (choose from '', 'overview', 'repo-selection-and-setup', 'dist-repo-status', 'repo-versions', 'aliases', 'usage-tips', 'script-dependencies', 'default-branch', 'all')" self.assertEqual( GeneralScriptSupport.extractLinesMatchingSubstr(cmndOut,errorToFind), errorToFind+"\n") @@ -1400,5 +1400,74 @@ def test_dist_repo_status_extra_args_fail(self): os.chdir(testBaseDir) + def test_dist_default_branch(self): + os.chdir(testBaseDir) + try: + + # Create a mock git meta-project + + testDir = createAndMoveIntoTestDir("gitdist_default_branch") + os.mkdir("ExtraRepo1") + os.makedirs("Path/To/ExtraRepo2") + os.mkdir("ExtraRepo3") + + # Make sure .gitdist.default is found and read correctly + open(".gitdist.default", "w").write( + ". master\n" \ + "ExtraRepo1 develop\n" \ + "Path/To/ExtraRepo2 app-devel\n" \ + "MissingExtraRepo\n" \ + "ExtraRepo3\n" + ) + cmndOut = GeneralScriptSupport.getCmndOutput( + gitdistPathMock+" checkout _DEFAULT_BRANCH_", workingDir=testDir) + cmndOut_expected = \ + "\n*** Base Git Repo: MockProjectDir\n" \ + "['mockgit', 'checkout', 'master']\n\n" \ + "*** Git Repo: ExtraRepo1\n" \ + "['mockgit', 'checkout', 'develop']\n\n" \ + "*** Git Repo: Path/To/ExtraRepo2\n" \ + "['mockgit', 'checkout', 'app-devel']\n\n" \ + "*** Git Repo: ExtraRepo3\n" \ + "['mockgit', 'checkout', 'master']\n\n" + self.assertEqual(s(cmndOut), s(cmndOut_expected)) + # NOTE: Above ensures that all of the paths are read correctly and that + # missing paths (MissingExtraRepo) are ignored. + + # Make sure that .gitdist overrides .gitdist.default + open(".gitdist", "w").write( + ". develop\n" \ + "ExtraRepo1 develop\n" \ + "ExtraRepo3 develop\n" + ) + cmndOut = GeneralScriptSupport.getCmndOutput( + gitdistPathMock+" checkout _DEFAULT_BRANCH_", workingDir=testDir) + cmndOut_expected = \ + "\n*** Base Git Repo: MockProjectDir\n" \ + "['mockgit', 'checkout', 'develop']\n\n" \ + "*** Git Repo: ExtraRepo1\n" \ + "['mockgit', 'checkout', 'develop']\n\n" \ + "*** Git Repo: ExtraRepo3\n" \ + "['mockgit', 'checkout', 'develop']\n\n" + self.assertEqual(s(cmndOut), s(cmndOut_expected)) + + # Make sure that --dist-repos overrides all files + cmndOut = GeneralScriptSupport.getCmndOutput( + gitdistPathMock+" --dist-repos=.,ExtraRepo1,Path/To/ExtraRepo2 "+ \ + "checkout _DEFAULT_BRANCH_", + workingDir=testDir) + cmndOut_expected = \ + "\n*** Base Git Repo: MockProjectDir\n" \ + "['mockgit', 'checkout', 'master']\n\n" \ + "*** Git Repo: ExtraRepo1\n" \ + "['mockgit', 'checkout', 'master']\n\n" \ + "*** Git Repo: Path/To/ExtraRepo2\n" \ + "['mockgit', 'checkout', 'master']\n\n" + self.assertEqual(s(cmndOut), s(cmndOut_expected)) + + finally: + os.chdir(testBaseDir) + + if __name__ == '__main__': unittest.main() diff --git a/tribits/python_utils/gitdist.py b/tribits/python_utils/gitdist.py index 6d2a36175..db896562d 100755 --- a/tribits/python_utils/gitdist.py +++ b/tribits/python_utils/gitdist.py @@ -50,7 +50,8 @@ def s(x): 'repo-versions', 'aliases', 'usage-tips', - 'script-dependencies' + 'script-dependencies', + 'default-branch' ] @@ -613,6 +614,47 @@ def getHelpTopicsStr(): helpTopicsDict.update( { 'script-dependencies' : scriptDependenciesHelp } ) +defaultBranchHelp = r""" +DEFAULT BRANCH SPECIFICATION: + +When using any git command that accepts a reference (a SHA1, or branch or tag +name), it is possible to use _DEFAULT_BRANCH_ instead. For instance, + + gitdist checkout _DEFAULT_BRANCH_ + +will check out the default development branch in each repository being managed +by gitdist. You can specify the default branch for each repository in your +.gitdist[.default] file. For instance, if your .gitdist file contains + + . master + extraRepo1 develop + extraRepo2 app-devel + +then the command above would check out master in the base repo, develop in +extraRepo1, and app-devel in extraRepo2. This makes it convenient when working +with multiple repositories that have different names for their main development +branches. For instance, you can + + gitdist checkout _DEFAULT_BRANCH_ + gitdist pull + gitdist checkout -b newFeatureBranch + # do some work + gitdist fetch + gitdist merge _DEFAULT_BRANCH_ + # do some more work + gitdist checkout _DEFAULT_BRANCH_ + gitdist pull + gitdist merge newFeatureBranch + +and not worry about this newFeatureBranch being off of master in the root repo, +off of develop in extraRepo1, and off of app-devel in extraRepo2. + +If no branch name is specified for any given repository in the +.gitdist[.default] file, then master is assumed. +""" +helpTopicsDict.update( { 'default-branch' : defaultBranchHelp } ) + + # # Functions to help Format an ASCII table # @@ -819,6 +861,22 @@ def addColorToErrorMsg(useColor, strIn): return strIn +# Get the paths to all the repos gitdist will work on, along with any optional +# default branches. +def parseGitdistFile(gitdistfile): + reposFullList = [] + defaultBranchDict = {} + with open(gitdistfile, 'r') as file: + for line in file: + entries = line.split() + reposFullList.append(entries[0]) + if len(entries) > 1: + defaultBranchDict[entries[0]] = entries[1] + else: + defaultBranchDict[entries[0]] = "master" + return (reposFullList, defaultBranchDict) + + # Get the commandline options def getCommandlineOps(): @@ -1075,6 +1133,9 @@ def getCommandlineOps(): if options.repos: reposFullList = options.repos.split(",") + defaultBranchDict = {} + for repo in reposFullList: + defaultBranchDict[repo] = "master" else: if os.path.exists(".gitdist"): gitdistfile = ".gitdist" @@ -1083,9 +1144,10 @@ def getCommandlineOps(): else: gitdistfile = None if gitdistfile: - reposFullList = open(gitdistfile, 'r').read().split() + (reposFullList, defaultBranchDict) = parseGitdistFile(gitdistfile) else: reposFullList = ["."] # The default is the base repo + defaultBranchDict = {".": "master"} # Get list of not extra repos @@ -1098,7 +1160,7 @@ def getCommandlineOps(): # G) Return # - return (options, nativeCmnd, otherArgs, reposFullList, + return (options, nativeCmnd, otherArgs, reposFullList, defaultBranchDict, notReposFullList) @@ -1205,13 +1267,28 @@ def replaceRepoVersionInCmndLineArgs(cmndLineArgsArray, repoDirName, \ return cmndLineArgsArrayRepo +# Replace _DEFAULT_BRANCH_ in the command line arguments with the appropriate +# default branch name. +def replaceDefaultBranchInCmndLineArgs(cmndLineArgsArray, repoDirName, \ + defaultBranchDict \ + ): + cmndLineArgsArrayDefaultBranch = [] + for cmndLineArg in cmndLineArgsArray: + newCmndLineArg = re.sub("_DEFAULT_BRANCH_", \ + defaultBranchDict[repoDirName], cmndLineArg) + cmndLineArgsArrayDefaultBranch.append(newCmndLineArg) + return cmndLineArgsArrayDefaultBranch + + # Generate the command line arguments def runRepoCmnd(options, cmndLineArgsArray, repoDirName, baseDir, \ - repoVersionDict, repoVersionDict2 \ + repoVersionDict, repoVersionDict2, defaultBranchDict \ ): - cmndLineArgsArryRepo = replaceRepoVersionInCmndLineArgs(cmndLineArgsArray, \ + cmndLineArgsArrayRepo = replaceRepoVersionInCmndLineArgs(cmndLineArgsArray, \ repoDirName, repoVersionDict, repoVersionDict2) - egCmndArray = [ options.useGit ] + cmndLineArgsArryRepo + cmndLineArgsArrayDefaultBranch = replaceDefaultBranchInCmndLineArgs( \ + cmndLineArgsArrayRepo, repoDirName, defaultBranchDict) + egCmndArray = [ options.useGit ] + cmndLineArgsArrayDefaultBranch runCmnd(options, egCmndArray) @@ -1423,8 +1500,8 @@ def getRepoName(repoDir, baseRepoName): if __name__ == '__main__': - (options, nativeCmnd, otherArgs, reposFullList, notReposList) = \ - getCommandlineOps() + (options, nativeCmnd, otherArgs, reposFullList, defaultBranchDict, \ + notReposList) = getCommandlineOps() if nativeCmnd == "dist-repo-status": distRepoStatus = True @@ -1496,7 +1573,7 @@ def getRepoName(repoDir, baseRepoName): print("*** Tracking branch for git repo '" + repoName + "' = '" + repoStats.trackingBranch + "'") runRepoCmnd(options, cmndLineArgsArray, repo, baseDir, \ - repoVersionDict, repoVersionDict2) + repoVersionDict, repoVersionDict2, defaultBranchDict) if options.debug: print("*** Changing to directory " + baseDir)