Bug 1492128: [mozrelease] Send an email when a release starts with a bug list; r=mtabara a=release
authorTom Prince <mozilla@hocat.ca>
Tue, 30 Oct 2018 21:04:00 +0000
changeset 501024 45948f09c167c3a3fffe0fa3c86e709fff133c5d
parent 501023 824771ceb6f16cedde18560a2813df04a5ac97bc
child 501025 c00f4ecec6e7b7dc3867bfad8e116ed18395bc68
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmtabara, release
bugs1492128
milestone64.0
Bug 1492128: [mozrelease] Send an email when a release starts with a bug list; r=mtabara a=release Differential Revision: https://phabricator.services.mozilla.com/D10155
python/mozrelease/mozrelease/buglist_creator.py
python/mozrelease/mozrelease/mach_commands.py
taskcluster/ci/release-notify-started/kind.yml
taskcluster/docs/kinds.rst
taskcluster/taskgraph/transforms/job/mach.py
taskcluster/taskgraph/transforms/release_started.py
--- a/python/mozrelease/mozrelease/buglist_creator.py
+++ b/python/mozrelease/mozrelease/buglist_creator.py
@@ -4,16 +4,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, print_function
 
 import logging
 import os
 import re
 import requests
+from taskcluster.notify import Notify
 from operator import itemgetter
 
 from mozilla_version.gecko import GeckoVersion
 
 BUGLIST_PREFIX = 'Bugs since previous changeset: '
 BACKOUT_REGEX = re.compile(r'back(\s?)out|backed out|backing out', re.IGNORECASE)
 BACKOUT_PREFIX = 'Backouts since previous changeset: '
 BUGZILLA_BUGLIST_TEMPLATE = 'https://bugzilla.mozilla.org/buglist.cgi?bug_id={bugs}'
@@ -205,8 +206,48 @@ def get_branch_by_version(version):
     elif version.is_release:
         return 'releases/mozilla-release'
     elif version.is_esr:
         return 'releases/mozilla-esr{}'.format(version.major_number)
     else:
         raise Exception(
             'Unsupported version type {}: {}'.format(
                 version.version_type.name, version))
+
+
+def email_release_drivers(
+    addresses, product, version, build_number,
+    revision, task_group_id,
+):
+    # Send an email to the mailing after the build
+    email_buglist_string = create_bugs_url(product, version, revision)
+
+    content = """\
+A new build has been started:
+
+Commit: https://hg.mozilla.org/{path}/rev/{revision}
+Task group: https://tools.taskcluster.net/push-inspector/#/{task_group_id}
+
+{email_buglist_string}
+""".format(path=get_branch_by_version(version), revision=revision,
+           task_group_id=task_group_id,
+           email_buglist_string=email_buglist_string)
+
+    # On r-d, we prefix the subject of the email in order to simplify filtering
+    subject_prefix = ""
+    if product in {"fennec"}:
+        subject_prefix = "[mobile] "
+    if product in {"firefox", "devedition"}:
+        subject_prefix = "[desktop] "
+
+    subject = '{} Build of {} {} build {}'.format(subject_prefix, product, version, build_number)
+
+    notify_options = {}
+    if 'TASKCLUSTER_PROXY_URL' in os.environ:
+        base_url = os.environ['TASKCLUSTER_PROXY_URL'].rstrip('/')
+        notify_options['baseUrl'] = '{}/notify/v1'.format(base_url)
+    notify = Notify(notify_options)
+    for address in addresses:
+        notify.email({
+            'address': address,
+            'subject': subject,
+            'content': content,
+        })
--- a/python/mozrelease/mozrelease/mach_commands.py
+++ b/python/mozrelease/mozrelease/mach_commands.py
@@ -47,16 +47,44 @@ class MachCommands(MachCommandBase):
         self.setup_logging()
         from mozrelease.buglist_creator import create_bugs_url
         print(create_bugs_url(
             product=product,
             current_version=version,
             current_revision=revision,
         ))
 
+    @SubCommand('release', 'send-buglist-email',
+                description="Send an email with the bugs since the last release.")
+    @CommandArgument('--address',
+                     required=True,
+                     action='append',
+                     dest='addresses',
+                     help="The email address to send the bug list to "
+                          "(may be specified more than once.")
+    @CommandArgument('--version',
+                     type=GeckoVersion.parse,
+                     required=True,
+                     help="The version being built.")
+    @CommandArgument('--product',
+                     required=True,
+                     help="The product being built.")
+    @CommandArgument('--revision',
+                     required=True,
+                     help="The revision being built.")
+    @CommandArgument('--build-number',
+                     required=True,
+                     help="The build number")
+    @CommandArgument('--task-group-id',
+                     help="The task group of the build.")
+    def buglist_email(self, **options):
+        self.setup_logging()
+        from mozrelease.buglist_creator import email_release_drivers
+        email_release_drivers(**options)
+
     def setup_logging(self, quiet=False, verbose=True):
         """
         Set up Python logging for all loggers, sending results to stderr (so
         that command output can be redirected easily) and adding the typical
         mach timestamp.
         """
         # remove the old terminal handler
         old = self.log_manager.replace_terminal_handler(None)
new file mode 100644
--- /dev/null
+++ b/taskcluster/ci/release-notify-started/kind.yml
@@ -0,0 +1,36 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+loader: taskgraph.loader.transform:loader
+
+transforms:
+    - taskgraph.transforms.release_deps:transforms
+    - taskgraph.transforms.release_started:transforms
+    - taskgraph.transforms.job:transforms
+    - taskgraph.transforms.task:transforms
+
+job-defaults:
+    name: notify-release-drivers-started
+    description: Sends email to release-drivers telling release was started.
+    run-on-projects: []
+    shipping-phase: promote
+    worker-type: aws-provisioner-v1/gecko-{level}-b-linux
+    worker:
+        docker-image: {in-tree: "debian9-base"}
+        max-run-time: 600
+    emails:
+        by-project:
+            mozilla-beta: ["release-signoff@mozilla.org"]
+            mozilla-release: ["release-signoff@mozilla.org"]
+            mozilla-esr60: ["release-signoff@mozilla.org"]
+            try: ["{config[params][owner]}"]
+            default: []
+
+jobs:
+    fennec:
+        shipping-product: fennec
+    firefox:
+        shipping-product: firefox
+    devedition:
+        shipping-product: devedition
--- a/taskcluster/docs/kinds.rst
+++ b/taskcluster/docs/kinds.rst
@@ -282,16 +282,20 @@ Notify when a release has been shipped.
 release-secondary-notify-ship
 -----------------------------
 Notify when an RC release has been shipped to the beta channel.
 
 release-notify-promote
 ----------------------
 Notify when a release has been promoted.
 
+release-notify-started
+-------------------
+Notify when a release has been started.
+
 release-bouncer-sub
 -------------------
 Submits bouncer updates for releases.
 
 release-mark-as-shipped
 -----------------------
 Marks releases as shipped in Ship-It v1
 
--- a/taskcluster/taskgraph/transforms/job/mach.py
+++ b/taskcluster/taskgraph/transforms/job/mach.py
@@ -4,24 +4,28 @@
 """
 Support for running mach tasks (via run-task)
 """
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 from taskgraph.transforms.job import run_job_using, configure_taskdesc_for_run
 from taskgraph.util.schema import Schema
-from voluptuous import Required
+from voluptuous import Required, Optional, Any
 
 mach_schema = Schema({
     Required('using'): 'mach',
 
     # The mach command (omitting `./mach`) to run
     Required('mach'): basestring,
 
+    # The sparse checkout profile to use. Value is the filename relative to the
+    # directory where sparse profiles are defined (build/sparse-profiles/).
+    Optional('sparse-profile'): Any(basestring, None),
+
     # if true, perform a checkout of a comm-central based branch inside the
     # gecko checkout
     Required('comm-checkout'): bool,
 
     # Base work directory used to set up the task.
     Required('workdir'): basestring,
 })
 
new file mode 100644
--- /dev/null
+++ b/taskcluster/taskgraph/transforms/release_started.py
@@ -0,0 +1,50 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"""
+Add notifications via taskcluster-notify for release tasks
+"""
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+import os
+from pipes import quote as shell_quote
+
+from taskgraph.transforms.base import TransformSequence
+from taskgraph.util.schema import resolve_keyed_by
+
+
+transforms = TransformSequence()
+
+
+@transforms.add
+def add_notifications(config, jobs):
+    for job in jobs:
+        label = '{}-{}'.format(config.kind, job['name'])
+
+        resolve_keyed_by(job, 'emails', label, project=config.params['project'])
+        emails = [email.format(config=config.__dict__) for email in job.pop('emails')]
+
+        command = [
+            'release',
+            'send-buglist-email',
+            '--version', config.params['version'],
+            '--product', job['shipping-product'],
+            '--revision', config.params['head_rev'],
+            '--build-number', str(config.params['build_number']),
+        ]
+        for address in emails:
+            command += ['--address', address]
+        if 'TASK_ID' in os.environ:
+            command += [
+                '--task-group-id', os.environ['TASK_ID'],
+            ]
+
+        job['scopes'] = ['notify:email:{}'.format(address) for address in emails]
+        job['run'] = {
+            'using': 'mach',
+            'sparse-profile': 'mach',
+            'mach': ' '.join(map(shell_quote, command)),
+        }
+
+        yield job