Esempio n. 1
0
 def connect_taskcluster(self, client_id=None, access_token=None):
     '''
     Load notification service
     '''
     self.notify = get_service('notify', client_id, access_token)
     self.queue = get_service('queue', client_id, access_token)
     self.index = get_service('index', client_id, access_token)
Esempio n. 2
0
 def connect_taskcluster(self, client_id=None, access_token=None):
     '''
     Load notification service
     '''
     self.notify = get_service('notify', client_id, access_token)
     self.queue = get_service('queue', client_id, access_token)
     self.index = get_service('index', client_id, access_token)
Esempio n. 3
0
def schedule_phase(name, phase):
    session = current_app.db.session
    try:
        phase = session.query(Phase) \
            .filter(Release.id == Phase.release_id) \
            .filter(Release.name == name) \
            .filter(Phase.name == phase).one()
    except NoResultFound:
        abort(404)

    # we must require scope which depends on product
    required_permission = f'{SCOPE_PREFIX}/schedule_phase/{phase.release.product}/{phase.name}'
    if not current_user.has_permissions(required_permission):
        user_permissions = ', '.join(current_user.get_permissions())
        abort(401, f'required permission: {required_permission}, user permissions: {user_permissions}')

    if phase.submitted:
        abort(409, 'Already submitted!')

    for signoff in phase.signoffs:
        if not signoff.signed:
            abort(400, 'Pending signoffs')

    task_or_hook = phase.task_json
    if 'hook_payload' in task_or_hook:
        hooks = get_service('hooks')
        client_id = hooks.options['credentials']['clientId'].decode('utf-8')
        extra_context = {'clientId': client_id}
        result = hooks.triggerHook(
            task_or_hook['hook_group_id'],
            task_or_hook['hook_id'],
            phase.rendered_hook_payload(extra_context=extra_context),
        )
        phase.task_id = result['status']['taskId']
    else:
        queue = get_service('queue')
        client_id = queue.options['credentials']['clientId'].decode('utf-8')
        extra_context = {'clientId': client_id}
        queue.createTask(phase.task_id, phase.rendered(extra_context=extra_context))

    phase.submitted = True
    phase.completed_by = current_user.get_id()
    completed = datetime.datetime.utcnow()
    phase.completed = completed
    if all([ph.submitted for ph in phase.release.phases]):
        phase.release.status = 'shipped'
        phase.release.completed = completed
    session.commit()

    notify_via_irc(phase.release.product,
                   f'Phase {phase.name} was just scheduled '
                   f'for release {phase.release.product} {phase.release.version} '
                   f'build{phase.release.build_number} - '
                   f'(https://tools.taskcluster.net/groups/{phase.task_id})')

    return phase.json
Esempio n. 4
0
    def connect_taskcluster(self, client_id=None, access_token=None):
        '''
        Save hooks and queue services for later use
        '''
        # Get taskcluster hooks
        self.hooks = get_service('hooks', client_id, access_token)

        # Get taskcluster queue
        self.queue = get_service('queue', client_id, access_token)

        return True
Esempio n. 5
0
def schedule_phase(name, phase):
    session = g.db.session
    try:
        phase = session.query(Phase) \
            .filter(Release.id == Phase.release_id) \
            .filter(Release.name == name) \
            .filter(Phase.name == phase).one()
    except NoResultFound:
        abort(404)

    if phase.submitted:
        abort(409, 'Already submitted!')

    for signoff in phase.signoffs:
        if not signoff.signed:
            abort(400, 'Pending signoffs')

    task_or_hook = phase.task_json
    if 'hook_payload' in task_or_hook:
        hooks = get_service('hooks')
        client_id = hooks.options['credentials']['clientId'].decode('utf-8')
        extra_context = {'clientId': client_id}
        result = hooks.triggerHook(
            task_or_hook['hook_group_id'],
            task_or_hook['hook_id'],
            phase.rendered_hook_payload(extra_context=extra_context),
        )
        phase.task_id = result['status']['taskId']
    else:
        queue = get_service('queue')
        client_id = queue.options['credentials']['clientId'].decode('utf-8')
        extra_context = {'clientId': client_id}
        queue.createTask(phase.task_id,
                         phase.rendered(extra_context=extra_context))

    phase.submitted = True
    phase.completed_by = g.userinfo['email']
    completed = datetime.datetime.utcnow()
    phase.completed = completed
    if all([ph.submitted for ph in phase.release.phases]):
        phase.release.status = 'shipped'
        phase.release.completed = completed
    session.commit()

    notify_via_irc(
        f'Phase {phase.name} was just scheduled '
        f'for release {phase.release.product} {phase.release.version} '
        f'build{phase.release.build_number} - '
        f'(https://tools.taskcluster.net/groups/{phase.task_id})')

    return phase.json
Esempio n. 6
0
    def __init__(self, cache_root, emails, client_id=None, access_token=None):
        self.emails = emails
        self.cache_root = cache_root
        assert os.path.isdir(self.cache_root), \
            'Cache root {} is not a dir.'.format(self.cache_root)

        # Load TC services & secrets
        self.notify = get_service(
            'notify',
            client_id=client_id,
            access_token=access_token,
        )

        # Clone mozilla-central
        self.repo_dir = os.path.join(self.cache_root, 'static-analysis/')
        shared_dir = os.path.join(self.cache_root, 'static-analysis-shared')
        logger.info('Clone mozilla central', dir=self.repo_dir)
        cmd = hglib.util.cmdbuilder('robustcheckout',
                                    REPO_CENTRAL,
                                    self.repo_dir,
                                    purge=True,
                                    sharebase=shared_dir,
                                    branch=b'tip')

        cmd.insert(0, hglib.HGPATH)
        proc = hglib.util.popen(cmd)
        out, err = proc.communicate()
        if proc.returncode:
            raise hglib.error.CommandError(cmd, proc.returncode, out, err)

        # Open new hg client
        self.hg = hglib.open(self.repo_dir)
Esempio n. 7
0
def find_decision_task_id(project, revision):
    decision_task_route = '{trust_domain}.v2.{project}.revision.{revision}.taskgraph.decision'.format(
        trust_domain=get_trust_domain(project),
        project=project,
        revision=revision)
    index = get_service('index')
    return index.findTask(decision_task_route)['taskId']
Esempio n. 8
0
    def __init__(self, repository, revision, task_name_filter, cache_root,
                 client_id, access_token):
        # List of test-suite, sorted alphabetically.
        # This way, the index of a suite in the array should be stable enough.
        self.suites = [
            'web-platform-tests',
        ]

        self.cache_root = cache_root

        temp_dir = tempfile.mkdtemp()
        self.artifacts_dir = os.path.join(temp_dir, 'ccov-artifacts')
        self.ccov_reports_dir = os.path.join(temp_dir, 'code-coverage-reports')

        self.client_id = client_id
        self.access_token = access_token

        self.index_service = get_service('index', client_id, access_token)

        self.githubUtils = GitHubUtils(cache_root, client_id, access_token)

        if revision is None:
            # Retrieve revision of latest codecov build
            self.github_revision = uploader.get_latest_codecov()
            self.repository = MOZILLA_CENTRAL_REPOSITORY
            self.revision = self.githubUtils.git_to_mercurial(
                self.github_revision)
            self.from_pulse = False
        else:
            self.github_revision = None
            self.repository = repository
            self.revision = revision
            self.from_pulse = True

        self.branch = self.repository[len(HG_BASE):]

        assert os.path.isdir(cache_root), 'Cache root {} is not a dir.'.format(
            cache_root)
        self.repo_dir = os.path.join(cache_root, self.branch)

        logger.info('Mercurial revision', revision=self.revision)

        task_ids = {}
        for platform in [
                'linux', 'windows', 'android-test', 'android-emulator'
        ]:
            task = taskcluster.get_task(self.branch, self.revision, platform)

            # On try, developers might have requested to run only one platform, and we trust them.
            # On mozilla-central, we want to assert that every platform was run (except for android platforms
            # as they are unstable).
            if task is not None:
                task_ids[platform] = task
            elif self.repository == MOZILLA_CENTRAL_REPOSITORY and not platform.startswith(
                    'android'):
                raise Exception(
                    'Code coverage build failed and was not indexed.')

        self.artifactsHandler = ArtifactsHandler(task_ids, self.artifacts_dir,
                                                 task_name_filter)
Esempio n. 9
0
def abandon_release(name):
    session = current_app.db.session
    try:
        release = session.query(Release).filter(Release.name == name).one()

        # we must require scope which depends on product
        required_permission = f"{SCOPE_PREFIX}/abandon_release/{release.product}"
        if not current_user.has_permissions(required_permission):
            user_permissions = ", ".join(current_user.get_permissions())
            abort(
                401,
                f"required permission: {required_permission}, user permissions: {user_permissions}"
            )

        # Cancel all submitted task groups first
        for phase in filter(lambda x: x.submitted and not x.skipped,
                            release.phases):
            try:
                actions = fetch_artifact(phase.task_id, "public/actions.json")
                parameters = fetch_artifact(phase.task_id,
                                            "public/parameters.yml")
            except ArtifactNotFound:
                logger.info("Ignoring not completed action task %s",
                            phase.task_id)
                continue

            hook = generate_action_hook(task_group_id=phase.task_id,
                                        action_name="cancel-all",
                                        actions=actions,
                                        parameters=parameters,
                                        input_={})
            hooks = get_service("hooks")
            client_id = hooks.options["credentials"]["clientId"].decode(
                "utf-8")
            hook["context"]["clientId"] = client_id
            hook_payload_rendered = render_action_hook(
                payload=hook["hook_payload"],
                context=hook["context"],
                delete_params=[
                    "existing_tasks", "release_history",
                    "release_partner_config"
                ])
            logger.info("Cancel phase %s by hook %s with payload: %s",
                        phase.name, hook["hook_id"], hook_payload_rendered)
            res = hooks.triggerHook(hook["hook_group_id"], hook["hook_id"],
                                    hook_payload_rendered)
            logger.debug("Done: %s", res)

        release.status = "aborted"
        session.commit()
        release_json = release.json
    except NoResultFound:
        abort(404)

    notify_via_irc(
        release.product,
        f"Release {release.product} {release.version} build{release.build_number} was just canceled."
    )

    return release_json
Esempio n. 10
0
def schedule_phase(name, phase):
    session = flask.g.db.session
    try:
        phase = session.query(Phase) \
            .filter(Release.id == Phase.release_id) \
            .filter(Release.name == name) \
            .filter(Phase.name == phase).one()
    except NoResultFound:
        flask.abort(404)

    if phase.submitted:
        flask.abort(409, 'Already submitted!')

    queue = get_service('queue')
    queue.createTask(phase.task_id, phase.rendered)

    phase.submitted = True
    phase.completed_by = flask.g.userinfo['email']
    completed = datetime.datetime.utcnow()
    phase.completed = completed
    if all([ph.submitted for ph in phase.release.phases]):
        phase.release.status = 'shipped'
        phase.release.completed = completed
    session.commit()

    notify_via_irc(
        f'Phase {phase.name} was just scheduled '
        f'for release {phase.release.product} {phase.release.version} '
        f'build{phase.release.build_number} - '
        f'(https://tools.taskcluster.net/groups/{phase.task_id})')

    return phase.json
Esempio n. 11
0
    def send(self, app_channel):
        '''
        Build and send report using Taskcluster notification service
        '''
        # Skip sending when there are no failed merges
        if not self.merges:
            logger.info('Nothing to report.')
            return

        def _str(x):
            return isinstance(x, bytes) and x.decode('utf-8') or x

        def _commit_report(revision, result):
            fail_fmt = ' * Merge failed for commit `{}` (parent `{}`)\n\n```\n{}```'  # noqa
            default_fmt = ' * Merge {} for commit `{}`'
            if result.status == 'failed':
                return fail_fmt.format(
                    _str(revision),
                    _str(result.parent),
                    result.message,
                )

            else:
                return default_fmt.format(result.status, _str(revision))

        # Build markdown output
        # Sorting failed merge tests by bugzilla id & branch
        subject = '[{}] Uplift bot detected {} merge failures'.format(
            app_channel,
            len(self.merges),
        )
        mail = [
            '# Failed automated merge test',
            ''
        ]
        cmp_func = operator.attrgetter('bugzilla_id', 'branch')
        merges = sorted(self.merges, key=cmp_func)
        merges = itertools.groupby(merges, key=cmp_func)
        for keys, failures in merges:
            bz_id, branch = keys
            mail.append('## Bug [{0}](https://bugzil.la/{0}) - Uplift to {1}\n'.format(bz_id, _str(branch)))  # noqa
            for merge_test in failures:
                mail += [
                    _commit_report(revision, result)
                    for revision, result in merge_test.results.items()
                ]
            mail.append('')  # newline
        mail_md = '\n'.join(mail)

        # Send mail report to every mail address
        notify = get_service('notify')
        for email in self.emails:
            notify.email({
                'address': email,
                'subject': subject,
                'content': mail_md,
                'template': 'fullscreen',
            })
            logger.info('Sent report', to=email)
Esempio n. 12
0
File: api.py Progetto: tp-tc/shipit
def schedule_phase(name, phase):
    session = current_app.db.session
    try:
        phase = session.query(Phase).filter(
            Release.id == Phase.release_id).filter(
                Release.name == name).filter(Phase.name == phase).one()
    except NoResultFound:
        abort(404)

    # we must require scope which depends on product
    required_permission = f"{SCOPE_PREFIX}/schedule_phase/{phase.release.product}/{phase.name}"
    if not current_user.has_permissions(required_permission):
        user_permissions = ", ".join(current_user.get_permissions())
        abort(
            401,
            f"required permission: {required_permission}, user permissions: {user_permissions}"
        )

    if phase.submitted:
        abort(409, "Already submitted!")

    for signoff in phase.signoffs:
        if not signoff.signed:
            abort(400, "Pending signoffs")

    hook = phase.task_json

    if "hook_payload" not in hook:
        raise ValueError("Action tasks are not supported")

    hooks = get_service("hooks")
    client_id = hooks.options["credentials"]["clientId"].decode("utf-8")
    extra_context = {"clientId": client_id}
    result = hooks.triggerHook(
        hook["hook_group_id"], hook["hook_id"],
        phase.rendered_hook_payload(extra_context=extra_context))
    phase.task_id = result["status"]["taskId"]

    phase.submitted = True
    phase.completed_by = current_user.get_id()
    completed = datetime.datetime.utcnow()
    phase.completed = completed
    if all([ph.submitted for ph in phase.release.phases]):
        phase.release.status = "shipped"
        phase.release.completed = completed
    session.commit()

    root_url = hooks.options["rootUrl"]
    url = f"{root_url}/tasks/groups/{phase.task_id}"
    # TODO: Remove the condition after migration
    if root_url == "https://taskcluster.net":
        url = "https://tools.taskcluster.net/groups/{phase.task_id}"

    notify_via_irc(
        phase.release.product,
        f"Phase {phase.name} was just scheduled for release {phase.release.product} {phase.release.version} build{phase.release.build_number} - {url}",
    )

    return phase.json
Esempio n. 13
0
def abandon_release(name):
    session = current_app.db.session
    try:
        release = session.query(Release).filter(Release.name == name).one()

        # we must require scope which depends on product
        required_permission = f'{SCOPE_PREFIX}/abandon_release/{release.product}'
        if not current_user.has_permissions(required_permission):
            user_permissions = ', '.join(current_user.get_permissions())
            abort(
                401,
                f'required permission: {required_permission}, user permissions: {user_permissions}'
            )

        # Cancel all submitted task groups first
        for phase in filter(lambda x: x.submitted, release.phases):
            try:
                actions = fetch_actions_json(phase.task_id)
            except ActionsJsonNotFound:
                logger.info('Ignoring not completed action task %s',
                            phase.task_id)
                continue

            hook = generate_action_hook(
                task_group_id=phase.task_id,
                action_name='cancel-all',
                actions=actions,
                input_={},
            )
            hooks = get_service('hooks')
            client_id = hooks.options['credentials']['clientId'].decode(
                'utf-8')
            hook['context']['clientId'] = client_id
            hook_payload_rendered = render_action_hook(
                payload=hook['hook_payload'],
                context=hook['context'],
                delete_params=[
                    'existing_tasks', 'release_history',
                    'release_partner_config'
                ],
            )
            logger.info('Cancel phase %s by hook %s with payload: %s',
                        phase.name, hook['hook_id'], hook_payload_rendered)
            res = hooks.triggerHook(hook['hook_group_id'], hook['hook_id'],
                                    hook_payload_rendered)
            logger.debug('Done: %s', res)

        release.status = 'aborted'
        session.commit()
        release_json = release.json
    except NoResultFound:
        abort(404)

    notify_via_irc(
        release.product,
        f'Release {release.product} {release.version} build{release.build_number} was just canceled.'
    )

    return release_json
Esempio n. 14
0
    def post_github_status(self, commit_sha):
        if self.gecko_dev_user is None or self.gecko_dev_pwd is None:
            return

        tcGithub = get_service('github', self.client_id, self.access_token)
        tcGithub.createStatus('marco-c', 'gecko-dev', commit_sha, {
            'state': 'success',
        })
Esempio n. 15
0
 def __init__(self, cache_root, client_id, access_token):
     self.cache_root = cache_root
     self.gecko_dev_user = secrets.get(secrets.GECKO_DEV_USER)
     self.gecko_dev_pwd = secrets.get(secrets.GECKO_DEV_PWD)
     self.hg_git_mapper = secrets[secrets.HG_GIT_MAPPER] if secrets.HG_GIT_MAPPER in secrets else 'https://mapper.mozilla-releng.net'
     self.client_id = client_id
     self.access_token = access_token
     self.notify_service = get_service('notify', client_id, access_token)
Esempio n. 16
0
    def post_github_status(self, commit_sha):
        if self.gecko_dev_user is None or self.gecko_dev_pwd is None:
            return

        tcGithub = get_service('github', self.client_id, self.access_token)
        tcGithub.createStatus('marco-c', 'gecko-dev', commit_sha, {
            'state': 'success',
        })
Esempio n. 17
0
    def connect_taskcluster(self, client_id=None, access_token=None):
        '''
        Save hooks and queue services for later use
        '''
        # Get taskcluster hooks
        self.hooks = get_service('hooks', client_id, access_token)

        return True
Esempio n. 18
0
    def __init__(self, cache_root, client_id, access_token):
        self.cache_root = cache_root

        assert os.path.isdir(cache_root), 'Cache root {} is not a dir.'.format(cache_root)

        self.client_id = client_id
        self.access_token = access_token

        self.index_service = get_service('index', client_id, access_token)
Esempio n. 19
0
    def __init__(self, cache_root, client_id, access_token):
        self.cache_root = cache_root

        assert os.path.isdir(cache_root), 'Cache root {} is not a dir.'.format(cache_root)

        self.client_id = client_id
        self.access_token = access_token

        self.index_service = get_service('index', client_id, access_token)
Esempio n. 20
0
    def connect_taskcluster(self, client_id=None, access_token=None):
        '''
        Load the hook's task definition through Taskcluster
        Save queue service for later use
        '''
        logger.info('Loading task definition', hook=self.hook_id, group=self.group_id)  # noqa
        try:
            service = get_service('hooks', client_id, access_token)
            hook_payload = service.hook(self.group_id, self.hook_id)
            self.task_definition = hook_payload['task']
        except Exception as e:
            logger.warn('Failed to fetch task definition', hook=self.hook_id, group=self.group_id, err=e)  # noqa
            return False

        # Get taskcluster queue
        self.queue = get_service('queue', client_id, access_token)

        return True
Esempio n. 21
0
def find_decision_task_id(repo_url, project, revision, product):
    trust_domain = get_trust_domain(repo_url, project, product)
    if repo_url.startswith("https://github.com"):
        # XXX "project" is a gecko-centric term which is translated into a branch in the git world.
        branch = project
        decision_task_route = f"{trust_domain}.v2.branch.{branch}.revision.{revision}.taskgraph.decision"
    else:
        decision_task_route = f"{trust_domain}.v2.{project}.revision.{revision}.taskgraph.decision"
    index = get_service("index")
    return index.findTask(decision_task_route)["taskId"]
 def __init__(self, cache_root, client_id, access_token):
     self.cache_root = cache_root
     self.gecko_dev_user = secrets.get(secrets.GECKO_DEV_USER)
     self.gecko_dev_pwd = secrets.get(secrets.GECKO_DEV_PWD)
     self.hg_git_mapper = secrets[
         secrets.
         HG_GIT_MAPPER] if secrets.HG_GIT_MAPPER in secrets else 'https://mapper.mozilla-releng.net'
     self.client_id = client_id
     self.access_token = access_token
     self.notify_service = get_service('notify', client_id, access_token)
Esempio n. 23
0
    def __init__(self,
                 cache_root,
                 emails,
                 app_channel,
                 mozreview_api_root,
                 mozreview_enabled=False,
                 mozreview_publish_success=False,
                 client_id=None,
                 access_token=None):  # noqa
        self.emails = emails
        self.app_channel = app_channel
        self.mozreview_api_root = mozreview_api_root
        self.mozreview_enabled = mozreview_enabled
        self.mozreview_publish_success = mozreview_publish_success
        self.cache_root = cache_root
        assert os.path.isdir(self.cache_root), \
            'Cache root {} is not a dir.'.format(self.cache_root)
        assert 'MOZCONFIG' in os.environ, \
            'Missing MOZCONFIG in environment'

        # Save Taskcluster ID for logging
        if 'TASK_ID' in os.environ and 'RUN_ID' in os.environ:
            self.taskcluster_id = '{} run:{}'.format(
                os.environ['TASK_ID'],
                os.environ['RUN_ID'],
            )
        else:
            self.taskcluster_id = 'local instance'

        # Load TC services & secrets
        self.notify = get_service(
            'notify',
            client_id=client_id,
            access_token=access_token,
        )

        # Clone mozilla-central
        self.repo_dir = os.path.join(cache_root, 'central')
        shared_dir = os.path.join(cache_root, 'central-shared')
        logger.info('Clone mozilla central', dir=self.repo_dir)
        cmd = hglib.util.cmdbuilder('robustcheckout',
                                    REPO_CENTRAL,
                                    self.repo_dir,
                                    purge=True,
                                    sharebase=shared_dir,
                                    branch=b'tip')

        cmd.insert(0, hglib.HGPATH)
        proc = hglib.util.popen(cmd)
        out, err = proc.communicate()
        if proc.returncode:
            raise hglib.error.CommandError(cmd, proc.returncode, out, err)

        # Open new hg client
        self.hg = hglib.open(self.repo_dir)
Esempio n. 24
0
def fetch_actions_json(task_id):
    try:
        queue = get_service('queue')
        actions_url = queue.buildUrl('getLatestArtifact', task_id, 'public/actions.json')
        q = requests.get(actions_url)
        q.raise_for_status()
        return q.json()
    except requests.exceptions.HTTPError as e:
        if e.response.status_code == 404:
            raise ActionsJsonNotFound
        raise
Esempio n. 25
0
def fetch_artifact(task_id, artifact):
    try:
        queue = get_service('queue')
        url = queue.buildUrl('getLatestArtifact', task_id, artifact)
        q = requests.get(url)
        q.raise_for_status()
        return yaml.safe_load(q.text)
    except requests.exceptions.HTTPError as e:
        if e.response.status_code == 404:
            raise ArtifactNotFound
        raise
Esempio n. 26
0
def fetch_actions_json(task_id):
    try:
        queue = get_service('queue')
        actions_url = queue.buildUrl('getLatestArtifact', task_id,
                                     'public/actions.json')
        q = requests.get(actions_url)
        q.raise_for_status()
        return q.json()
    except requests.exceptions.HTTPError as e:
        if e.response.status_code == 404:
            raise ActionsJsonNotFound
        raise
Esempio n. 27
0
    def __init__(self, configuration, client_id, access_token):
        self.emails, = self.requires(configuration, 'emails')
        assert len(self.emails) > 0, 'Missing emails data'

        # Load TC services & secrets
        self.notify = get_service(
            'notify',
            client_id=client_id,
            access_token=access_token,
        )

        logger.info('Mail report enabled', emails=self.emails)
Esempio n. 28
0
    def __init__(self, repository, revision, cache_root, client_id, access_token):
        # List of test-suite, sorted alphabetically.
        # This way, the index of a suite in the array should be stable enough.
        self.suites = [
            'web-platform-tests',
        ]

        self.cache_root = cache_root

        temp_dir = tempfile.mkdtemp()
        self.artifacts_dir = os.path.join(temp_dir, 'ccov-artifacts')
        self.ccov_reports_dir = os.path.join(temp_dir, 'code-coverage-reports')

        self.client_id = client_id
        self.access_token = access_token

        self.index_service = get_service('index', client_id, access_token)

        self.githubUtils = GitHubUtils(cache_root, client_id, access_token)

        if revision is None:
            # Retrieve revision of latest codecov build
            self.github_revision = uploader.get_latest_codecov()
            self.repository = MOZILLA_CENTRAL_REPOSITORY
            self.revision = self.githubUtils.git_to_mercurial(self.github_revision)
            self.from_pulse = False
        else:
            self.github_revision = None
            self.repository = repository
            self.revision = revision
            self.from_pulse = True

        branch = self.repository[len(HG_BASE):]

        assert os.path.isdir(cache_root), 'Cache root {} is not a dir.'.format(cache_root)
        self.repo_dir = os.path.join(cache_root, branch)

        logger.info('Mercurial revision', revision=self.revision)

        task_ids = {}
        for platform in ['linux', 'windows', 'android-test', 'android-emulator']:
            task = taskcluster.get_task(branch, self.revision, platform)

            # On try, developers might have requested to run only one platform, and we trust them.
            # On mozilla-central, we want to assert that every platform was run (except for android platforms
            # as they are unstable).
            if task is not None:
                task_ids[platform] = task
            elif self.repository == MOZILLA_CENTRAL_REPOSITORY and not platform.startswith('android'):
                raise Exception('Code coverage build failed and was not indexed.')

        self.artifactsHandler = ArtifactsHandler(task_ids, self.artifacts_dir)
Esempio n. 29
0
    def __init__(self, revision, cache_root, client_id, access_token):
        # List of test-suite, sorted alphabetically.
        # This way, the index of a suite in the array should be stable enough.
        self.suites = [
            'web-platform-tests',
        ]

        self.cache_root = cache_root

        assert os.path.isdir(cache_root), 'Cache root {} is not a dir.'.format(
            cache_root)
        self.repo_dir = os.path.join(cache_root, 'mozilla-central')
        temp_dir = tempfile.mkdtemp()
        self.artifacts_dir = os.path.join(temp_dir, 'ccov-artifacts')
        self.ccov_reports_dir = os.path.join(temp_dir, 'code-coverage-reports')

        self.client_id = client_id
        self.access_token = access_token

        self.index_service = get_service('index', client_id, access_token)

        self.githubUtils = GitHubUtils(cache_root, client_id, access_token)

        if revision is None:
            # Retrieve revision of latest codecov build
            self.github_revision = uploader.get_latest_codecov()
            self.revision = self.githubUtils.git_to_mercurial(
                self.github_revision)
            self.from_pulse = False
        else:
            self.github_revision = None
            self.revision = revision
            self.from_pulse = True
            self.notifier = Notifier(self.repo_dir, revision, client_id,
                                     access_token)

        logger.info('Mercurial revision', revision=self.revision)

        task_ids = {
            'linux':
            taskcluster.get_task('mozilla-central', self.revision, 'linux'),
            'windows':
            taskcluster.get_task('mozilla-central', self.revision, 'win'),
            'android-test':
            taskcluster.get_task('mozilla-central', self.revision,
                                 'android-test'),
            'android-emulator':
            taskcluster.get_task('mozilla-central', self.revision,
                                 'android-emulator'),
        }

        self.artifactsHandler = ArtifactsHandler(task_ids, self.artifacts_dir)
Esempio n. 30
0
def abandon_release(name):
    session = g.db.session
    try:
        r = session.query(Release).filter(Release.name == name).one()
        # Cancel all submitted task groups first
        for phase in filter(lambda x: x.submitted, r.phases):
            try:
                actions = fetch_actions_json(phase.task_id)
            except ActionsJsonNotFound:
                logger.info('Ignoring not completed action task %s',
                            phase.task_id)
                continue

            hook = generate_action_hook(
                task_group_id=phase.task_id,
                action_name='cancel-all',
                actions=actions,
                input_={},
            )
            hooks = get_service('hooks')
            client_id = hooks.options['credentials']['clientId'].decode(
                'utf-8')
            hook['context']['clientId'] = client_id
            hook_payload_rendered = render_action_hook(
                payload=hook['hook_payload'],
                context=hook['context'],
                delete_params=[
                    'existing_tasks', 'release_history',
                    'release_partner_config'
                ],
            )
            logger.info('Cancel phase %s by hook %s with payload: %s',
                        phase.name, hook['hook_id'], hook_payload_rendered)
            res = hooks.triggerHook(hook['hook_group_id'], hook['hook_id'],
                                    hook_payload_rendered)
            logger.debug('Done: %s', res)

        r.status = 'aborted'
        session.commit()
        release = r.json
    except NoResultFound:
        abort(404)

    notify_via_irc(
        f'Release {r.product} {r.version} build{r.build_number} was just canceled.'
    )

    return release
Esempio n. 31
0
def trigger_task(task_group_id, commit):
    '''
    Trigger a code coverage task to build covdir at a specified revision
    '''
    assert 'mercurial' in commit
    name = 'covdir {} - {} - {}'.format(secrets[secrets.APP_CHANNEL],
                                        commit['timestamp'],
                                        commit['mercurial'])
    hooks = taskcluster.get_service('hooks')
    payload = {
        'REPOSITORY': MC_REPO,
        'REVISION': commit['mercurial'],
        'taskGroupId': task_group_id,
        'taskName': name,
    }
    hook_id = HOOK_ID.format(app_channel=secrets[secrets.APP_CHANNEL])
    return hooks.triggerHook(HOOK_GROUP, hook_id, payload)
Esempio n. 32
0
def main():
    # CLI args
    parser = argparse.ArgumentParser()
    parser.add_argument('--nb-tasks',
                        type=int,
                        default=5,
                        help='NB of tasks to create')
    parser.add_argument('--unique',
                        choices=('day', 'week'),
                        help='Trigger only one task per day or week')
    parser.add_argument('--group',
                        type=str,
                        default=slugId(),
                        help='Task group to create/update')
    parser.add_argument('--dry-run',
                        action='store_true',
                        default=False,
                        help='List actions without triggering any new task')
    args = parser.parse_args()

    # List existing tags & commits
    print('Group', args.group)
    queue = taskcluster.get_service('queue')
    try:
        group = queue.listTaskGroup(args.group)
        commits = [
            task['task']['payload']['env']['REVISION']
            for task in group['tasks']
            if task['status']['state'] not in ('failed', 'exception')
        ]
        print('Found {} commits processed in task group {}'.format(
            len(commits), args.group))
    except Exception as e:
        print('Invalid task group : {}'.format(e))
        commits = []

    # Trigger a task for each commit
    for commit in list_commits(args.nb_tasks, args.unique, commits):
        print(
            'Triggering commit {mercurial} from {timestamp}'.format(**commit))
        if args.dry_run:
            print('>>> No trigger on dry run')
        else:
            out = trigger_task(args.group, commit)
            print('>>>', out['status']['taskId'])
Esempio n. 33
0
    def __init__(self,
                 cache_root,
                 emails,
                 mozreview,
                 mozreview_enabled=False,
                 client_id=None,
                 access_token=None):  # noqa
        self.emails = emails
        self.mozreview = mozreview
        self.mozreview_enabled = mozreview_enabled
        self.cache_root = cache_root
        assert os.path.isdir(self.cache_root), \
            'Cache root {} is not a dir.'.format(self.cache_root)
        assert 'MOZCONFIG' in os.environ, \
            'Missing MOZCONFIG in environment'

        # Load TC services & secrets
        self.notify = get_service(
            'notify',
            client_id=client_id,
            access_token=access_token,
        )

        # Clone mozilla-central
        self.repo_dir = os.path.join(cache_root, 'central')
        shared_dir = os.path.join(cache_root, 'central-shared')
        logger.info('Clone mozilla central', dir=self.repo_dir)
        cmd = hglib.util.cmdbuilder('robustcheckout',
                                    REPO_CENTRAL,
                                    self.repo_dir,
                                    purge=True,
                                    sharebase=shared_dir,
                                    branch=b'tip')

        cmd.insert(0, hglib.HGPATH)
        proc = hglib.util.popen(cmd)
        out, err = proc.communicate()
        if proc.returncode:
            raise hglib.error.CommandError(cmd, proc.returncode, out, err)

        # Open new hg client
        self.hg = hglib.open(self.repo_dir)

        # Setup clang
        self.clang = ClangTidy(self.repo_dir, settings.target)
Esempio n. 34
0
def abandon_release(name):
    session = g.db.session
    try:
        r = session.query(Release).filter(Release.name == name).one()
        # Cancel all submitted task groups first
        for phase in filter(lambda x: x.submitted, r.phases):
            try:
                actions = fetch_actions_json(phase.task_id)
            except ActionsJsonNotFound:
                logger.info('Ignoring not completed action task %s',
                            phase.task_id)
                continue

            hook = generate_action_hook(
                decision_task_id=phase.task_id,
                action_name='cancel-all',
                actions=actions,
            )
            # some parameters contain a lot of entries, so we hit the payload
            # size limit. We don't use this parameter in any case, safe to
            # remove
            for long_param in ('existing_tasks', 'release_history',
                               'release_partner_config'):
                del hook['context']['parameters'][long_param]
            logger.info('Cancel phase %s by hook %s', phase.name, hook)
            hooks = get_service('hooks')
            res = hooks.triggerHook(hook['hook_group_id'], hook['hook_id'],
                                    hook['hook_payload'])
            logger.debug('Done: %s', res)

        r.status = 'aborted'
        session.commit()
        release = r.json
    except NoResultFound:
        abort(404)

    notify_via_irc(
        f'Release {r.product} {r.version} build{r.build_number} was just canceled.'
    )

    return release
Esempio n. 35
0
def do_schedule_phase(session, phase):
    if phase.submitted:
        abort(409, "Already submitted!")

    for signoff in phase.signoffs:
        if not signoff.signed:
            abort(400, "Pending signoffs")

    hook = phase.task_json
    hooks = get_service("hooks")
    client_id = hooks.options["credentials"]["clientId"].decode("utf-8")
    extra_context = {"clientId": client_id}
    try:
        result = hooks.triggerHook(
            hook["hook_group_id"], hook["hook_id"],
            phase.rendered_hook_payload(extra_context=extra_context))
        phase.task_id = result["status"]["taskId"]
    except TaskclusterRestFailure as e:
        abort(400, str(e))

    phase.submitted = True
    completed = datetime.datetime.utcnow()
    phase.completed_by = current_user.get_id()
    phase.completed = completed
    # If the previous phases are not submitted, mark them as submitted and they
    # will be calculated as skipped because they don't have taskId associated
    for ph in phase.release.phases:
        if ph.name == phase.name:
            break
        if not ph.submitted:
            ph.submitted = True
            ph.completed_by = current_user.get_id()
            ph.completed = completed

    session.commit()
    return phase
Esempio n. 36
0
 def __init__(self, repo_dir, revision, client_id, access_token):
     self.repo_dir = repo_dir
     self.revision = revision
     self.notify_service = get_service('notify', client_id, access_token)
Esempio n. 37
0
def find_decision_task_id(project, revision):
    decision_task_route = f'{get_trust_domain(project)}.v2.{project}.revision.{revision}.taskgraph.decision'
    index = get_service('index')
    return index.findTask(decision_task_route)['taskId']
Esempio n. 38
0
 def __init__(self, repo_dir, revision, client_id, access_token):
     self.repo_dir = repo_dir
     self.revision = revision
     self.notify_service = get_service('notify', client_id, access_token)
Esempio n. 39
0
def find_decision_task_id(project, revision):
    decision_task_route = f'{get_trust_domain(project)}.v2.{project}.revision.{revision}.taskgraph.decision'
    index = get_service('index')
    return index.findTask(decision_task_route)['taskId']