From 8689d95766a8c8b9cdeefd46c997e0f5a4e3aec5 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Wed, 19 Aug 2020 14:54:35 -0400 Subject: [PATCH 1/4] Add ability to specify a specific branch for listing --- mepo.d/cmdline/branch_parser.py | 10 ++++++++-- mepo.d/command/branch/brlist/brlist.py | 13 +++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/mepo.d/cmdline/branch_parser.py b/mepo.d/cmdline/branch_parser.py index 947a94a..8ff56f2 100644 --- a/mepo.d/cmdline/branch_parser.py +++ b/mepo.d/cmdline/branch_parser.py @@ -14,11 +14,17 @@ def __init__(self, branch): def __list(self): brlist = self.branch_subparsers.add_parser( 'list', - description = 'List local branches of all components') + description = 'List local branches.' + 'If no component is specified, runs over all components') brlist.add_argument( '-a', '--all', action = 'store_true', - help = 'list all (local+remote) branches of all components') + help = 'list all (local+remote) branches') + brlist.add_argument( + 'comp_name', + metavar = 'comp-name', + nargs = '*', + help = 'Component to list branches in') def __create(self): create = self.branch_subparsers.add_parser( diff --git a/mepo.d/command/branch/brlist/brlist.py b/mepo.d/command/branch/brlist/brlist.py index d5f7dae..7174024 100644 --- a/mepo.d/command/branch/brlist/brlist.py +++ b/mepo.d/command/branch/brlist/brlist.py @@ -1,13 +1,22 @@ from state.state import MepoState +from utilities import verify from repository.git import GitRepository def run(args): allcomps = MepoState.read_state() - max_namelen = len(max([x.name for x in allcomps], key=len)) + comps2list = _get_comps_to_list(args.comp_name, allcomps) + max_namelen = len(max([x.name for x in comps2list], key=len)) FMT = '{:<%s.%ss} | {: Date: Wed, 19 Aug 2020 14:58:44 -0400 Subject: [PATCH 2/4] Add zenodo file --- .zenodo.json | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .zenodo.json diff --git a/.zenodo.json b/.zenodo.json new file mode 100644 index 0000000..e3d01d8 --- /dev/null +++ b/.zenodo.json @@ -0,0 +1,40 @@ +{ + "license": "other-open", + "upload_type": "software", + "creators": [ + { + "name": "Thompson, Matthew", + "affiliation": "GMAO SSAI", + "orcid": "0000-0001-6222-6863" + }, + { + "name": "Chakraborty, Purnendu" + }, + { + "name": "Clune, Tom", + "affiliation": "NASA", + "orcid": "0000-0003-3320-0204" + } + ], + "contributors": [ + { + "name": "Thompson, Matthew", + "affiliation": "GMAO SSAI", + "orcid": "0000-0001-6222-6863", + "type": "ContactPerson" + }, + { + "name": "Clune, Tom", + "affiliation": "NASA", + "orcid": "0000-0003-3320-0204", + "type": "ProjectLeader" + } + ], + "keywords": [ + "git", + "repository", + "python", + "yaml" + ], + "access_right": "open" +} From 21732795f5881162e0d17b900492df17e7c65b43 Mon Sep 17 00:00:00 2001 From: Matthew Thompson Date: Wed, 19 Aug 2020 15:54:56 -0400 Subject: [PATCH 3/4] Add tag commands --- mepo.d/cmdline/parser.py | 22 ++++++++-- mepo.d/cmdline/stash_parser.py | 10 ++--- mepo.d/cmdline/tag_parser.py | 56 ++++++++++++++++++++++++++ mepo.d/command/push/push.py | 2 +- mepo.d/command/tag/create/create.py | 62 +++++++++++++++++++++++++++++ mepo.d/command/tag/delete/delete.py | 12 ++++++ mepo.d/command/tag/tag.py | 15 +++++++ mepo.d/command/tag/tglist/tglist.py | 22 ++++++++++ mepo.d/repository/git.py | 31 ++++++++++++++- 9 files changed, 220 insertions(+), 12 deletions(-) create mode 100644 mepo.d/cmdline/tag_parser.py create mode 100644 mepo.d/command/tag/create/create.py create mode 100644 mepo.d/command/tag/delete/delete.py create mode 100644 mepo.d/command/tag/tag.py create mode 100644 mepo.d/command/tag/tglist/tglist.py diff --git a/mepo.d/cmdline/parser.py b/mepo.d/cmdline/parser.py index f9614ca..0db5d8f 100644 --- a/mepo.d/cmdline/parser.py +++ b/mepo.d/cmdline/parser.py @@ -2,6 +2,7 @@ from cmdline.branch_parser import MepoBranchArgParser from cmdline.stash_parser import MepoStashArgParser +from cmdline.tag_parser import MepoTagArgParser class MepoArgParser(object): @@ -27,6 +28,7 @@ def parse(self): self.__checkout() self.__checkout_if_exists() self.__branch() + self.__tag() self.__stash() self.__develop() self.__pull() @@ -137,15 +139,23 @@ def __fetch_all(self): fetch_all.add_argument('--tags','-t', action = 'store_true', help = 'Fetch tags.') def __branch(self): - branch = self.subparsers.add_parser('branch') + branch = self.subparsers.add_parser( + 'branch', + description = "Runs branch commands.") MepoBranchArgParser(branch) def __stash(self): stash = self.subparsers.add_parser( - 'stash', - description = "Runs stash commands.") + 'stash', + description = "Runs stash commands.") MepoStashArgParser(stash) + def __tag(self): + tag = self.subparsers.add_parser( + 'tag', + description = "Runs tag commands.") + MepoTagArgParser(tag) + def __develop(self): develop = self.subparsers.add_parser( 'develop', @@ -216,7 +226,11 @@ def __commit(self): def __push(self): push = self.subparsers.add_parser( 'push', - description = 'Push local commits to remote') + description = 'Push local commits or tags to remote') + push.add_argument( + '--tags', + action = 'store_true', + help = 'push tags') push.add_argument( 'comp_name', metavar = 'comp-name', diff --git a/mepo.d/cmdline/stash_parser.py b/mepo.d/cmdline/stash_parser.py index eac71ac..0d34920 100644 --- a/mepo.d/cmdline/stash_parser.py +++ b/mepo.d/cmdline/stash_parser.py @@ -18,11 +18,11 @@ def __push(self): 'push', description = 'Push (create) stash in component ') stpush.add_argument( - '-m', '--message', - type=str, - metavar = 'message', - default=None, - help = 'Message for the stash') + '-m', '--message', + type=str, + metavar = 'message', + default=None, + help = 'Message for the stash') stpush.add_argument( 'comp_name', metavar = 'comp-name', diff --git a/mepo.d/cmdline/tag_parser.py b/mepo.d/cmdline/tag_parser.py new file mode 100644 index 0000000..2d11de2 --- /dev/null +++ b/mepo.d/cmdline/tag_parser.py @@ -0,0 +1,56 @@ +import argparse + +class MepoTagArgParser(object): + + def __init__(self, tag): + self.tag = tag.add_subparsers() + self.tag.title = 'mepo tag sub-commands' + self.tag.dest = 'mepo_tag_cmd' + self.tag.required = True + self.__list() + self.__create() + self.__delete() + + def __list(self): + tglist = self.tag.add_parser( + 'list', + description = 'List tags.' + 'If no component is specified, runs over all components') + tglist.add_argument( + 'comp_name', + metavar = 'comp-name', + nargs = '*', + help = 'Component to list tags in') + + def __create(self): + create = self.tag.add_parser( + 'create', + description = 'Create tag in component ') + create.add_argument('tag_name', metavar = 'tag-name') + create.add_argument( + '-a', '--annotate', + action = 'store_true', + help = "Make an annotated tag") + create.add_argument( + '-m', '--message', + type=str, + metavar = 'message', + default = None, + help = "Message for the tag" + ) + create.add_argument( + 'comp_name', + metavar = 'comp-name', + nargs = '+', + help = 'Component to create tags in') + + def __delete(self): + delete = self.tag.add_parser( + 'delete', + description = 'Delete tag in component ') + delete.add_argument('tag_name', metavar = 'tag-name') + delete.add_argument( + 'comp_name', + metavar = 'comp-name', + nargs = '+', + help = 'Component to delete tags in') diff --git a/mepo.d/command/push/push.py b/mepo.d/command/push/push.py index adcf2ae..1e236b4 100644 --- a/mepo.d/command/push/push.py +++ b/mepo.d/command/push/push.py @@ -8,6 +8,6 @@ def run(args): comps2push = [x for x in allcomps if x.name in args.comp_name] for comp in comps2push: git = GitRepository(comp.remote, comp.local) - output = git.push() + output = git.push(args.tags) print('----------\nPushed: {}\n----------'.format(comp.name)) print(output) diff --git a/mepo.d/command/tag/create/create.py b/mepo.d/command/tag/create/create.py new file mode 100644 index 0000000..2219eff --- /dev/null +++ b/mepo.d/command/tag/create/create.py @@ -0,0 +1,62 @@ +from state.state import MepoState +from utilities import verify +from repository.git import GitRepository + +# Popping up an EDITOR is based on https://stackoverflow.com/a/39989442 +import os, tempfile, subprocess + +def run(args): + allcomps = MepoState.read_state() + verify.valid_components(args.comp_name, allcomps) + comps2crttg = [x for x in allcomps if x.name in args.comp_name] + + tf_file = None + + if args.annotate: + create_annotated_tag = True + elif args.message: + create_annotated_tag = True + else: + create_annotated_tag = False + + if create_annotated_tag: + # Pop up an editor if a message is not provided + if not args.message: + EDITOR = git_var('GIT_EDITOR') + initial_message = b"" # set up the file + + # Use delete=False to keep the file around as we send the file name to git commit -F + tf = tempfile.NamedTemporaryFile(delete=False) + tf_file = tf.name + tf.write(initial_message) + tf.flush() + subprocess.call([EDITOR, tf.name]) + + for comp in comps2crttg: + git = GitRepository(comp.remote, comp.local) + git.create_tag(args.tag_name,create_annotated_tag,args.message,tf_file) + print('+ {}: {}'.format(comp.name, args.tag_name)) + + if create_annotated_tag: + # Now close and by-hand delete the temp file + if not args.message: + tf.close() + os.unlink(tf.name) + +def git_var(what): + ''' + return GIT_EDITOR or GIT_PAGER, for instance + + Found at https://stackoverflow.com/a/44174750/1876449 + + ''' + proc = subprocess.Popen(['git', 'var', what], shell=False, + stdout=subprocess.PIPE) + output = proc.stdout.read() + status = proc.wait() + if status != 0: + raise Exception("git_var failed with [%]" % what) + output = output.rstrip(b'\n') + output = output.decode('utf8', errors='ignore') # or similar for py3k + return output + diff --git a/mepo.d/command/tag/delete/delete.py b/mepo.d/command/tag/delete/delete.py new file mode 100644 index 0000000..ff7b92b --- /dev/null +++ b/mepo.d/command/tag/delete/delete.py @@ -0,0 +1,12 @@ +from state.state import MepoState +from utilities import verify +from repository.git import GitRepository + +def run(args): + allcomps = MepoState.read_state() + verify.valid_components(args.comp_name, allcomps) + comps2deltg = [x for x in allcomps if x.name in args.comp_name] + for comp in comps2deltg: + git = GitRepository(comp.remote, comp.local) + git.delete_tag(args.tag_name) + print('- {}: {}'.format(comp.name, args.tag_name)) diff --git a/mepo.d/command/tag/tag.py b/mepo.d/command/tag/tag.py new file mode 100644 index 0000000..7441636 --- /dev/null +++ b/mepo.d/command/tag/tag.py @@ -0,0 +1,15 @@ +import subprocess as sp + +from state.state import MepoState + +from command.tag.tglist import tglist +from command.tag.create import create +from command.tag.delete import delete + +def run(args): + d = { + 'list': tglist, + 'create': create, + 'delete': delete + } + d[args.mepo_tag_cmd].run(args) diff --git a/mepo.d/command/tag/tglist/tglist.py b/mepo.d/command/tag/tglist/tglist.py new file mode 100644 index 0000000..c04c325 --- /dev/null +++ b/mepo.d/command/tag/tglist/tglist.py @@ -0,0 +1,22 @@ +from state.state import MepoState +from utilities import verify +from repository.git import GitRepository + +def run(args): + allcomps = MepoState.read_state() + comps2list = _get_comps_to_list(args.comp_name, allcomps) + max_namelen = len(max([x.name for x in comps2list], key=len)) + FMT = '{:<%s.%ss} | {: Date: Wed, 19 Aug 2020 16:32:26 -0400 Subject: [PATCH 4/4] remove unneeded command --- mepo.d/repository/git.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mepo.d/repository/git.py b/mepo.d/repository/git.py index 68f3728..92fe605 100644 --- a/mepo.d/repository/git.py +++ b/mepo.d/repository/git.py @@ -104,10 +104,6 @@ def create_branch(self, branch_name): cmd = self.__git + ' branch {}'.format(branch_name) shellcmd.run(cmd.split()) - def create_tags(self, tag_name): - cmd = self.__git + ' tag {}'.format(branch_name) - shellcmd.run(cmd.split()) - def create_tag(self, tag_name, annotate, message, tf_file=None): if annotate: if tf_file: