def phabricator_base_revision_from_phid(revision_phid):
    try:
        phabricator = PhabricatorAPI(secrets.PHABRICATOR_TOKEN)
        diffs = phabricator.search_diffs(revision_phid=revision_phid)
        if len(diffs) > 0:
            revision = diffs[-1]['baseRevision']
            if revision and revision_exists_on_central(revision):
                return {'revision': revision}, 200
        return {'error': 'Base revision not found.'}, 404
    except Exception as e:
        return {
            'error': str(e),
            'error_code': getattr(e, 'error_code', 'unknown')
        }, 500
Exemplo n.º 2
0
class HookPhabricator(Hook):
    '''
    Taskcluster hook handling the static analysis
    for Phabricator differentials
    '''
    latest_id = None

    def __init__(self, configuration):
        assert 'hookId' in configuration
        super().__init__(
            'project-releng',
            configuration['hookId'],
        )

        # Connect to Phabricator API
        assert 'phabricator_url' in configuration
        assert 'phabricator_token' in configuration
        self.api = PhabricatorAPI(
            api_key=configuration['phabricator_token'],
            url=configuration['phabricator_url'],
        )

        # List enabled repositories
        enabled = configuration.get('repositories', [
            'mozilla-central',
        ])
        self.repos = {
            r['phid']: r
            for r in self.api.list_repositories()
            if r['fields']['name'] in enabled
        }
        assert len(self.repos) > 0, 'No repositories enabled'
        logger.info('Enabled Phabricator repositories',
                    repos=[r['fields']['name'] for r in self.repos.values()])

        # Start by getting top id
        diffs = self.api.search_diffs(limit=1)
        assert len(diffs) == 1
        self.latest_id = diffs[0]['id']

    def list_differential(self):
        '''
        List new differential items using pagination
        using an iterator
        '''
        cursor = self.latest_id
        while cursor is not None:
            diffs, cursor = self.api.search_diffs(
                order='oldest',
                limit=20,
                after=self.latest_id,
                output_cursor=True,
            )
            if not diffs:
                break

            for diff in diffs:
                yield diff

            # Update the latest id
            if cursor and cursor['after']:
                self.latest_id = cursor['after']
            elif len(diffs) > 0:
                self.latest_id = diffs[-1]['id']

    async def build_consumer(self, *args, **kwargs):
        '''
        Query phabricator differentials regularly
        '''
        while True:

            # Get new differential ids
            for diff in self.list_differential():
                if diff['type'] != 'DIFF':
                    logger.info('Skipping differential, not a diff',
                                id=diff['id'],
                                type=diff['type'])
                    continue

                # Load revision to check the repository is authorized
                rev = self.api.load_revision(diff['revisionPHID'])
                repo_phid = rev['fields']['repositoryPHID']
                if repo_phid not in self.repos:
                    logger.info('Skipping differential, repo not enabled',
                                id=diff['id'],
                                repo=repo_phid)
                    continue

                # Create new task
                await self.create_task({
                    'ANALYSIS_SOURCE': 'phabricator',
                    'ANALYSIS_ID': diff['phid']
                })

            # Sleep a bit before trying new diffs
            await asyncio.sleep(60)