[Asterisk-code-review] digium git/version parser: Update branch and tag functionality (repotools[master])
Kevin Harwell
asteriskteam at digium.com
Mon Feb 19 16:42:04 CST 2018
Kevin Harwell has uploaded this change for review. ( https://gerrit.asterisk.org/8290
Change subject: digium_git/version_parser: Update branch and tag functionality
......................................................................
digium_git/version_parser: Update branch and tag functionality
Updated the utility and other support methods to the following modules:
digium_git -
* Made it so the local_path expands the '~' for the current user.
* Added ability to add/push multiple branches
* Add abitlity to delete local and remote branches
* Added a find_last_tag function that finds the last tag created tag before a
given version.
version_parser -
* Added a branch_name method that returns a branch name from the version.
* Added two functions to check if the version represents either a first pre-
release, or a first branch release version.
Change-Id: I5a7f44e75ae3d867f9795b7fb0ea5bff526b5429
---
M digium_git.py
M version_parser.py
2 files changed, 173 insertions(+), 22 deletions(-)
git pull ssh://gerrit.asterisk.org:29418/repotools refs/changes/90/8290/1
diff --git a/digium_git.py b/digium_git.py
index 3536522..e28642f 100644
--- a/digium_git.py
+++ b/digium_git.py
@@ -17,6 +17,7 @@
from progressbar import ProgressBar
from digium_commits import DigiumCommitMessageParser
from git import Repo, RemoteProgress
+from version_parser import AsteriskVersion
LOGGER = logging.getLogger(__name__)
@@ -166,8 +167,11 @@
self.show_progress = show_progress
self.current_branch = None
+ self.updated_branches = [] # Local new or modified branches
+ self.deleted_branches = [] # Locally deleted branches
progress = None
+ local_path = os.path.expanduser(local_path)
if os.path.isdir(local_path):
self.repo = Repo(local_path)
origin = self.repo.remotes.origin
@@ -183,7 +187,6 @@
origin.fetch(progress=self.progress)
origin.fetch(progress=self.progress)
-
@property
def progress(self):
@@ -208,17 +211,6 @@
pass
return False
- def _push_branch(self):
- """Push the currently checked out local branch to the remote"""
-
- assert self.current_branch is not None
-
- LOGGER.debug("Pushing branch {0} to remote".format(self.current_branch))
- self.repo.remotes.origin.push(refspec='refs/heads/{0}:refs/heads/{1}'.format(
- self.current_branch, self.current_branch), progress=self.progress)
- self._set_tracking(self.repo.heads[self.current_branch])
-
-
def branch_exists(self, name):
"""Determine if a branch exists
@@ -232,13 +224,62 @@
return name in self.repo.heads
+ def _push_updated_branches(self):
+ """Push new or updated branches to the remote repository."""
+
+ if not self.updated_branches:
+ return
+
+ for b in self.updated_branches:
+ LOGGER.debug("Pushing branch '{0}' to remote".format(b))
+
+ self.repo.remotes.origin.push(
+ refspec='refs/heads/{0}:refs/heads/{1}'.format(
+ b, b), progress=self.progress)
+
+ self._set_tracking(self.repo.heads[b])
+
+ self.updated_branches = []
+
+ def _push_deleted_branches(self):
+ """Delete a branch(es) from the remote repository."""
+
+ if not self.deleted_branches:
+ return
+
+ for b in self.deleted_branches:
+ try:
+ LOGGER.debug("Pushing/Deleting remote branch '{0}'".format(b))
+ self.repo.remotes.origin.push(':{0}'.format(b), self.progress)
+ except:
+ LOGGER.debug("Remote branch '{0}' does not exist. "
+ "Nothing to delete".format(b))
+
+ self.deleted_branches = []
+
+ def delete_branch(self, branch):
+ """Delete a branch from the local repository.
+
+ Note: The branch to delete cannot be currently checked out.
+
+ Keyword Arguments:
+ branch - The branch to remove
+ """
+
+ self.deleted_branches.append(branch)
+ self.updated_branches.remove(branch)
+ try:
+ LOGGER.debug("Deleting local branch '{0}'".format(branch))
+ self.repo.delete_head(branch)
+ except:
+ LOGGER.debug("Local branch '{0}' does not exist. "
+ "Nothing to delete".format(branch))
def _push_tags(self):
"""Push any locally created tags to the remote"""
LOGGER.debug("Pushing any locally created tag(s) to remote")
self.repo.remotes.origin.push(progress=self.progress, tags=True)
-
def tag_exists(self, name):
"""Determine if a tag exists locally
@@ -253,6 +294,58 @@
return name in self.repo.tags
+ def find_tags(self, sub):
+ """Find all tags matching starting with given substring
+
+ Keyword Arguments:
+ sub - The sub string to match against
+
+ Returns:
+ A list of tags that contain the given substring
+ """
+
+ tags = [t for t in self.repo.tags if t.name.startswith(sub)]
+
+ try:
+ tags.sort(key=lambda t: t.tag.tagged_date) # Sort by creation date
+ return tags
+ except AttributeError as e:
+ raise AttributeError("{0} - tag not annotated".format(e))
+
+ def find_last_tag(self, version):
+ """Find the last tag prior to the given version on the same major branch.
+
+ Keyword Arguments:
+ version - A version object used to start the search from
+
+ Returns:
+ A version object representing the located tag, or None if a tag
+ cannot be located.
+ """
+
+ prev = version.get_previous_version()
+ if prev.major != version.major:
+ return None
+
+ if prev.minor == version.minor:
+ # Last tag is the previous version.
+ if self.tag_exists(str(prev)):
+ return prev
+
+ raise ValueError("Tag '{0}' does not exist!".format(prev))
+
+ # Find the last set of tags for a previous version
+ tags = []
+ while prev.major == version.major:
+ tags = self.find_tags(prev.branch_name())
+ if tags: break
+ prev = prev.get_previous_version()
+
+ if prev.major != version.major:
+ return None
+
+ # Last item in list is the last tag
+ return AsteriskVersion.create_from_string(tags[-1].name)
def create_tag(self, name):
"""Create a new local tag
@@ -266,13 +359,15 @@
self.repo.create_tag(name, message="Create '{0}'".format(name))
LOGGER.debug("Created tag {0}".format(name))
-
def checkout(self, name):
"""Checkout the specified tag or branch
Keyword Arguments:
name - The tag or branch to checkout
"""
+
+ if name == self.current_branch:
+ return
self.current_branch = name
@@ -286,6 +381,7 @@
tracking = self.repo.remotes.origin.refs[name]
except:
tracking = 'HEAD'
+ self.updated_branches.append(name)
try:
branch = self.repo.heads[name]
@@ -302,7 +398,6 @@
self.repo.remotes.origin.pull()
LOGGER.debug("Local branch set to {0}".format(name))
-
def _convert_git_to_digium_commit(self, git_commit):
"""Convert a Git commit into a Digium/Asterisk commit
@@ -322,7 +417,6 @@
git_commit.author.email)
return digium_commit
-
def _convert_git_to_digium_commits(self, git_commits):
"""Convert a series of Git commits to Digium/Asterisk commits
@@ -339,7 +433,6 @@
digium_commits.append(digium_commit)
return digium_commits
-
def get_commits_by_tags(self, start, end):
"""Retrieve a sequence of commits between two tags
@@ -362,7 +455,6 @@
list(self.repo.iter_commits(rev='{0}..{1}'.format(
commit_start, commit_end))))
-
def get_commits_by_date(self, branch, start, end):
"""Retrieve a sequence of commits between two dates
@@ -384,7 +476,6 @@
list(self.repo.iter_commits(rev=branch,
after=commit_start, before=commit_end)))
-
def add_and_commit(self, files, commit_msg):
"""Add and commit modified files
@@ -399,9 +490,9 @@
self.repo.index.add(files)
self.repo.index.commit(commit_msg)
-
def push_changes(self):
- """Push any changes (branch, tags, etc...) upstream"""
+ """Push any changes (branches, tags, etc...) upstream"""
self._push_tags()
- self._push_branch()
+ self._push_updated_branches()
+ self._push_deleted_branches()
diff --git a/version_parser.py b/version_parser.py
index 3a6188b..fcb116e 100644
--- a/version_parser.py
+++ b/version_parser.py
@@ -136,6 +136,66 @@
previous.major -= 1
return previous
+ def has_modifier(self, mods):
+ """Check to see if any of the given modifiers are part of
+ this version.
+
+ Keyword Arguments:
+ mods - a list of modifiers to search for
+ """
+
+ if not isinstance(mods, list):
+ mods = [mods]
+
+ for m in mods:
+ for p, n in self.modifiers:
+ if m in "{0}{1}".format(p, n):
+ return True
+ return False
+
+ def branch_name(self, prefix=True):
+ """Retrieve the name of a branch.
+
+ Branches are name from the major.minor numbers, so we only have to
+ use those values when building the branch name.
+ """
+
+ name = '{0}.{1}'.format(self.major, self.minor)
+
+ if prefix and self.prefix:
+ name = '{0}/{1}'.format(self.prefix, name)
+
+ return name
+
+ def is_first(self):
+ """Retrieve whether or not this version represents the first patch
+ release for a branch.
+
+ Returns:
+ True if the version has a patch number of '0' or has a 'cert1'
+ modifier, and does not contain other modifiers (like RCs).
+ """
+
+ return ((self.patch == 0 or self.has_modifier('cert1'))
+ and not self.has_modifier(['rc', 'alpha', 'beta']))
+
+ def is_first_pre(self):
+ """Retrieve whether or not this version represents the first pre-
+ release for a branch.
+
+ Returns:
+ True if the version that has a patch number of '0' or has a 'cert1'
+ modifier, and contains an 'rc1' (or similar) modifier.
+ """
+
+ # Major branch releases start with beta1 so check that first
+ if self.minor == 0 and self.patch == 0:
+ return self.has_modifier('beta1')
+
+ # Otherwise it might be a branch release, so check for rc1
+ return ((self.patch == 0 or self.has_modifier('cert1')) and
+ self.has_modifier('rc1'))
+
def __repr__(self):
"""Return a representation of the version"""
ver = ''
--
To view, visit https://gerrit.asterisk.org/8290
To unsubscribe, visit https://gerrit.asterisk.org/settings
Gerrit-Project: repotools
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I5a7f44e75ae3d867f9795b7fb0ea5bff526b5429
Gerrit-Change-Number: 8290
Gerrit-PatchSet: 1
Gerrit-Owner: Kevin Harwell <kharwell at digium.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20180219/fb86dfd9/attachment-0001.html>
More information about the asterisk-code-review
mailing list