Bug 1497575: [staging-release] Add try subcommand to create a push for staging releases; r=aki,ahal
authorTom Prince <mozilla@hocat.ca>
Tue, 16 Oct 2018 23:04:03 +0000
changeset 497466 8b563ebe7cdad2b7f739cd53dfec0fc6ea9581f8
parent 497465 cc20c7974801cb69129d1bf78b40b9f92f364b98
child 497467 80f7c4e29bea3f238bbf047c3fdf8e853c8c0a5d
push id9996
push userarchaeopteryx@coole-files.de
push dateThu, 18 Oct 2018 18:37:15 +0000
treeherdermozilla-beta@8efe26839243 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaki, ahal
bugs1497575
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1497575: [staging-release] Add try subcommand to create a push for staging releases; r=aki,ahal This adds `mach try release` which adds temporary changes to enable staging release to run. Differential Revision: https://phabricator.services.mozilla.com/D8625
taskcluster/taskgraph/decision.py
tools/moz.build
tools/tryselect/mach_commands.py
tools/tryselect/push.py
tools/tryselect/selectors/release.py
--- a/taskcluster/taskgraph/decision.py
+++ b/taskcluster/taskgraph/decision.py
@@ -277,24 +277,30 @@ def get_decision_parameters(config, opti
         set_try_config(parameters, task_config_file)
 
     result = Parameters(**parameters)
     result.check()
     return result
 
 
 def set_try_config(parameters, task_config_file):
-    parameters['try_mode'] = None
     if os.path.isfile(task_config_file):
         logger.info("using try tasks from {}".format(task_config_file))
-        parameters['try_mode'] = 'try_task_config'
         with open(task_config_file, 'r') as fh:
-            parameters['try_task_config'] = json.load(fh)
-    else:
-        parameters['try_task_config'] = None
+            task_config = json.load(fh)
+        task_config_version = task_config.get('version', 1)
+        if task_config_version == 1:
+            parameters['try_mode'] = 'try_task_config'
+            parameters['try_task_config'] = task_config
+        elif task_config_version == 2:
+            parameters.update(task_config['parameters'])
+            return
+        else:
+            raise Exception(
+                "Unknown `try_task_config.json` version: {}".format(task_config_version))
 
     if 'try:' in parameters['message']:
         parameters['try_mode'] = 'try_option_syntax'
         args = parse_message(parameters['message'])
         parameters['try_options'] = args
     else:
         parameters['try_options'] = None
 
--- a/tools/moz.build
+++ b/tools/moz.build
@@ -36,16 +36,19 @@ with Files("rb/**"):
     BUG_COMPONENT = ("Core", "XPCOM")
 
 with Files("rewriting/**"):
     BUG_COMPONENT = ("Core", "Rewriting and Analysis")
 
 with Files("tryselect/**"):
     BUG_COMPONENT = ("Testing", "General")
 
+with Files("tryselect/selectors/release.py"):
+    BUG_COMPONENT = ("Release Engineering", "General")
+
 with Files("update-packaging/**"):
     BUG_COMPONENT = ("Release Engineering", "Other")
 
 SPHINX_TREES['lint'] = 'lint/docs'
 
 with Files('lint/docs/**'):
     SCHEDULES.exclusive = ['docs']
 
--- a/tools/tryselect/mach_commands.py
+++ b/tools/tryselect/mach_commands.py
@@ -229,8 +229,18 @@ class TrySelect(MachCommandBase):
 
         config_status = os.path.join(self.topobjdir, 'config.status')
         if (kwargs['paths'] or kwargs['tags']) and not config_status:
             print(CONFIG_ENVIRONMENT_NOT_FOUND)
             sys.exit(1)
 
         at = AutoTry(self.topsrcdir, self._mach_context)
         return at.run(**kwargs)
+
+    @SubCommand('try',
+                'release',
+                description='Push the current tree to try, configured for a staging release.',
+                parser=get_parser('release'))
+    def try_release(self, **kwargs):
+        """Push the current tree to try, configured for a staging release.
+        """
+        from tryselect.selectors.release import run_try_release
+        return run_try_release(**kwargs)
--- a/tools/tryselect/push.py
+++ b/tools/tryselect/push.py
@@ -47,17 +47,17 @@ vcs = get_repository_object(build.topsrc
 topsrcdir_hash = hashlib.sha256(os.path.abspath(build.topsrcdir)).hexdigest()
 history_path = os.path.join(get_state_dir()[0], 'history', topsrcdir_hash, 'try_task_configs.json')
 old_history_path = os.path.join(get_state_dir()[0], 'history', 'try_task_configs.json')
 
 
 def write_task_config(try_task_config):
     config_path = os.path.join(vcs.path, 'try_task_config.json')
     with open(config_path, 'w') as fh:
-        json.dump(try_task_config, fh, indent=2, separators=(',', ':'))
+        json.dump(try_task_config, fh, indent=4, separators=(',', ': '))
         fh.write('\n')
     return config_path
 
 
 def write_task_config_history(msg, try_task_config):
     if not os.path.isfile(history_path):
         if not os.path.isdir(os.path.dirname(history_path)):
             os.makedirs(os.path.dirname(history_path))
@@ -77,53 +77,65 @@ def check_working_directory(push=True):
         return
 
     if not vcs.working_directory_clean():
         print(UNCOMMITTED_CHANGES)
         sys.exit(1)
 
 
 def push_to_try(method, msg, labels=None, templates=None, try_task_config=None,
-                push=True, closed_tree=False):
+                push=True, closed_tree=False, files_to_change=None):
     check_working_directory(push)
 
     # Format the commit message
     closed_tree_string = " ON A CLOSED TREE" if closed_tree else ""
     commit_message = ('%s%s\n\nPushed via `mach try %s`' %
                       (msg, closed_tree_string, method))
 
     if labels or labels == []:
-        try_task_config = {'tasks': sorted(labels)}
+        try_task_config = {
+            'version': 1,
+            'tasks': sorted(labels),
+        }
         if templates:
             try_task_config['templates'] = templates
         if push:
             write_task_config_history(msg, try_task_config)
 
-    config = None
+    config_path = None
+    changed_files = []
     if try_task_config:
-        config = write_task_config(try_task_config)
+        config_path = write_task_config(try_task_config)
+        changed_files.append(config_path)
+
+    if files_to_change:
+        for path, content in files_to_change.items():
+            path = os.path.join(vcs.path, path)
+            with open(path, 'w') as fh:
+                fh.write(content)
+            changed_files.append(path)
 
     try:
         if not push:
             print("Commit message:")
             print(commit_message)
-            if config:
+            if config_path:
                 print("Calculated try_task_config.json:")
-                with open(config) as fh:
+                with open(config_path) as fh:
                     print(fh.read())
             return
 
-        if config:
-            vcs.add_remove_files(config)
+        for path in changed_files:
+            vcs.add_remove_files(path)
 
         try:
             vcs.push_to_try(commit_message)
         except MissingVCSExtension as e:
             if e.ext == 'push-to-try':
                 print(HG_PUSH_TO_TRY_NOT_FOUND)
             elif e.ext == 'cinnabar':
                 print(GIT_CINNABAR_NOT_FOUND)
             else:
                 raise
             sys.exit(1)
     finally:
-        if config and os.path.isfile(config):
-            os.remove(config)
+        if config_path and os.path.isfile(config_path):
+            os.remove(config_path)
new file mode 100644
--- /dev/null
+++ b/tools/tryselect/selectors/release.py
@@ -0,0 +1,61 @@
+# 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/.
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+import attr
+from mozilla_version.gecko import FirefoxVersion
+
+from ..cli import BaseTryParser
+from ..push import push_to_try
+
+
+class ReleaseParser(BaseTryParser):
+    name = 'release'
+    arguments = [
+        [['-v', '--version'],
+         {'metavar': 'STR',
+          'required': True,
+          'action': 'store',
+          'type': FirefoxVersion.parse,
+          'help': "The version number to use for the staging release.",
+          }],
+    ]
+    common_groups = ['push']
+
+
+def run_try_release(version, push=True, message='{msg}', **kwargs):
+
+    if version.is_beta:
+        app_version = attr.evolve(version, beta_number=None)
+    else:
+        app_version = version
+
+    files_to_change = {
+        'browser/config/version.txt': '{}\n'.format(app_version),
+        'browser/config/version_display.txt': '{}\n'.format(version),
+    }
+
+    release_type = version.version_type.name.lower()
+    if release_type not in ('beta', 'release', 'esr'):
+        raise Exception(
+            "Can't do staging release for version: {} type: {}".format(
+                version, version.version_type))
+    task_config = {
+        'version': 2,
+        'parameters': {
+            'target_tasks_method': 'staging_release_builds',
+            'optimize_target_tasks': True,
+            'include_nightly': True,
+            'release_type': release_type,
+        },
+    }
+
+    msg = 'staging release: {}'.format(version)
+    return push_to_try(
+        'release', message.format(msg=msg),
+        push=push, closed_tree=kwargs["closed_tree"],
+        try_task_config=task_config,
+        files_to_change=files_to_change,
+    )