Exemple #1
0
    def test_populate_not_build_all(self):
        self.env.get_repository = lambda authname=None: Mock(
            get_changeset=lambda rev: Mock(date=to_datetime(rev * 1000, utc)),
            get_node=lambda path, rev=None: Mock(
                get_entries=lambda: [Mock(), Mock()],
                get_history=lambda: [('somepath', 123, 'edit'),
                                     ('somepath', 121, 'edit'),
                                     ('somepath', 120, 'edit')]
            ),
            normalize_path=lambda path: path,
            rev_older_than=lambda rev1, rev2: rev1 < rev2
        )
        BuildConfig(self.env, 'test', path='somepath', active=True).insert()
        platform1 = TargetPlatform(self.env, config='test', name='P1')
        platform1.insert()
        platform2 = TargetPlatform(self.env, config='test', name='P2')
        platform2.insert()

        queue = BuildQueue(self.env)
        queue.populate()
        queue.populate()
        queue.populate()

        builds = list(Build.select(self.env, config='test'))
        builds.sort(lambda a, b: cmp(a.platform, b.platform))
        self.assertEqual(2, len(builds))
        self.assertEqual(platform1.id, builds[0].platform)
        self.assertEqual('123', builds[0].rev)
        self.assertEqual(platform2.id, builds[1].platform)
        self.assertEqual('123', builds[1].rev)
Exemple #2
0
    def should_delete_build(self, build, repos):
        config = BuildConfig.fetch(self.env, build.config)

        platform = TargetPlatform.fetch(self.env, build.platform)
        # Platform may or may not exist anymore - get safe name for logging
        platform_name = platform and platform.name \
                        or 'unknown platform "%s"' % build.platform

        # Drop build if platform no longer exists
        if not platform:
            self.log.info(
                'Dropping build of configuration "%s" at '
                'revision [%s] on %s because the platform no longer '
                'exists', config.name, build.rev, platform_name)
            return True

        # Ignore pending builds for deactived build configs
        if not config.active:
            self.log.info(
                'Dropping build of configuration "%s" at '
                'revision [%s] on %s because the configuration is '
                'deactivated', config.name, build.rev, platform_name)
            return True

        # If not 'build_all', drop if a more recent revision is available
        if not self.build_all and \
                len(list(Build.select(self.env, config=build.config,
                min_rev_time=build.rev_time, platform=build.platform))) > 1:
            self.log.info(
                'Dropping build of configuration "%s" at revision [%s] '
                'on "%s" because a more recent build exists', config.name,
                build.rev, platform_name)
            return True

        return False
Exemple #3
0
    def get_annotation_data(self, context):
        add_stylesheet(context.req, 'bitten/bitten_coverage.css')

        resource = context.resource
        self.log.debug("Looking for coverage report for %s@%s..." % (
                        resource.id, str(resource.version)))
        builds = Build.select(self.env, rev=resource.version)
        reports = []
        for build in builds:
            config = BuildConfig.fetch(self.env, build.config)
            if not resource.id.startswith(config.branch):
                continue
            reports = Report.select(self.env, build=build.id,
                                    category='coverage')
            branch_in_config = resource.id[len(config.branch):]
            for report in reports:
                for item in report.items:
                    if item.get('file') == branch_in_config:
                        coverage = item.get('line_hits', '').split()
                        if coverage:
                            # Return first result with line data
                            self.log.debug(
                                "Coverage annotate for %s@%s: %s" % \
                                (resource.id, resource.version, coverage))
                            return coverage
        return []
Exemple #4
0
    def reset_orphaned_builds(self):
        """Reset all in-progress builds to ``PENDING`` state if they've been
        running so long that the configured timeout has been reached.
        
        This is used to cleanup after slaves that have unexpectedly cancelled
        a build without notifying the master, or are for some other reason not
        reporting back status updates.
        """
        if not self.timeout:
            # If no timeout is set, none of the in-progress builds can be
            # considered orphaned
            return

        db = self.env.get_db_cnx()
        now = int(time.time())
        for build in Build.select(self.env, status=Build.IN_PROGRESS, db=db):
            if now - build.started < self.timeout:
                # This build has not reached the timeout yet, assume it's still
                # being executed
                # FIXME: ideally, we'd base this check on the last activity on
                #        the build, not the start time
                continue
            build.status = Build.PENDING
            build.slave = None
            build.slave_info = {}
            build.started = 0
            for step in list(BuildStep.select(self.env, build=build.id, db=db)):
                step.delete(db=db)
            build.update(db=db)
        db.commit()
Exemple #5
0
    def reset_orphaned_builds(self):
        """Reset all in-progress builds to ``PENDING`` state if they've been
        running so long that the configured timeout has been reached.
        
        This is used to cleanup after slaves that have unexpectedly cancelled
        a build without notifying the master, or are for some other reason not
        reporting back status updates.
        """
        if not self.timeout:
            # If no timeout is set, none of the in-progress builds can be
            # considered orphaned
            return

        db = self.env.get_db_cnx()
        now = int(time.time())
        for build in Build.select(self.env, status=Build.IN_PROGRESS, db=db):
            if now - build.started < self.timeout:
                # This build has not reached the timeout yet, assume it's still
                # being executed
                # FIXME: ideally, we'd base this check on the last activity on
                #        the build, not the start time
                continue
            build.status = Build.PENDING
            build.slave = None
            build.slave_info = {}
            build.started = 0
            for step in list(BuildStep.select(self.env, build=build.id,
                                              db=db)):
                step.delete(db=db)
            build.update(db=db)
        db.commit()
Exemple #6
0
    def should_delete_build(self, build, repos):
        config = BuildConfig.fetch(self.env, build.config)

        platform = TargetPlatform.fetch(self.env, build.platform)
        # Platform may or may not exist anymore - get safe name for logging
        platform_name = platform and platform.name \
                        or 'unknown platform "%s"' % build.platform

        # Drop build if platform no longer exists
        if not platform:
            self.log.info('Dropping build of configuration "%s" at '
                     'revision [%s] on %s because the platform no longer '
                     'exists', config.name, build.rev, platform_name)
            return True

        # Ignore pending builds for deactived build configs
        if not config.active:
            self.log.info('Dropping build of configuration "%s" at '
                     'revision [%s] on %s because the configuration is '
                     'deactivated', config.name, build.rev, platform_name)
            return True

        # If not 'build_all', drop if a more recent revision is available
        if not self.build_all and \
                len(list(Build.select(self.env, config=build.config,
                min_rev_time=build.rev_time, platform=build.platform))) > 1:
            self.log.info('Dropping build of configuration "%s" at revision [%s] '
                     'on "%s" because a more recent build exists',
                         config.name, build.rev, platform_name)
            return True

        return False
Exemple #7
0
 def getBuilds(self,
               req,
               config=None,
               rev=None,
               platform=None,
               slave=None,
               status=None):
     """Retrieve a list of builds that match the selected criteria, with all build properties
     """
     builds = []
     for build in Build.select(self.env,
                               config=config or None,
                               rev=rev or None,
                               platform=platform or None,
                               slave=slave or None,
                               status=status or None):
         if not build:
             continue
         builds.append({
             'id': build.id,
             'config': build.config,
             'rev': build.rev,
             'platform': build.platform,
             'slave': build.slave,
             'started': build.started,
             'stopped': build.stopped,
             'last_activity': build.last_activity,
             'rev_time': build.rev_time,
             'status': build.status,
         })
     return builds
Exemple #8
0
    def test_populate_not_build_all(self):
        self.env.get_repository = lambda authname=None: Mock(
            get_changeset=lambda rev: Mock(date=to_datetime(rev * 1000, utc)),
            get_node=lambda path, rev=None: Mock(
                get_entries=lambda: [Mock(), Mock()],
                get_history=lambda: [('somepath', 123, 'edit'),
                                     ('somepath', 121, 'edit'),
                                     ('somepath', 120, 'edit')]
            ),
            normalize_path=lambda path: path,
            rev_older_than=lambda rev1, rev2: rev1 < rev2
        )
        BuildConfig(self.env, 'test', path='somepath', active=True).insert()
        platform1 = TargetPlatform(self.env, config='test', name='P1')
        platform1.insert()
        platform2 = TargetPlatform(self.env, config='test', name='P2')
        platform2.insert()

        queue = BuildQueue(self.env)
        queue.populate()
        queue.populate()
        queue.populate()

        builds = list(Build.select(self.env, config='test'))
        builds.sort(lambda a, b: cmp(a.platform, b.platform))
        self.assertEqual(2, len(builds))
        self.assertEqual(platform1.id, builds[0].platform)
        self.assertEqual('123', builds[0].rev)
        self.assertEqual(platform2.id, builds[1].platform)
        self.assertEqual('123', builds[1].rev)
    def get_annotation_data(self, context):
        """add annotation data for lint"""

        context.perm.require('BUILD_VIEW')

        add_stylesheet(context.req, 'bitten/bitten_coverage.css')
        add_stylesheet(context.req, 'bitten/bitten_lintannotator.css')

        resource = context.resource

        # attempt to use the version passed in with the request,
        # otherwise fall back to the latest version of this file.
        try:
            version = context.req.args['rev']
        except (KeyError, TypeError):
            version = resource.version
            self.log.debug('no version passed to get_annotation_data')

        builds = Build.select(self.env, rev=version)

        self.log.debug("Looking for lint report for %s@%s [%s]..." %
                       (resource.id, str(resource.version), version))

        self.itemid = 0
        data = {}
        reports = None
        for build in builds:
            config = BuildConfig.fetch(self.env, build.config)
            if not resource.id.lstrip('/').startswith(config.path.lstrip('/')):
                self.log.debug('Skip build %s' % build)
                continue
            path_in_config = resource.id[len(config.path) + 1:].lstrip('/')
            reports = Report.select(self.env, build=build.id, category='lint')
            for report in reports:
                for item in report.items:
                    if item.get('file') == path_in_config:
                        line = item.get('line')
                        if line:
                            problem = {
                                'category': item.get('category', ''),
                                'tag': item.get('tag', ''),
                                'bid': build.id,
                                'rbuild': report.build,
                                'rstep': report.step,
                                'rid': report.id
                            }
                            data.setdefault(int(line), []).append(problem)
        if data:
            self.log.debug("Lint annotate for %s@%s: %s results" % \
                (resource.id, resource.version, len(data)))
            return data
        if not builds:
            self.log.debug("No builds found")
        elif not reports:
            self.log.debug("No reports found")
        else:
            self.log.debug("No item of any report matched (%s)" % reports)
        return None
Exemple #10
0
    def get_annotation_data(self, context):
        """add annotation data for lint"""

        context.perm.require('BUILD_VIEW')

        add_stylesheet(context.req, 'bitten/bitten_coverage.css')
        add_stylesheet(context.req, 'bitten/bitten_lintannotator.css')

        resource = context.resource

        # attempt to use the version passed in with the request,
        # otherwise fall back to the latest version of this file.
        try:
            version = context.req.args['rev']
        except (KeyError, TypeError):
            version = resource.version
            self.log.debug('no version passed to get_annotation_data')

        builds = Build.select(self.env, rev=version)

        self.log.debug("Looking for lint report for %s@%s [%s]..." % (
                        resource.id, str(resource.version), version))

        self.itemid = 0
        data = {}
        reports = None
        for build in builds:
            config = BuildConfig.fetch(self.env, build.config)
            if not resource.id.lstrip('/').startswith(config.path.lstrip('/')):
                self.log.debug('Skip build %s' % build)
                continue
            path_in_config = resource.id[len(config.path)+1:].lstrip('/')
            reports = Report.select(self.env, build=build.id, category='lint')
            for report in reports:
                for item in report.items:
                    if item.get('file') == path_in_config:
                        line = item.get('line')
                        if line:
                            problem = {'category': item.get('category', ''),
                                       'tag': item.get('tag', ''),
                                       'bid': build.id,
                                       'rbuild': report.build,
                                       'rstep': report.step, 'rid': report.id}
                            data.setdefault(int(line), []).append(problem)
        if data:
            self.log.debug("Lint annotate for %s@%s: %s results" % \
                (resource.id, resource.version, len(data)))
            return data
        if not builds:
            self.log.debug("No builds found")
        elif not reports:
            self.log.debug("No reports found")
        else:
            self.log.debug("No item of any report matched (%s)" % reports)
        return None
Exemple #11
0
    def test_populate_thread_race_condition(self):
        messages = []
        self.env.log = Mock(info=lambda msg, *args: messages.append(msg))

        def get_history():
            yield ('somepath', 123, 'edit')
            yield ('somepath', 121, 'edit')
            yield ('somepath', 120, 'edit')
            time.sleep(1)  # sleep to make sure both threads collect

        self.env.get_repository = lambda authname=None: Mock(
            get_changeset=lambda rev: Mock(date=to_datetime(rev * 1000, utc)),
            get_node=lambda path, rev=None: Mock(
                get_entries=lambda: [Mock(), Mock()], get_history=get_history),
            normalize_path=lambda path: path,
            rev_older_than=lambda rev1, rev2: rev1 < rev2)
        BuildConfig(self.env, 'test', path='somepath', active=True).insert()
        platform1 = TargetPlatform(self.env, config='test', name='P1')
        platform1.insert()
        platform2 = TargetPlatform(self.env, config='test', name='P2')
        platform2.insert()

        def build_populator():
            queue = BuildQueue(self.env, build_all=True)
            queue.populate()

        thread1 = threading.Thread(target=build_populator)
        thread2 = threading.Thread(target=build_populator)
        thread1.start()
        thread2.start()
        thread1.join()
        thread2.join()

        # check builds got added
        builds = list(Build.select(self.env, config='test'))
        builds.sort(lambda a, b: cmp(a.platform, b.platform))
        self.assertEqual(6, len(builds))
        self.assertEqual(platform1.id, builds[0].platform)
        self.assertEqual('123', builds[0].rev)
        self.assertEqual(platform1.id, builds[1].platform)
        self.assertEqual('121', builds[1].rev)
        self.assertEqual(platform1.id, builds[2].platform)
        self.assertEqual('120', builds[2].rev)
        self.assertEqual(platform2.id, builds[3].platform)
        self.assertEqual('123', builds[3].rev)
        self.assertEqual(platform2.id, builds[4].platform)
        self.assertEqual('121', builds[4].rev)
        self.assertEqual(platform2.id, builds[5].platform)
        self.assertEqual('120', builds[5].rev)

        # check attempts at duplicate inserts were logged.
        failure_messages = [
            x for x in messages if x.startswith('Failed to insert build')
        ]
        self.assertEqual(6, len(failure_messages))
Exemple #12
0
    def test_delete_platform_with_pending_builds(self):
        """Check that deleting a platform with pending builds removes those pending builds"""
        db = self.env.get_db_cnx()
        platform = TargetPlatform(self.env, config='test', name='Linux')
        platform.insert()
        build = Build(self.env, config='test', platform=platform.id, rev='42', rev_time=12039)
        build.insert()

        platform.delete()
        pending = list(build.select(self.env, config='test', status=Build.PENDING))
        self.assertEqual(0, len(pending))
Exemple #13
0
    def test_populate_thread_race_condition(self):
        messages = []
        self.env.log = Mock(info=lambda msg, *args: messages.append(msg))
        def get_history():
            yield ('somepath', 123, 'edit')
            yield ('somepath', 121, 'edit')
            yield ('somepath', 120, 'edit')
            time.sleep(1) # sleep to make sure both threads collect
        self.repos.get_changeset=lambda rev: Mock(
                                        date=to_datetime(rev * 1000, utc))
        self.repos.get_node=lambda path, rev=None: Mock(
                get_entries=lambda: [Mock(), Mock()],
                get_history=get_history)
        self.repos.normalize_path=lambda path: path
        self.repos.rev_older_than=lambda rev1, rev2: rev1 < rev2
        
        BuildConfig(self.env, 'test', path='somepath', active=True).insert()
        platform1 = TargetPlatform(self.env, config='test', name='P1')
        platform1.insert()
        platform2 = TargetPlatform(self.env, config='test', name='P2')
        platform2.insert()

        def build_populator():
            queue = BuildQueue(self.env, build_all=True)
            queue.populate()

        thread1 = threading.Thread(target=build_populator)
        thread2 = threading.Thread(target=build_populator)
        # tiny sleep is to avoid odd segementation faults
        # (on Linux) and bus errors (on Mac OS X)
        thread1.start(); time.sleep(0.01); thread2.start()
        thread1.join(); thread2.join()

        # check builds got added
        builds = list(Build.select(self.env, config='test'))
        builds.sort(lambda a, b: cmp(a.platform, b.platform))
        self.assertEqual(6, len(builds))
        self.assertEqual(platform1.id, builds[0].platform)
        self.assertEqual('123', builds[0].rev)
        self.assertEqual(platform1.id, builds[1].platform)
        self.assertEqual('121', builds[1].rev)
        self.assertEqual(platform1.id, builds[2].platform)
        self.assertEqual('120', builds[2].rev)
        self.assertEqual(platform2.id, builds[3].platform)
        self.assertEqual('123', builds[3].rev)
        self.assertEqual(platform2.id, builds[4].platform)
        self.assertEqual('121', builds[4].rev)
        self.assertEqual(platform2.id, builds[5].platform)
        self.assertEqual('120', builds[5].rev)

        # check attempts at duplicate inserts were logged.
        failure_messages = [x for x in messages if x.startswith('Failed to insert build')]
        self.assertEqual(6, len(failure_messages))
Exemple #14
0
    def get_build_for_slave(self, name, properties):
        """Check whether one of the pending builds can be built by the build
        slave.
        
        :param name: the name of the slave
        :type name: `basestring`
        :param properties: the slave configuration
        :type properties: `dict`
        :return: the allocated build, or `None` if no build was found
        :rtype: `Build`
        """
        self.log.debug('Checking for pending builds...')

        db = self.env.get_db_cnx()
        repos = self.env.get_repository()
        assert repos, 'No "(default)" Repository: Add a repository or alias ' \
                      'named "(default)" to Trac.'

        self.reset_orphaned_builds()

        # Iterate through pending builds by descending revision timestamp, to
        # avoid the first configuration/platform getting all the builds
        platforms = [p.id for p in self.match_slave(name, properties)]
        builds_to_delete = []
        build_found = False
        for build in Build.select(self.env, status=Build.PENDING, db=db):
            if self.should_delete_build(build, repos):
                self.log.info('Scheduling build %d for deletion', build.id)
                builds_to_delete.append(build)
            elif build.platform in platforms:
                build_found = True
                break
        if not build_found:
            self.log.debug('No pending builds.')
            build = None

        # delete any obsolete builds
        for build_to_delete in builds_to_delete:
            build_to_delete.delete(db=db)

        if build:
            build.slave = name
            build.slave_info.update(properties)
            build.status = Build.IN_PROGRESS
            build.update(db=db)

        if build or builds_to_delete:
            db.commit()

        return build
Exemple #15
0
    def get_build_for_slave(self, name, properties):
        """Check whether one of the pending builds can be built by the build
        slave.
        
        :param name: the name of the slave
        :type name: `basestring`
        :param properties: the slave configuration
        :type properties: `dict`
        :return: the allocated build, or `None` if no build was found
        :rtype: `Build`
        """
        self.log.debug('Checking for pending builds...')

        db = self.env.get_db_cnx()
        repos = self.env.get_repository()
        assert repos, 'No "(default)" Repository: Add a repository or alias ' \
                      'named "(default)" to Trac.'

        self.reset_orphaned_builds()

        # Iterate through pending builds by descending revision timestamp, to
        # avoid the first configuration/platform getting all the builds
        platforms = [p.id for p in self.match_slave(name, properties)]
        builds_to_delete = []
        build_found = False
        for build in Build.select(self.env, status=Build.PENDING, db=db):
            if self.should_delete_build(build, repos):
                self.log.info('Scheduling build %d for deletion', build.id)
                builds_to_delete.append(build)
            elif build.platform in platforms:
                build_found = True
                break
        if not build_found:
            self.log.debug('No pending builds.')
            build = None

        # delete any obsolete builds
        for build_to_delete in builds_to_delete:
            build_to_delete.delete(db=db)

        if build:
            build.slave = name
            build.slave_info.update(properties)
            build.status = Build.IN_PROGRESS
            build.update(db=db)

        if build or builds_to_delete:
            db.commit()

        return build
Exemple #16
0
    def should_delete_build(self, build, repos):
        config = BuildConfig.fetch(self.env, build.config)
        config_name = config and config.name \
                        or 'unknown config "%s"' % build.config

        platform = TargetPlatform.fetch(self.env, build.platform)
        # Platform may or may not exist anymore - get safe name for logging
        platform_name = platform and platform.name \
                        or 'unknown platform "%s"' % build.platform

        # Drop build if platform no longer exists
        if not platform:
            self.log.info(
                'Dropping build of configuration "%s" at '
                'revision [%s] on %s because the platform no longer '
                'exists', config.name, build.rev, platform_name)
            return True

        # Ignore pending builds for deactived build configs
        if not (config and config.active):
            self.log.info(
                'Dropping build of configuration "%s" at '
                'revision [%s] on %s because the configuration is '
                'deactivated', config_name, build.rev, platform_name)
            return True

        # Stay within the revision limits of the build config
        if (config.min_rev and repos.rev_older_than(build.rev,
                                                    config.min_rev)) \
        or (config.max_rev and repos.rev_older_than(config.max_rev,
                                                    build.rev)):
            self.log.info(
                'Dropping build of configuration "%s" at revision [%s] on '
                '"%s" because it is outside of the revision range of the '
                'configuration', config.name, build.rev, platform_name)
            return True

        # If not 'build_all', drop if a more recent revision is available
        if not self.build_all and \
                len(list(Build.select(self.env, config=build.config,
                min_rev_time=build.rev_time, platform=build.platform))) > 1:
            self.log.info(
                'Dropping build of configuration "%s" at revision [%s] '
                'on "%s" because a more recent build exists', config.name,
                build.rev, platform_name)
            return True

        return False
Exemple #17
0
 def getBuildIds(self,
                 req,
                 config=None,
                 rev=None,
                 platform=None,
                 slave=None,
                 status=None):
     """Retrieve a list of build unique identifiers that match the selected criteria
     """
     return [
         build.id for build in Build.select(self.env,
                                            config=config or None,
                                            rev=rev or None,
                                            platform=platform or None,
                                            slave=slave or None,
                                            status=status or None) if build
     ]
Exemple #18
0
    def should_delete_build(self, build, repos):
        config = BuildConfig.fetch(self.env, build.config)
        config_name = config and config.name \
                        or 'unknown config "%s"' % build.config

        platform = TargetPlatform.fetch(self.env, build.platform)
        # Platform may or may not exist anymore - get safe name for logging
        platform_name = platform and platform.name \
                        or 'unknown platform "%s"' % build.platform

        # Drop build if platform no longer exists
        if not platform:
            self.log.info('Dropping build of configuration "%s" at '
                     'revision [%s] on %s because the platform no longer '
                     'exists', config.name, build.rev, platform_name)
            return True

        # Ignore pending builds for deactived build configs
        if not (config and config.active):
            self.log.info('Dropping build of configuration "%s" at '
                     'revision [%s] on %s because the configuration is '
                     'deactivated', config_name, build.rev, platform_name)
            return True

        # Stay within the revision limits of the build config
        if (config.min_rev and repos.rev_older_than(build.rev,
                                                    config.min_rev)) \
        or (config.max_rev and repos.rev_older_than(config.max_rev,
                                                    build.rev)):
            self.log.info('Dropping build of configuration "%s" at revision [%s] on '
                     '"%s" because it is outside of the revision range of the '
                     'configuration', config.name, build.rev, platform_name)
            return True

        # If not 'build_all', drop if a more recent revision is available
        if not self.build_all and \
                len(list(Build.select(self.env, config=build.config,
                min_rev_time=build.rev_time, platform=build.platform))) > 1:
            self.log.info('Dropping build of configuration "%s" at revision [%s] '
                     'on "%s" because a more recent build exists',
                         config.name, build.rev, platform_name)
            return True

        return False
Exemple #19
0
        def get_annotation_data(self, context):
            add_stylesheet(context.req, 'bitten/bitten_coverage.css')

            resource = context.resource
            builds = Build.select(self.env, rev=resource.version)
            reports = []
            for build in builds:
                config = BuildConfig.fetch(self.env, build.config)
                if not resource.id.startswith(config.path):
                    continue
                reports = Report.select(self.env, build=build.id,
                                        category='coverage')
                path_in_config = resource.id[len(config.path):].lstrip('/')
                for report in reports:
                    for item in report.items:
                        if item.get('file') == path_in_config:
                            # TODO should aggregate coverage across builds
                            return item.get('line_hits', '').split()
            return []
Exemple #20
0
 def getBuilds(self, req, config=None, rev=None, platform=None, slave=None, status=None):
     """Retrieve a list of builds that match the selected criteria, with all build properties
     """
     builds = []
     for build in Build.select(self.env, config=config or None, rev=rev or None,
                               platform=platform or None, slave=slave or None,
                               status=status or None):
         if not build:
             continue
         builds.append({
             'id': build.id,
             'config': build.config,
             'rev': build.rev,
             'platform': build.platform,
             'slave': build.slave,
             'started': build.started,
             'stopped': build.stopped,
             'last_activity': build.last_activity,
             'rev_time': build.rev_time,
             'status': build.status,
         })
     return builds
Exemple #21
0
    def reset_orphaned_builds(self):
        """Reset all in-progress builds to ``PENDING`` state if they've been
        running so long that the configured timeout has been reached.
        
        This is used to cleanup after slaves that have unexpectedly cancelled
        a build without notifying the master, or are for some other reason not
        reporting back status updates.
        """
        if not self.timeout:
            # If no timeout is set, none of the in-progress builds can be
            # considered orphaned
            return

        db = self.env.get_db_cnx()
        now = int(time.time())
        for build in Build.select(self.env, status=Build.IN_PROGRESS, db=db):
            if now - build.last_activity < self.timeout:
                # This build has not reached the timeout yet, assume it's still
                # being executed
                continue

            self.log.info('Orphaning build %d. Last activity was %s (%s)' % \
                              (build.id, format_datetime(build.last_activity),
                               pretty_timedelta(build.last_activity)))

            build.status = Build.PENDING
            build.slave = None
            build.slave_info = {}
            build.started = 0
            build.stopped = 0
            build.last_activity = 0
            for step in list(BuildStep.select(self.env, build=build.id,
                                              db=db)):
                step.delete(db=db)
            build.update(db=db)

            Attachment.delete_all(self.env, 'build', build.resource.id, db)
        db.commit()
Exemple #22
0
    def reset_orphaned_builds(self):
        """Reset all in-progress builds to ``PENDING`` state if they've been
        running so long that the configured timeout has been reached.
        
        This is used to cleanup after slaves that have unexpectedly cancelled
        a build without notifying the master, or are for some other reason not
        reporting back status updates.
        """
        if not self.timeout:
            # If no timeout is set, none of the in-progress builds can be
            # considered orphaned
            return

        db = self.env.get_db_cnx()
        now = int(time.time())
        for build in Build.select(self.env, status=Build.IN_PROGRESS, db=db):
            if now - build.last_activity < self.timeout:
                # This build has not reached the timeout yet, assume it's still
                # being executed
                continue

            self.log.info('Orphaning build %d. Last activity was %s (%s)' % \
                              (build.id, format_datetime(build.last_activity),
                               pretty_timedelta(build.last_activity)))

            build.status = Build.PENDING
            build.slave = None
            build.slave_info = {}
            build.started = 0
            build.stopped = 0
            build.last_activity = 0
            for step in list(BuildStep.select(self.env, build=build.id, db=db)):
                step.delete(db=db)
            build.update(db=db)

            Attachment.delete_all(self.env, 'build', build.resource.id, db)
        db.commit()
Exemple #23
0
    def _render_overview(self, req):
        data = {'title': 'Build Status'}
        show_all = False
        if req.args.get('show') == 'all':
            show_all = True
        data['show_all'] = show_all

        repos = self.env.get_repository(authname=req.authname)
        assert repos, 'No "(default)" Repository: Add a repository or alias ' \
                      'named "(default)" to Trac.'

        configs = []
        for config in BuildConfig.select(self.env, include_inactive=show_all):
            rev = config.max_rev or repos.youngest_rev
            try:
                if not _has_permission(req.perm, repos, config.path, rev=rev):
                    continue
            except NoSuchNode:
                add_warning(req, "Configuration '%s' points to non-existing "
                        "path '/%s' at revision '%s'. Configuration skipped." \
                                    % (config.name, config.path, rev))
                continue

            description = config.description
            if description:
                description = wiki_to_html(description, self.env, req)

            platforms_data = []
            for platform in TargetPlatform.select(self.env, config=config.name):
                pd = { 'name': platform.name,
                       'id': platform.id,
                       'builds_pending': len(list(Build.select(self.env,
                                config=config.name, status=Build.PENDING,
                                platform=platform.id))),
                       'builds_inprogress': len(list(Build.select(self.env,
                                config=config.name, status=Build.IN_PROGRESS,
                                platform=platform.id)))
                }
                platforms_data.append(pd)

            config_data = {
                'name': config.name, 'label': config.label or config.name,
                'active': config.active, 'path': config.path,
                'description': description,
                'builds_pending' : len(list(Build.select(self.env,
                                                config=config.name,
                                                status=Build.PENDING))),
                'builds_inprogress' : len(list(Build.select(self.env,
                                                config=config.name,
                                                status=Build.IN_PROGRESS))),
                'href': req.href.build(config.name),
                'builds': [],
                'platforms': platforms_data
            }
            configs.append(config_data)
            if not config.active:
                continue

            prev_rev = None
            for platform, rev, build in collect_changes(repos, config):
                if rev != prev_rev:
                    if prev_rev is None:
                        chgset = repos.get_changeset(rev)
                        config_data['youngest_rev'] = {
                            'id': rev, 'href': req.href.changeset(rev),
                            'display_rev': repos.normalize_rev(rev),
                            'author': chgset.author or 'anonymous',
                            'date': format_datetime(chgset.date),
                            'message': wiki_to_oneliner(
                                shorten_line(chgset.message), self.env, req=req)
                        }
                    else:
                        break
                    prev_rev = rev
                if build:
                    build_data = _get_build_data(self.env, req, build)
                    build_data['platform'] = platform.name
                    config_data['builds'].append(build_data)
                else:
                    config_data['builds'].append({
                        'platform': platform.name, 'status': 'pending'
                    })

        data['configs'] = sorted(configs, key=lambda x:x['label'].lower())
        data['page_mode'] = 'overview'

        in_progress_builds = Build.select(self.env, status=Build.IN_PROGRESS)
        pending_builds = Build.select(self.env, status=Build.PENDING)

        data['builds_pending'] = len(list(pending_builds))
        data['builds_inprogress'] = len(list(in_progress_builds))

        add_link(req, 'views', req.href.build(view='inprogress'),
                 'In Progress Builds')
        add_ctxtnav(req, 'In Progress Builds',
                    req.href.build(view='inprogress'))
        return data
Exemple #24
0
    def _render_config(self, req, config_name):
        db = self.env.get_db_cnx()

        config = BuildConfig.fetch(self.env, config_name, db=db)
        if not config:
            raise HTTPNotFound("Build configuration '%s' does not exist." \
                                % config_name)

        repos = self.env.get_repository(authname=req.authname)
        assert repos, 'No "(default)" Repository: Add a repository or alias ' \
                      'named "(default)" to Trac.'
        rev = config.max_rev or repos.youngest_rev
        try:
            _has_permission(req.perm, repos, config.path, rev=rev,
                                                        raise_error=True)
        except NoSuchNode:
            raise TracError("Permission checking against repository path %s "
                "at revision %s failed." % (config.path, rev))

        data = {'title': 'Build Configuration "%s"' \
                          % config.label or config.name,
                'page_mode': 'view_config'}
        add_link(req, 'up', req.href.build(), 'Build Status')
        description = config.description
        if description:
            description = wiki_to_html(description, self.env, req)

        pending_builds = list(Build.select(self.env,
                                config=config.name, status=Build.PENDING))
        inprogress_builds = list(Build.select(self.env,
                                config=config.name, status=Build.IN_PROGRESS))

        data['config'] = {
            'name': config.name, 'label': config.label, 'path': config.path,
            'min_rev': config.min_rev,
            'min_rev_href': req.href.changeset(config.min_rev),
            'max_rev': config.max_rev,
            'max_rev_href': req.href.changeset(config.max_rev),
            'active': config.active, 'description': description,
            'browser_href': req.href.browser(config.path),
            'builds_pending' : len(pending_builds),
            'builds_inprogress' : len(inprogress_builds)
        }

        context = Context.from_request(req, config.resource)
        data['context'] = context
        data['config']['attachments'] = AttachmentModule(self.env).attachment_data(context)

        platforms = list(TargetPlatform.select(self.env, config=config_name,
                                               db=db))
        data['config']['platforms'] = [
            { 'name': platform.name,
              'id': platform.id,
              'builds_pending': len(list(Build.select(self.env,
                                                    config=config.name,
                                                    status=Build.PENDING,
                                                    platform=platform.id))),
              'builds_inprogress': len(list(Build.select(self.env,
                                                    config=config.name,
                                                    status=Build.IN_PROGRESS,
                                                    platform=platform.id)))
              }
            for platform in platforms
        ]

        has_reports = False
        for report in Report.select(self.env, config=config.name, db=db):
            has_reports = True
            break

        if has_reports:
            chart_generators = []
            report_categories = list(self._report_categories_for_config(config))
            for generator in ReportChartController(self.env).generators:
                for category in generator.get_supported_categories():
                    if category in report_categories:
                        chart_generators.append({
                            'href': req.href.build(config.name, 'chart/' + category),
                            'category': category,
                            'style': self.config.get('bitten', 'chart_style'),
                        })
            data['config']['charts'] = chart_generators

        page = max(1, int(req.args.get('page', 1)))
        more = False
        data['page_number'] = page

        repos = self.env.get_repository(authname=req.authname)
        assert repos, 'No "(default)" Repository: Add a repository or alias ' \
                      'named "(default)" to Trac.'

        builds_per_page = 12 * len(platforms)
        idx = 0
        builds = {}
        revisions = []
        for platform, rev, build in collect_changes(repos, config):
            if idx >= page * builds_per_page:
                more = True
                break
            elif idx >= (page - 1) * builds_per_page:
                if rev not in builds:
                    revisions.append(rev)
                builds.setdefault(rev, {})
                builds[rev].setdefault('href', req.href.changeset(rev))
                builds[rev].setdefault('display_rev', repos.normalize_rev(rev))
                if build and build.status != Build.PENDING:
                    build_data = _get_build_data(self.env, req, build)
                    build_data['steps'] = []
                    for step in BuildStep.select(self.env, build=build.id,
                                                 db=db):
                        build_data['steps'].append({
                            'name': step.name,
                            'description': step.description,
                            'duration': to_datetime(step.stopped or int(time.time()), utc) - \
                                        to_datetime(step.started, utc),
                            'status': _step_status_label[step.status],
                            'cls': _step_status_label[step.status].replace(' ', '-'),

                            'errors': step.errors,
                            'href': build_data['href'] + '#step_' + step.name
                        })
                    builds[rev][platform.id] = build_data
            idx += 1
        data['config']['builds'] = builds
        data['config']['revisions'] = revisions

        if page > 1:
            if page == 2:
                prev_href = req.href.build(config.name)
            else:
                prev_href = req.href.build(config.name, page=page - 1)
            add_link(req, 'prev', prev_href, 'Previous Page')
        if more:
            next_href = req.href.build(config.name, page=page + 1)
            add_link(req, 'next', next_href, 'Next Page')
        if arity(prevnext_nav) == 4: # Trac 0.12 compat, see #450
            prevnext_nav(req, 'Previous Page', 'Next Page')
        else:
            prevnext_nav (req, 'Page')
        return data
Exemple #25
0
    def _render_config(self, req, config_name):
        db = self.env.get_db_cnx()

        config = BuildConfig.fetch(self.env, config_name, db=db)
        if not config:
            raise HTTPNotFound("Build configuration '%s' does not exist." \
                                % config_name)

        repos = self.env.get_repository(req.authname)
        repos.authz.assert_permission(config.branch)

        data = {'title': 'Build Configuration "%s"' \
                          % config.label or config.name,
                'page_mode': 'view_config'}
        add_link(req, 'up', req.href.build(), 'Build Status')
        description = config.description
        if description:
            description = wiki_to_html(description, self.env, req)

        pending_builds = list(
            Build.select(self.env, config=config.name, status=Build.PENDING))
        inprogress_builds = list(
            Build.select(self.env,
                         config=config.name,
                         status=Build.IN_PROGRESS))

        rev = ''

        for b in repos.git.get_branches():
            if b[0] == config.branch:
                rev = b[1]
                break

        data['config'] = {
            'name': config.name,
            'label': config.label,
            'branch': config.branch,
            'active': config.active,
            'description': description,
            'browser_href': req.href.browser(rev=rev),
            'builds_pending': len(pending_builds),
            'builds_inprogress': len(inprogress_builds)
        }

        context = Context.from_request(req, config.resource)
        data['context'] = context
        data['config']['attachments'] = AttachmentModule(
            self.env).attachment_data(context)

        platforms = list(
            TargetPlatform.select(self.env, config=config_name, db=db))
        data['config']['platforms'] = [{
            'name':
            platform.name,
            'id':
            platform.id,
            'builds_pending':
            len(
                list(
                    Build.select(self.env,
                                 config=config.name,
                                 status=Build.PENDING,
                                 platform=platform.id))),
            'builds_inprogress':
            len(
                list(
                    Build.select(self.env,
                                 config=config.name,
                                 status=Build.IN_PROGRESS,
                                 platform=platform.id)))
        } for platform in platforms]

        has_reports = False
        for report in Report.select(self.env, config=config.name, db=db):
            has_reports = True
            break

        if has_reports:
            chart_generators = []
            for generator in ReportChartController(self.env).generators:
                for category in generator.get_supported_categories():
                    chart_generators.append({
                        'href':
                        req.href.build(config.name, 'chart/' + category)
                    })
            data['config']['charts'] = chart_generators
            charts_license = self.config.get('bitten', 'charts_license')
            if charts_license:
                data['config']['charts_license'] = charts_license

        page = max(1, int(req.args.get('page', 1)))
        more = False
        data['page_number'] = page

        repos = self.env.get_repository(req.authname)

        builds_per_page = 12 * len(platforms)
        idx = 0
        builds = {}
        for platform, rev, build in collect_changes(repos, config):
            if idx >= page * builds_per_page:
                more = True
                break
            elif idx >= (page - 1) * builds_per_page:
                builds.setdefault(rev, {})
                builds[rev].setdefault('href', req.href.changeset(rev))
                if build and build.status != Build.PENDING:
                    build_data = _get_build_data(self.env, req, build)
                    build_data['steps'] = []
                    for step in BuildStep.select(self.env,
                                                 build=build.id,
                                                 db=db):
                        build_data['steps'].append({
                            'name': step.name,
                            'description': step.description,
                            'duration': to_datetime(step.stopped, utc) - \
                                        to_datetime(step.started, utc),
                            'failed': not step.successful,
                            'errors': step.errors,
                            'href': build_data['href'] + '#step_' + step.name
                        })
                    builds[rev][platform.id] = build_data
            idx += 1
        data['config']['builds'] = builds

        if page > 1:
            if page == 2:
                prev_href = req.href.build(config.name)
            else:
                prev_href = req.href.build(config.name, page=page - 1)
            add_link(req, 'prev', prev_href, 'Previous Page')
        if more:
            next_href = req.href.build(config.name, page=page + 1)
            add_link(req, 'next', next_href, 'Next Page')
        prevnext_nav(req, 'Page')
        return data
Exemple #26
0
    def _render_inprogress(self, req):
        data = {'title': 'In Progress Builds', 'page_mode': 'view-inprogress'}

        db = self.env.get_db_cnx()

        repos = self.env.get_repository(req.authname)

        configs = []
        for config in BuildConfig.select(self.env, include_inactive=False):
            if not repos.authz.has_permission(config.branch):
                continue

            self.log.debug(config.name)
            if not config.active:
                continue

            in_progress_builds = Build.select(self.env,
                                              config=config.name,
                                              status=Build.IN_PROGRESS,
                                              db=db)

            current_builds = 0
            builds = []
            # sort correctly by revision.
            for build in sorted(in_progress_builds,
                                cmp=lambda x, y: int(y.rev) - int(x.rev)):
                rev = build.rev
                build_data = _get_build_data(self.env, req, build)
                build_data['rev'] = rev
                build_data['rev_href'] = req.href.changeset(rev)
                platform = TargetPlatform.fetch(self.env, build.platform)
                build_data['platform'] = platform.name
                build_data['steps'] = []

                for step in BuildStep.select(self.env, build=build.id, db=db):
                    build_data['steps'].append({
                        'name': step.name,
                        'description': step.description,
                        'duration': to_datetime(step.stopped, utc) - \
                                    to_datetime(step.started, utc),
                        'failed': not step.successful,
                        'errors': step.errors,
                        'href': build_data['href'] + '#step_' + step.name
                    })

                builds.append(build_data)
                current_builds += 1

            if current_builds == 0:
                continue

            description = config.description
            if description:
                description = wiki_to_html(description, self.env, req)
            configs.append({
                'name': config.name,
                'label': config.label or config.name,
                'active': config.active,
                'branch': config.branch,
                'description': description,
                'href': req.href.build(config.name),
                'builds': builds
            })

        data['configs'] = configs
        return data
Exemple #27
0
    def _render_overview(self, req):
        data = {'title': 'Build Status'}
        show_all = False
        if req.args.get('show') == 'all':
            show_all = True
        data['show_all'] = show_all

        repos = self.env.get_repository(req.authname)

        configs = []
        for config in BuildConfig.select(self.env, include_inactive=show_all):
            if not repos.authz.has_permission(config.branch):
                continue

            description = config.description
            if description:
                description = wiki_to_html(description, self.env, req)

            platforms_data = []
            for platform in TargetPlatform.select(self.env,
                                                  config=config.name):
                pd = {
                    'name':
                    platform.name,
                    'id':
                    platform.id,
                    'builds_pending':
                    len(
                        list(
                            Build.select(self.env,
                                         config=config.name,
                                         status=Build.PENDING,
                                         platform=platform.id))),
                    'builds_inprogress':
                    len(
                        list(
                            Build.select(self.env,
                                         config=config.name,
                                         status=Build.IN_PROGRESS,
                                         platform=platform.id)))
                }
                platforms_data.append(pd)

            config_data = {
                'name':
                config.name,
                'label':
                config.label or config.name,
                'active':
                config.active,
                'branch':
                config.branch,
                'description':
                description,
                'builds_pending':
                len(
                    list(
                        Build.select(self.env,
                                     config=config.name,
                                     status=Build.PENDING))),
                'builds_inprogress':
                len(
                    list(
                        Build.select(self.env,
                                     config=config.name,
                                     status=Build.IN_PROGRESS))),
                'href':
                req.href.build(config.name),
                'builds': [],
                'platforms':
                platforms_data
            }
            configs.append(config_data)
            if not config.active:
                continue

            prev_rev = None
            for platform, rev, build in collect_changes(repos, config):
                if rev != prev_rev:
                    if prev_rev is None:
                        chgset = repos.get_changeset(rev)
                        config_data['youngest_rev'] = {
                            'id':
                            rev,
                            'href':
                            req.href.changeset(rev),
                            'author':
                            chgset.author or 'anonymous',
                            'date':
                            format_datetime(chgset.date),
                            'message':
                            wiki_to_oneliner(shorten_line(chgset.message),
                                             self.env,
                                             req=req)
                        }
                    else:
                        break
                    prev_rev = rev
                if build:
                    build_data = _get_build_data(self.env, req, build)
                    build_data['platform'] = platform.name
                    config_data['builds'].append(build_data)
                else:
                    config_data['builds'].append({
                        'platform': platform.name,
                        'status': 'pending'
                    })

        data['configs'] = configs
        data['page_mode'] = 'overview'

        in_progress_builds = Build.select(self.env, status=Build.IN_PROGRESS)
        pending_builds = Build.select(self.env, status=Build.PENDING)

        data['builds_pending'] = len(list(pending_builds))
        data['builds_inprogress'] = len(list(in_progress_builds))

        add_link(req, 'views', req.href.build(view='inprogress'),
                 'In Progress Builds')
        add_ctxtnav(req, 'In Progress Builds',
                    req.href.build(view='inprogress'))
        return data
Exemple #28
0
    def _render_config(self, req, config_name):
        db = self.env.get_db_cnx()

        config = BuildConfig.fetch(self.env, config_name, db=db)
        if not config:
            raise HTTPNotFound("Build configuration '%s' does not exist." \
                                % config_name)

        repos = self.env.get_repository(authname=req.authname)
        assert repos, 'No "(default)" Repository: Add a repository or alias ' \
                      'named "(default)" to Trac.'
        rev = config.max_rev or repos.youngest_rev
        try:
            _has_permission(req.perm,
                            repos,
                            config.path,
                            rev=rev,
                            raise_error=True)
        except NoSuchNode:
            raise TracError("Permission checking against repository path %s "
                            "at revision %s failed." % (config.path, rev))

        data = {'title': 'Build Configuration "%s"' \
                          % config.label or config.name,
                'page_mode': 'view_config'}
        add_link(req, 'up', req.href.build(), 'Build Status')
        description = config.description
        if description:
            description = wiki_to_html(description, self.env, req)

        pending_builds = list(
            Build.select(self.env, config=config.name, status=Build.PENDING))
        inprogress_builds = list(
            Build.select(self.env,
                         config=config.name,
                         status=Build.IN_PROGRESS))

        data['config'] = {
            'name': config.name,
            'label': config.label,
            'path': config.path,
            'min_rev': config.min_rev,
            'min_rev_href': req.href.changeset(config.min_rev),
            'max_rev': config.max_rev,
            'max_rev_href': req.href.changeset(config.max_rev),
            'active': config.active,
            'description': description,
            'browser_href': req.href.browser(config.path),
            'builds_pending': len(pending_builds),
            'builds_inprogress': len(inprogress_builds)
        }

        context = Context.from_request(req, config.resource)
        data['context'] = context
        data['config']['attachments'] = AttachmentModule(
            self.env).attachment_data(context)

        platforms = list(
            TargetPlatform.select(self.env, config=config_name, db=db))
        data['config']['platforms'] = [{
            'name':
            platform.name,
            'id':
            platform.id,
            'builds_pending':
            len(
                list(
                    Build.select(self.env,
                                 config=config.name,
                                 status=Build.PENDING,
                                 platform=platform.id))),
            'builds_inprogress':
            len(
                list(
                    Build.select(self.env,
                                 config=config.name,
                                 status=Build.IN_PROGRESS,
                                 platform=platform.id)))
        } for platform in platforms]

        has_reports = False
        for report in Report.select(self.env, config=config.name, db=db):
            has_reports = True
            break

        if has_reports:
            chart_generators = []
            report_categories = list(
                self._report_categories_for_config(config))
            for generator in ReportChartController(self.env).generators:
                for category in generator.get_supported_categories():
                    if category in report_categories:
                        chart_generators.append({
                            'href':
                            req.href.build(config.name, 'chart/' + category),
                            'category':
                            category,
                            'style':
                            self.config.get('bitten', 'chart_style'),
                        })
            data['config']['charts'] = chart_generators

        page = max(1, int(req.args.get('page', 1)))
        more = False
        data['page_number'] = page

        repos = self.env.get_repository(authname=req.authname)
        assert repos, 'No "(default)" Repository: Add a repository or alias ' \
                      'named "(default)" to Trac.'

        builds_per_page = 12 * len(platforms)
        idx = 0
        builds = {}
        revisions = []
        for platform, rev, build in collect_changes(repos, config):
            if idx >= page * builds_per_page:
                more = True
                break
            elif idx >= (page - 1) * builds_per_page:
                if rev not in builds:
                    revisions.append(rev)
                builds.setdefault(rev, {})
                builds[rev].setdefault('href', req.href.changeset(rev))
                builds[rev].setdefault('display_rev', repos.normalize_rev(rev))
                if build and build.status != Build.PENDING:
                    build_data = _get_build_data(self.env, req, build)
                    build_data['steps'] = []
                    for step in BuildStep.select(self.env,
                                                 build=build.id,
                                                 db=db):
                        build_data['steps'].append({
                            'name': step.name,
                            'description': step.description,
                            'duration': to_datetime(step.stopped or int(time.time()), utc) - \
                                        to_datetime(step.started, utc),
                            'status': _step_status_label[step.status],
                            'cls': _step_status_label[step.status].replace(' ', '-'),

                            'errors': step.errors,
                            'href': build_data['href'] + '#step_' + step.name
                        })
                    builds[rev][platform.id] = build_data
            idx += 1
        data['config']['builds'] = builds
        data['config']['revisions'] = revisions

        if page > 1:
            if page == 2:
                prev_href = req.href.build(config.name)
            else:
                prev_href = req.href.build(config.name, page=page - 1)
            add_link(req, 'prev', prev_href, 'Previous Page')
        if more:
            next_href = req.href.build(config.name, page=page + 1)
            add_link(req, 'next', next_href, 'Next Page')
        if arity(prevnext_nav) == 4:  # Trac 0.12 compat, see #450
            prevnext_nav(req, 'Previous Page', 'Next Page')
        else:
            prevnext_nav(req, 'Page')
        return data
Exemple #29
0
            continue

        # Make sure the repository directory isn't empty at this
        # revision
        old_node = repos.get_node(path, rev)
        is_empty = True
        for entry in old_node.get_entries():
            is_empty = False
            break
        if is_empty:
            continue

        # For every target platform, check whether there's a build
        # of this revision
        for platform in TargetPlatform.select(env, config.name, db=db):
            builds = list(Build.select(env, config.name, rev, platform.id,
                                       db=db))
            if builds:
                build = builds[0]
            else:
                build = None

            yield platform, rev, build


class BuildQueue(object):
    """Enapsulates the build queue of an environment.
    
    A build queue manages the the registration of build slaves and detection of
    repository revisions that need to be built.
    """
Exemple #30
0
    def _render_overview(self, req):
        data = {'title': 'Build Status'}
        show_all = False
        if req.args.get('show') == 'all':
            show_all = True
        data['show_all'] = show_all

        repos = self.env.get_repository(authname=req.authname)
        assert repos, 'No "(default)" Repository: Add a repository or alias ' \
                      'named "(default)" to Trac.'

        configs = []
        for config in BuildConfig.select(self.env, include_inactive=show_all):
            rev = config.max_rev or repos.youngest_rev
            try:
                if not _has_permission(req.perm, repos, config.path, rev=rev):
                    continue
            except NoSuchNode:
                add_warning(req, "Configuration '%s' points to non-existing "
                        "path '/%s' at revision '%s'. Configuration skipped." \
                                    % (config.name, config.path, rev))
                continue

            description = config.description
            if description:
                description = wiki_to_html(description, self.env, req)

            platforms_data = []
            for platform in TargetPlatform.select(self.env,
                                                  config=config.name):
                pd = {
                    'name':
                    platform.name,
                    'id':
                    platform.id,
                    'builds_pending':
                    len(
                        list(
                            Build.select(self.env,
                                         config=config.name,
                                         status=Build.PENDING,
                                         platform=platform.id))),
                    'builds_inprogress':
                    len(
                        list(
                            Build.select(self.env,
                                         config=config.name,
                                         status=Build.IN_PROGRESS,
                                         platform=platform.id)))
                }
                platforms_data.append(pd)

            config_data = {
                'name':
                config.name,
                'label':
                config.label or config.name,
                'active':
                config.active,
                'path':
                config.path,
                'description':
                description,
                'builds_pending':
                len(
                    list(
                        Build.select(self.env,
                                     config=config.name,
                                     status=Build.PENDING))),
                'builds_inprogress':
                len(
                    list(
                        Build.select(self.env,
                                     config=config.name,
                                     status=Build.IN_PROGRESS))),
                'href':
                req.href.build(config.name),
                'builds': [],
                'platforms':
                platforms_data
            }
            configs.append(config_data)
            if not config.active:
                continue

            prev_rev = None
            for platform, rev, build in collect_changes(repos, config):
                if rev != prev_rev:
                    if prev_rev is None:
                        chgset = repos.get_changeset(rev)
                        config_data['youngest_rev'] = {
                            'id':
                            rev,
                            'href':
                            req.href.changeset(rev),
                            'display_rev':
                            repos.normalize_rev(rev),
                            'author':
                            chgset.author or 'anonymous',
                            'date':
                            format_datetime(chgset.date),
                            'message':
                            wiki_to_oneliner(shorten_line(chgset.message),
                                             self.env,
                                             req=req)
                        }
                    else:
                        break
                    prev_rev = rev
                if build:
                    build_data = _get_build_data(self.env, req, build)
                    build_data['platform'] = platform.name
                    config_data['builds'].append(build_data)
                else:
                    config_data['builds'].append({
                        'platform': platform.name,
                        'status': 'pending'
                    })

        data['configs'] = sorted(configs, key=lambda x: x['label'].lower())
        data['page_mode'] = 'overview'

        in_progress_builds = Build.select(self.env, status=Build.IN_PROGRESS)
        pending_builds = Build.select(self.env, status=Build.PENDING)

        data['builds_pending'] = len(list(pending_builds))
        data['builds_inprogress'] = len(list(in_progress_builds))

        add_link(req, 'views', req.href.build(view='inprogress'),
                 'In Progress Builds')
        add_ctxtnav(req, 'In Progress Builds',
                    req.href.build(view='inprogress'))
        return data
Exemple #31
0
    def _render_inprogress(self, req):
        data = {'title': 'In Progress Builds', 'page_mode': 'view-inprogress'}

        db = self.env.get_db_cnx()

        repos = self.env.get_repository(authname=req.authname)
        assert repos, 'No "(default)" Repository: Add a repository or alias ' \
                      'named "(default)" to Trac.'

        configs = []
        for config in BuildConfig.select(self.env, include_inactive=False):
            rev = config.max_rev or repos.youngest_rev
            try:
                if not _has_permission(req.perm, repos, config.path, rev=rev):
                    continue
            except NoSuchNode:
                add_warning(req, "Configuration '%s' points to non-existing "
                        "path '/%s' at revision '%s'. Configuration skipped." \
                                    % (config.name, config.path, rev))
                continue

            self.log.debug(config.name)
            if not config.active:
                continue

            in_progress_builds = Build.select(self.env,
                                              config=config.name,
                                              status=Build.IN_PROGRESS,
                                              db=db)

            current_builds = 0
            builds = []
            # sort correctly by revision.
            for build in sorted(
                    in_progress_builds,
                    cmp=lambda x, y: int(y.rev_time) - int(x.rev_time)):
                rev = build.rev
                build_data = _get_build_data(self.env, req, build)
                build_data['rev'] = rev
                build_data['rev_href'] = req.href.changeset(rev)
                platform = TargetPlatform.fetch(self.env, build.platform)
                build_data['platform'] = platform.name
                build_data['steps'] = []

                for step in BuildStep.select(self.env, build=build.id, db=db):
                    build_data['steps'].append({
                        'name': step.name,
                        'description': step.description,
                        'duration': to_datetime(step.stopped or int(time.time()), utc) - \
                                    to_datetime(step.started, utc),
                        'status': _step_status_label[step.status],
                        'cls': _step_status_label[step.status].replace(' ', '-'),
                        'errors': step.errors,
                        'href': build_data['href'] + '#step_' + step.name
                    })

                builds.append(build_data)
                current_builds += 1

            if current_builds == 0:
                continue

            description = config.description
            if description:
                description = wiki_to_html(description, self.env, req)
            configs.append({
                'name': config.name,
                'label': config.label or config.name,
                'active': config.active,
                'path': config.path,
                'description': description,
                'href': req.href.build(config.name),
                'builds': builds
            })

        data['configs'] = sorted(configs, key=lambda x: x['label'].lower())
        return data
Exemple #32
0
 def getBuildIds(self, req, config=None, rev=None, platform=None, slave=None, status=None):
     """Retrieve a list of build unique identifiers that match the selected criteria
     """
     return [build.id for build in Build.select(self.env, config=config or None,
                 rev=rev or None, platform=platform or None, slave=slave or None,
                 status=status or None) if build]
Exemple #33
0
    def _render_inprogress(self, req):
        data = {'title': 'In Progress Builds',
                'page_mode': 'view-inprogress'}

        db = self.env.get_db_cnx()

        repos = self.env.get_repository(authname=req.authname)
        assert repos, 'No "(default)" Repository: Add a repository or alias ' \
                      'named "(default)" to Trac.'

        configs = []
        for config in BuildConfig.select(self.env, include_inactive=False):
            rev = config.max_rev or repos.youngest_rev
            try:
                if not _has_permission(req.perm, repos, config.path, rev=rev):
                    continue
            except NoSuchNode:
                add_warning(req, "Configuration '%s' points to non-existing "
                        "path '/%s' at revision '%s'. Configuration skipped." \
                                    % (config.name, config.path, rev))
                continue

            self.log.debug(config.name)
            if not config.active:
                continue

            in_progress_builds = Build.select(self.env, config=config.name,
                                              status=Build.IN_PROGRESS, db=db)

            current_builds = 0
            builds = []
            # sort correctly by revision.
            for build in sorted(in_progress_builds,
                                cmp=lambda x, y: int(y.rev_time) - int(x.rev_time)):
                rev = build.rev
                build_data = _get_build_data(self.env, req, build)
                build_data['rev'] = rev
                build_data['rev_href'] = req.href.changeset(rev)
                platform = TargetPlatform.fetch(self.env, build.platform)
                build_data['platform'] = platform.name
                build_data['steps'] = []

                for step in BuildStep.select(self.env, build=build.id, db=db):
                    build_data['steps'].append({
                        'name': step.name,
                        'description': step.description,
                        'duration': to_datetime(step.stopped or int(time.time()), utc) - \
                                    to_datetime(step.started, utc),
                        'status': _step_status_label[step.status],
                        'cls': _step_status_label[step.status].replace(' ', '-'),
                        'errors': step.errors,
                        'href': build_data['href'] + '#step_' + step.name
                    })

                builds.append(build_data)
                current_builds += 1

            if current_builds == 0:
                continue

            description = config.description
            if description:
                description = wiki_to_html(description, self.env, req)
            configs.append({
                'name': config.name, 'label': config.label or config.name,
                'active': config.active, 'path': config.path,
                'description': description,
                'href': req.href.build(config.name),
                'builds': builds
            })

        data['configs'] = sorted(configs, key=lambda x:x['label'].lower())
        return data
Exemple #34
0
    def _render_overview(self, req):
        data = {'title': 'Build Status'}
        show_all = False
        if req.args.get('show') == 'all':
            show_all = True
        data['show_all'] = show_all

        repos = self.env.get_repository(req.authname)
        if hasattr(repos, 'sync'):
            repos.sync()

        configs = []
        for config in BuildConfig.select(self.env, include_inactive=show_all):
            if not repos.authz.has_permission(config.path):
                continue

            description = config.description
            if description:
                description = wiki_to_html(description, self.env, req)

            platforms_data = []
            for platform in TargetPlatform.select(self.env, config=config.name):
                pd = { 'name': platform.name,
                       'id': platform.id,
                       'builds_pending': len(list(Build.select(self.env, config=config.name, status=Build.PENDING, platform=platform.id))),
                       'builds_inprogress': len(list(Build.select(self.env, config=config.name, status=Build.IN_PROGRESS, platform=platform.id)))
                }
                platforms_data.append(pd)
		
            config_data = {
                'name': config.name, 'label': config.label or config.name,
                'active': config.active, 'path': config.path,
                'description': description,
		'builds_pending' : len(list(Build.select(self.env, config=config.name, status=Build.PENDING))),
		'builds_inprogress' : len(list(Build.select(self.env, config=config.name, status=Build.IN_PROGRESS))),
                'href': req.href.build(config.name),
                'builds': [],
                'platforms': platforms_data
            }
            configs.append(config_data)
            if not config.active:
                continue

            prev_rev = None
            for platform, rev, build in collect_changes(repos, config):
                if rev != prev_rev:
                    if prev_rev is None:
                        chgset = repos.get_changeset(rev)
                        config_data['youngest_rev'] = {
                            'id': rev, 'href': req.href.changeset(rev),
                            'author': chgset.author or 'anonymous',
                            'date': format_datetime(chgset.date),
                            'message': wiki_to_oneliner(
                                shorten_line(chgset.message), self.env, req=req)
                        }
                    else:
                        break
                    prev_rev = rev
                if build:
                    build_data = _get_build_data(self.env, req, build)
                    build_data['platform'] = platform.name
                    config_data['builds'].append(build_data)
                else:
                    config_data['builds'].append({
                        'platform': platform.name, 'status': 'pending'
                    })

        data['configs'] = configs
        data['page_mode'] = 'overview'

        in_progress_builds = Build.select(self.env, status=Build.IN_PROGRESS)
        pending_builds = Build.select(self.env, status=Build.PENDING)

	data['builds_pending'] = len(list(pending_builds))
	data['builds_inprogress'] = len(list(in_progress_builds))

        add_link(req, 'views', req.href.build(view='inprogress'),
                 'In Progress Builds')
        add_ctxtnav(req, 'In Progress Builds',
                    req.href.build(view='inprogress'))
        return data
Exemple #35
0
    def _render_config(self, req, config_name):
        db = self.env.get_db_cnx()

        config = BuildConfig.fetch(self.env, config_name, db=db)

        repos = self.env.get_repository(req.authname)
        if hasattr(repos, 'sync'):
            repos.sync()
        repos.authz.assert_permission(config.path)

        data = {'title': 'Build Configuration "%s"' \
                          % config.label or config.name,
                'page_mode': 'view_config'}
        add_link(req, 'up', req.href.build(), 'Build Status')
        description = config.description
        if description:
            description = wiki_to_html(description, self.env, req)

        pending_builds = list(Build.select(self.env, config=config.name, status=Build.PENDING))
        inprogress_builds = list(Build.select(self.env, config=config.name, status=Build.IN_PROGRESS))

        data['config'] = {
            'name': config.name, 'label': config.label, 'path': config.path,
            'min_rev': config.min_rev,
            'min_rev_href': req.href.changeset(config.min_rev),
            'max_rev': config.max_rev,
            'max_rev_href': req.href.changeset(config.max_rev),
            'active': config.active, 'description': description,
            'browser_href': req.href.browser(config.path),
            'builds_pending' : len(pending_builds),
	    'builds_inprogress' : len(inprogress_builds)
        }

        platforms = list(TargetPlatform.select(self.env, config=config_name,
                                               db=db))
        data['config']['platforms'] = [
            { 'name': platform.name,
              'id': platform.id, 
              'builds_pending': len(list(Build.select(self.env, config=config.name, status=Build.PENDING, platform=platform.id))),
              'builds_inprogress': len(list(Build.select(self.env, config=config.name, status=Build.IN_PROGRESS, platform=platform.id)))
              }
            for platform in platforms
        ]

        has_reports = False
        for report in Report.select(self.env, config=config.name, db=db):
            has_reports = True
            break

        if has_reports:
            chart_generators = []
            for generator in ReportChartController(self.env).generators: 
                for category in generator.get_supported_categories(): 
                    chart_generators.append({
                        'href': req.href.build(config.name, 'chart/' + category) 
                    })
            data['config']['charts'] = chart_generators 
            charts_license = self.config.get('bitten', 'charts_license')
            if charts_license:
                data['config']['charts_license'] = charts_license

        page = max(1, int(req.args.get('page', 1)))
        more = False
        data['page_number'] = page

        repos = self.env.get_repository(req.authname)
        if hasattr(repos, 'sync'):
            repos.sync()

        builds_per_page = 12 * len(platforms)
        idx = 0
        builds = {}
        for platform, rev, build in collect_changes(repos, config):
            if idx >= page * builds_per_page:
                more = True
                break
            elif idx >= (page - 1) * builds_per_page:
                builds.setdefault(rev, {})
                builds[rev].setdefault('href', req.href.changeset(rev))
                if build and build.status != Build.PENDING:
                    build_data = _get_build_data(self.env, req, build)
                    build_data['steps'] = []
                    for step in BuildStep.select(self.env, build=build.id,
                                                 db=db):
                        build_data['steps'].append({
                            'name': step.name,
                            'description': step.description,
                            'duration': datetime.fromtimestamp(step.stopped) - \
                                        datetime.fromtimestamp(step.started),
                            'failed': not step.successful,
                            'errors': step.errors,
                            'href': build_data['href'] + '#step_' + step.name
                        })
                    builds[rev][platform.id] = build_data
            idx += 1
        data['config']['builds'] = builds

        if page > 1:
            if page == 2:
                prev_href = req.href.build(config.name)
            else:
                prev_href = req.href.build(config.name, page=page - 1)
            add_link(req, 'prev', prev_href, 'Previous Page')
        if more:
            next_href = req.href.build(config.name, page=page + 1)
            add_link(req, 'next', next_href, 'Next Page')
        prevnext_nav(req, 'Page')
        return data
Exemple #36
0
    def _render_inprogress(self, req):
        data = {'title': 'In Progress Builds',
                'page_mode': 'view-inprogress'}

        db = self.env.get_db_cnx()

        repos = self.env.get_repository(req.authname)
        if hasattr(repos, 'sync'):
            repos.sync()

        configs = []
        for config in BuildConfig.select(self.env, include_inactive=False):
            if not repos.authz.has_permission(config.path):
                continue

            self.log.debug(config.name)
            if not config.active:
                continue

            in_progress_builds = Build.select(self.env, config=config.name,
                                              status=Build.IN_PROGRESS, db=db)

            current_builds = 0
            builds = []
            # sort correctly by revision.
            for build in sorted(in_progress_builds,
                                cmp=lambda x, y: int(y.rev) - int(x.rev)):
                rev = build.rev
                build_data = _get_build_data(self.env, req, build)
                build_data['rev'] = rev
                build_data['rev_href'] = req.href.changeset(rev)
                platform = TargetPlatform.fetch(self.env, build.platform)
                build_data['platform'] = platform.name
                build_data['steps'] = []

                for step in BuildStep.select(self.env, build=build.id, db=db):
                    build_data['steps'].append({
                        'name': step.name,
                        'description': step.description,
                        'duration': datetime.fromtimestamp(step.stopped) - \
                                    datetime.fromtimestamp(step.started),
                        'failed': not step.successful,
                        'errors': step.errors,
                        'href': build_data['href'] + '#step_' + step.name
                    })

                builds.append(build_data)
                current_builds += 1

            if current_builds == 0: 
                continue

            description = config.description
            if description:
                description = wiki_to_html(description, self.env, req)
            configs.append({
                'name': config.name, 'label': config.label or config.name,
                'active': config.active, 'path': config.path,
                'description': description,
                'href': req.href.build(config.name),
                'builds': builds
            })

        data['configs'] = configs
        return data