[Asterisk-code-review] Update JIRA issues during the make release process (repotools[master])

George Joseph asteriskteam at digium.com
Wed Nov 15 07:35:33 CST 2017


George Joseph has submitted this change and it was merged. ( https://gerrit.asterisk.org/7144 )

Change subject: Update JIRA issues during the make release process
......................................................................

Update JIRA issues during the make release process

Typically when doing a release there are many JIRA issues that need to be
updated with the version number in which the fix is going out. This use to
be a separate step in the release process. Meaning the mkrelease script
was run, and then another script was manually ran to update the JIRA issues.

Now, however with this patch the JIRA issues are updated during the make
release process. The execution of the second script is no longer needed.
It also will create the version being released in JIRA if it does not
already exist.

Change-Id: I1be07a4ff67f5733b6f4cc410d47c4fce7b5a1e3
---
M digium_git.py
M digium_jira.py
M jira-release-update.py
M mkrelease.py
M release_summary.py
5 files changed, 150 insertions(+), 71 deletions(-)

Approvals:
  Joshua Colp: Looks good to me, but someone else must approve; Verified
  George Joseph: Looks good to me, approved; Approved for Submit



diff --git a/digium_git.py b/digium_git.py
index 4a78b7f..3536522 100644
--- a/digium_git.py
+++ b/digium_git.py
@@ -21,6 +21,38 @@
 LOGGER = logging.getLogger(__name__)
 
 
+# The one and only Gerrit/Git server.
+GERRIT = 'ssh://gerrit.asterisk.org:29418'
+
+DEFAULT_PROJECT = 'asterisk'
+DEFAULT_LOCAL_ROOT = '/tmp'
+
+
+def get_repo(project=None, local_root=None, remote_url=None,
+             show_progress=False):
+    """Prepare the repo that the release will be made from
+
+    Keyword Arguments:
+    project - The name of the project (default 'asterisk')
+    local_root - The local root directory where the repository will be
+        checked out under (default '/tmp')
+    remote_url - The remote url for the repository (default GERRIT)
+    show_progress - False (default) if a progress bar should not be shown
+
+    Returns:
+    A DigiumGitRepo object
+    """
+    project = project or DEFAULT_PROJECT
+    local_root = local_root or DEFAULT_LOCAL_ROOT
+    remote_url = remote_url or GERRIT
+
+    path = os.path.join(local_root, project)
+    repo_url = '{0}/{1}'.format(remote_url, project)
+
+    LOGGER.debug("Cloning from '{0}' to '{1}'".format(repo_url, path))
+    return DigiumGitRepo(path, repo_url=repo_url, show_progress=show_progress)
+
+
 class GitProgressBar(RemoteProgress):
     """A progress bar that maintains the state of a Git operation
     """
@@ -373,4 +405,3 @@
 
         self._push_tags()
         self._push_branch()
-
diff --git a/digium_jira.py b/digium_jira.py
index 560b7c2..b7d26f8 100644
--- a/digium_jira.py
+++ b/digium_jira.py
@@ -5,11 +5,17 @@
 Russell Bryant <russell at digium.com>
 """
 
+import logging
 import os
 import getpass
 
 from jira.client import JIRA
+from version_parser import AsteriskVersion
 
+
+LOGGER = logging.getLogger(__name__)
+
+DEFAULT_PROJECT = 'asterisk'
 
 def _get_jira_auth():
     """Get JIRA credentials"""
@@ -42,3 +48,88 @@
     jira = JIRA(options=jira_options, basic_auth=(jira_user, jira_password))
 
     return jira
+
+
+class DigiumJira(object):
+    """A managed Jira client
+
+    This class wraps up a Jira client and provides some common operations on it
+    that are useful for common project operations.
+    """
+
+    def __init__(self, project=DEFAULT_PROJECT, jira=None):
+        """Constructor
+
+        Keyword Arguments:
+        project - The name of the project in Jira
+        jira - The Jira client. If not specified one is created.
+        """
+        self._jira = jira or get_jira_client()
+        self._project = project
+
+
+class DigiumJiraVersion(DigiumJira):
+
+    def __init__(self, version, project=DEFAULT_PROJECT, jira=None):
+        """Constructor
+
+        Keyword Arguments:
+        version - The version to be used
+        project - The name of the project in Jira
+        jira - The Jira client. If not specified one is created.
+        """
+        super(DigiumJiraVersion, self).__init__(project, jira)
+
+        version = AsteriskVersion.create_from_string(version)
+
+        if version.prefix == 'certified':
+            # Set the apply version method to empty so it becomes a no op
+            self.apply_version = lambda x: None
+            return
+
+        self._version = '{0}.{1}.{2}'.format(
+            version.major, version.minor, version.patch)
+
+        self._jira_versions = {}
+
+        try:
+            LOGGER.info("Creating version {0} in project {1}"
+                         .format(self._version, self._project))
+            self._jira.create_version(version, self._project)
+        except:
+            LOGGER.debug("Version {0} already exists in project {1}"
+                         .format(self._version, self._project))
+
+    def apply_version(self, issue):
+        """Apply the version to the given issue
+
+        Keyword Arguments:
+        issue - The issue to apply the version to
+        """
+
+        # Get the actual version object for the project. This
+        # is what must be passed to JIRA to update the fixVersion
+        # field for the issue.
+        project = issue.fields.project
+        if project.name not in self._jira_versions:
+            project_versions = self._jira.project_versions(project)
+            try:
+                version, = [ver.id for ver in project_versions
+                            if ver.name == self._version]
+            except Exception:
+                LOGGER.error("Could not handle versions for {0}"
+                             .format(issue.id))
+                return
+
+            self._jira_versions[project.name] = version
+
+        # Make sure we don't update the fixVersion more than once for
+        # a particular issue
+        matches = [match for match in issue.fields.fixVersions
+                   if match.name == self._version]
+        if len(matches) == 0:
+            version_array = [{'id': u'{0}'.format(ver.id)} for ver in
+                             issue.fields.fixVersions]
+            version_array.append({'id': u'{0}'.format(
+                self._jira_versions[project.name])})
+            issue.update(fields={'fixVersions': version_array})
diff --git a/jira-release-update.py b/jira-release-update.py
index 6cd62dc..b980638 100755
--- a/jira-release-update.py
+++ b/jira-release-update.py
@@ -12,8 +12,8 @@
 from progressbar import ProgressBar
 from optparse import OptionParser
 
-from digium_git import DigiumGitRepo
-from digium_jira import get_jira_client
+from digium_git import get_repo
+from digium_jira import DigiumJiraVersion
 
 # The upstream Gerrit repo
 GERRIT = 'ssh://gerrit.asterisk.org:29418'
@@ -31,11 +31,9 @@
     print "Update JIRA for %s-%s ..." % \
         (options.project, options.version)
 
-    jira = get_jira_client()
-
-    path = os.path.join(options.local_root, options.project)
-    gerrit_repo = '{0}/{1}'.format(GERRIT, options.project)
-    repo = DigiumGitRepo(path, gerrit_repo, show_progress=True)
+    djv = DigiumJiraVersion(options.version, options.project)
+    repo = get_repo(options.project, options.local_root,
+                    options.remote_url, True)
 
     log_messages = repo.get_commits_by_tags(options.start_tag, options.end_tag)
 
@@ -64,33 +62,8 @@
                 continue
 
             status = str(issue.fields.status).lower()
-            if status != 'closed' and status != 'complete':
-                continue
-
-            # Get the actual version object for the project. This
-            # is what must be passed to JIRA to update the fixVersion
-            # field for the issue.
-            project = issue.fields.project
-            if project.name not in jira_versions:
-                project_versions = jira.project_versions(project)
-                try:
-                    version, = [ver.id for ver in project_versions
-                                if ver.name == options.version]
-                except Exception:
-                    print "Could not handle versions for {0}".format(issue_id)
-                    continue
-                jira_versions[project.name] = version
-
-            # Make sure we don't update the fixVersion more than once for
-            # a particular issue
-            matches = [match for match in issue.fields.fixVersions
-                       if match.name == options.version]
-            if len(matches) == 0:
-                version_array = [{'id': u'{0}'.format(ver.id)} for ver in
-                                 issue.fields.fixVersions]
-                version_array.append({'id': u'{0}'.format(
-                                     jira_versions[project.name])})
-                issue.update(fields={'fixVersions': version_array})
+            if status == 'closed' or status == 'complete':
+                djv.apply_version(issue)
 
         pbar.update(i + 1)
     pbar.finish()
@@ -122,6 +95,8 @@
     parser.add_option("-v", "--version", action="store", type="string",
         dest="version", default="",
         help="Version ID.")
+    parser.add_option("-r", "--remote-url", action="store", type="string",
+        dest="remote_url", default="", help="The remote url")
 
     (options, args) = parser.parse_args(argv)
 
diff --git a/mkrelease.py b/mkrelease.py
index 851dec2..a3f3f18 100755
--- a/mkrelease.py
+++ b/mkrelease.py
@@ -18,7 +18,7 @@
 from datetime import datetime
 from optparse import OptionParser
 
-from digium_git import DigiumGitRepo
+from digium_git import get_repo
 from version_parser import AsteriskVersion
 from release_summary import ReleaseSummary, ReleaseSummaryOptions
 from alembic_creator import create_db_script
@@ -31,10 +31,6 @@
 logging.getLogger("urllib3").setLevel(logging.WARNING)
 # Same for the migration stuff
 logging.getLogger("alembic").setLevel(logging.WARNING)
-
-
-# The one and only Gerrit/Git server.
-GERRIT = 'ssh://gerrit.asterisk.org:29418'
 
 # The previous tag from this release.
 previous_tag = ''
@@ -114,25 +110,6 @@
     i = version.find('/')
     ftp_project = ('{0}-{1}'.format(version[:i], options.project) if i > 0
                    else options.project)
-
-
-def prepare_repo(options):
-    """Prepare the repo that the release will be made from
-
-    Keyword Arguments:
-    options - Parsed command line arguments
-
-    Returns:
-    A DigiumGitRepo object
-    """
-
-    path = os.path.join(options.local_root, options.project)
-    repo_url = '{0}/{1}'.format(options.remote_url, options.project)
-
-    LOGGER.debug("Cloning from '{0}' to '{1}'".format(repo_url, path))
-    repo = DigiumGitRepo(path, repo_url=repo_url,
-                         show_progress=options.loglevel == logging.DEBUG)
-    return repo
 
 
 def prepare_branch(options, repo):
@@ -296,7 +273,7 @@
                 sum_opts.branch = branch
 
                 summary = ReleaseSummary(
-                    sum_opts, debug=options.loglevel == logging.DEBUG)
+                    sum_opts, repo=repo, debug=options.loglevel == logging.DEBUG)
             else:
                 summary = None
 
@@ -375,7 +352,7 @@
         file_path = os.path.join(file_dir, file_name)
 
         summary = ReleaseSummary(
-            sum_opts, debug=options.loglevel == logging.DEBUG)
+            sum_opts, repo=repo, debug=options.loglevel == logging.DEBUG)
         summary.to_html(out_file=file_path)
         LOGGER.debug("Release summaries created as '{0}'".format(file_path))
 
@@ -663,7 +640,7 @@
                       default="/tmp")
     parser.add_option("-r", "--remote-url", action="store", type="string",
                       dest="remote_url", help="The remote url",
-                      default=GERRIT)
+                      default="")
     parser.add_option("-p", "--project", action="store", type="string",
                       dest="project", help="The project to work from",
                       default="asterisk")
@@ -692,7 +669,8 @@
     # The following are all various set up steps that extract options, prepare
     # the environment, and calculate what it is we are trying to create.
     setup_options(options)
-    repo = prepare_repo(options)
+    repo = get_repo(options.project, options.local_root, options.remote_url,
+                    show_progress=options.loglevel == logging.DEBUG)
     prepare_branch(options, repo)
     extract_tags(options, repo)
 
diff --git a/release_summary.py b/release_summary.py
index 27d2fdd..de475a8 100755
--- a/release_summary.py
+++ b/release_summary.py
@@ -15,7 +15,7 @@
 from optparse import OptionParser
 from progressbar import ProgressBar
 
-from digium_jira import get_jira_client
+from digium_jira import get_jira_client, DigiumJiraVersion
 from digium_jira_user import AsteriskUser
 from digium_git import DigiumGitRepo
 
@@ -30,9 +30,6 @@
 
 # URL prefix for security advisories
 ADVISORY_URL = "http://downloads.asterisk.org/pub/security/"
-
-# URL for Gerrit/Git repos
-GERRIT = "ssh://gerrit.asterisk.org:29418"
 
 # Default repo location
 DEFAULT_REPO_ROOT = "/tmp"
@@ -171,13 +168,14 @@
         "protect their systems from these issues."
 
 
-    def __init__(self, options, jira=None, debug=False):
+    def __init__(self, options, jira=None, repo=None, debug=False):
         """Constructor
 
         Keyword Arguments:
         options      - An instance of ReleaseSummaryOptions.
         jira         - The JIRA client to use.
         debug        - If true, display progress as the summary is built
+        repo
         """
 
         self.jira = jira
@@ -194,9 +192,8 @@
         self.misc_commits = []      # Commits not associated with an issue
         self.contributors = Contributors()
 
-        path = os.path.join(self.options.local_root, self.options.project)
-        gerrit_repo = '{0}/{1}'.format(GERRIT, self.options.project)
-        self.repo = DigiumGitRepo(path, gerrit_repo, show_progress=self.debug)
+        self.repo = repo or get_repo(options.project, options.local_root,
+                                     options.remote_url, self.debug)
 
         # Infer the branch from the version
         if not self.options.branch:
@@ -254,6 +251,12 @@
             pbar.maxval = len(self.raw_log_messages)
             pbar.start()
 
+        # Go ahead and update the fixedVersion on the issue while processing
+        # the release summary. If the version has already been applied it
+        # won't do it again.
+        djv = DigiumJiraVersion(self.options.version,
+                                self.options.project, self.jira)
+
         for i, log_message in enumerate(self.raw_log_messages):
 
             if log_message.raw and len(log_message.raw.parents) > 1:
@@ -306,6 +309,7 @@
                     status = str(issue.fields.status).lower()
                     if status == 'closed' or status == 'complete':
                         issue_dict = self.closed_issues
+                        djv.apply_version(issue)
                     else:
                         issue_dict = self.open_issues
 

-- 
To view, visit https://gerrit.asterisk.org/7144
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-Project: repotools
Gerrit-Branch: master
Gerrit-MessageType: merged
Gerrit-Change-Id: I1be07a4ff67f5733b6f4cc410d47c4fce7b5a1e3
Gerrit-Change-Number: 7144
Gerrit-PatchSet: 1
Gerrit-Owner: Kevin Harwell <kharwell at digium.com>
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20171115/5b6a9ae5/attachment-0001.html>


More information about the asterisk-code-review mailing list