taskcluster/taskgraph/transforms/diffoscope.py
author Narcis Beleuzu <nbeleuzu@mozilla.com>
Wed, 21 Nov 2018 00:29:17 +0200
changeset 506598 3b818a926ee427b28b7898d24afec9cc864cda7f
parent 506594 e947694d0ed75030968484df36f08a222cdd79b5
child 506606 e27269b076334ddd520fcbab374b584942b886f2
permissions -rw-r--r--
Backed out changeset e947694d0ed7 (bug 1507898) for Linting failure. CLOSED TREE

# 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/.
"""
This transform construct tasks to perform diffs between builds, as
defined in kind.yml
"""

from __future__ import absolute_import, print_function, unicode_literals

from taskgraph.transforms.base import TransformSequence
from taskgraph.util.schema import (
    Schema,
    validate_schema,
)
from taskgraph.util.taskcluster import get_artifact_path, get_artifact_url
from voluptuous import (
    Any,
    Optional,
    Required,
)

transforms = TransformSequence()

index_or_string = Any(
    basestring,
    {Required('index-search'): basestring},
)

diff_description_schema = Schema({
    # Name of the diff task.
    Required('name'): basestring,

    # Treeherder symbol.
    Required('symbol'): basestring,

    # relative path (from config.path) to the file the task was defined in.
    Optional('job-from'): basestring,

    # Original and new builds to compare.
    Required('original'): index_or_string,
    Required('new'): index_or_string,

    # Arguments to pass to diffoscope, used for job-defaults in
    # taskcluster/ci/diffoscope/kind.yml
    Optional('args'): basestring,

    # Extra arguments to pass to diffoscope, that can be set per job.
    Optional('extra-args'): basestring,
})


@transforms.add
def validate(config, tasks):
    for task in tasks:
        validate_schema(
            diff_description_schema, task,
            "In diff task {!r}:".format(task.get('name', 'unknown')))
        yield task


@transforms.add
def fill_template(config, tasks):
    dummy_tasks = {}

    for task in tasks:
        name = task['name']

        deps = {}
        urls = {}
        previous_artifact = None
        for k in ('original', 'new'):
            value = task[k]
            if isinstance(value, basestring):
                deps[k] = value
                task_id = '<{}>'.format(k)
                os_hint = value
            else:
                index = value['index-search']
                if index not in dummy_tasks:
                    dummy_tasks[index] = {
                        'label': 'index-search-' + index,
                        'description': index,
                        'worker-type': 'invalid/always-optimized',
                        'run': {
                            'using': 'always-optimized',
                        },
                        'optimization': {
                            'index-search': [index],
                        }
                    }
                    yield dummy_tasks[index]
                deps[index] = 'index-search-' + index
                task_id = '<{}>'.format(index)
                os_hint = index.split('.')[-1]
            if 'linux' in os_hint:
                artifact = 'target.tar.bz2'
            elif 'macosx' in os_hint:
                artifact = 'target.dmg'
            elif 'android' in os_hint:
                artifact = 'target.apk'
            elif 'win' in os_hint:
                artifact = 'target.zip'
            else:
                raise Exception(
                    'Cannot figure out the OS for {!r}'.format(value))
            if previous_artifact is not None and previous_artifact != artifact:
                raise Exception(
                    'Cannot compare builds from different OSes')
            url = get_artifact_url(task_id, get_artifact_path(task, artifact))
            urls[k] = {'task-reference': url}
            previous_artifact = artifact

        taskdesc = {
            'label': 'diff-' + name,
            'description': name,
            'treeherder': {
                'symbol': task['symbol'],
                'platform': 'diff/opt',
                'kind': 'other',
                'tier': 2,
            },
            'worker-type': 'aws-provisioner-v1/gecko-{}-b-linux'.format(
               config.params['level']),
            'worker': {
                'docker-image': {'in-tree': 'diffoscope'},
                'artifacts': [{
                    'type': 'file',
                    'path': '/builds/worker/diff.html',
                    'name': 'public/diff.html',
                }, {
                    'type': 'file',
                    'path': '/builds/worker/diff.txt',
                    'name': 'public/diff.txt',
                }],
                'env': {
                    'ORIG_URL': urls['original'],
                    'NEW_URL': urls['new'],
                    'DIFFOSCOPE_ARGS': ' '.join(
                        task[k] for k in ('args', 'extra-args') if k in task)
                },
                'max-run-time': 1800,
            },
            'run': {
                'using': 'run-task',
                'checkout': False,
                'command': '/builds/worker/bin/get_and_diffoscope '
                           '"$ORIG_URL" "$NEW_URL"',
            },
            'dependencies': deps,
        }

        if artifact.endswith('.dmg'):
            taskdesc['toolchains'] = [
                'linux64-cctools-port',
                'linux64-libdmg',
            ]

        yield taskdesc