def test_poll_split_file(self):
        """Make sure split file works on branch only changes"""
        self.attachChangeSource(
            P4Source(p4port=None, p4user=None,
                     p4base='//depot/myproject/',
                     split_file=get_simple_split))
        self.expectCommands(
            gpo.Expect(
                'p4', 'changes', '//depot/myproject/...@51,#head').stdout(third_p4changes),
        )
        self.add_p4_describe_result(5, p4change[5])

        self.changesource.last_change = 50
        yield self.changesource.poll()

        # when_timestamp is converted from a local time spec, so just
        # replicate that here
        when = self.makeTime("2006/04/13 21:55:39")

        def changeKey(change):
            """ Let's sort the array of changes by branch,
                because in P4Source._poll(), changeAdded()
                is called by iterating over a dictionary of
                branches"""
            return change['branch']

        self.assertEqual(sorted(self.master.data.updates.changesAdded, key=changeKey),
            sorted([{
            'author': u'mpatel',
            'branch': u'branch_c',
            'category': None,
            'codebase': None,
            'comments': u'This is a multiline comment with tabs and spaces\n\nA list:\n  Item 1\n\tItem 2',
            'files': [u'branch_c_file'],
            'project': '',
            'properties': {},
            'repository': '',
            'revision': '5',
            'revlink': '',
            'src': None,
            'when_timestamp': datetime2epoch(when),
        }, {
            'author': u'mpatel',
            'branch': u'branch_b',
            'category': None,
            'codebase': None,
            'comments': u'This is a multiline comment with tabs and spaces\n\nA list:\n  Item 1\n\tItem 2',
            'files': [u'branch_b_file'],
            'project': '',
            'properties': {},
            'repository': '',
            'revision': '5',
            'revlink': '',
            'src': None,
            'when_timestamp': datetime2epoch(when),
        }], key=changeKey))
        self.assertEqual(self.changesource.last_change, 5)
        self.assertAllCommandsRan()
        def check_second_check(res):

            # when_timestamp is converted from a local time spec, so just
            # replicate that here
            when1 = self.makeTime("2006/04/13 21:46:23")
            when2 = self.makeTime("2006/04/13 21:51:39")

            # these two can happen in either order, since they're from the same
            # perforce change.
            changesAdded = self.master.data.updates.changesAdded
            if changesAdded[1]['branch'] == 'branch_c':
                changesAdded[1:] = reversed(changesAdded[1:])
            self.assertEqual(self.master.data.updates.changesAdded, [{
                'author': u'slamb',
                'branch': u'trunk',
                'category': None,
                'codebase': None,
                'comments': u'creation',
                'files': [u'whatbranch'],
                'project': '',
                'properties': {},
                'repository': '',
                'revision': '2',
                'revlink': '',
                'src': None,
                'when_timestamp': datetime2epoch(when1),
            }, {
                'author': u'bob',
                'branch': u'branch_b',
                'category': None,
                'codebase': None,
                'comments': u'short desc truncated because this is a long description.\nASDF-GUI-P3-\u2018Upgrade Icon\u2019 disappears sometimes.',
                'files': [u'branch_b_file', u'whatbranch'],
                'project': '',
                'properties': {},
                'repository': '',
                'revision': '3',
                'revlink': '',
                'src': None,
                'when_timestamp': datetime2epoch(when2),
            }, {
                'author': u'bob',
                'branch': u'branch_c',
                'category': None,
                'codebase': None,
                'comments': u'short desc truncated because this is a long description.\nASDF-GUI-P3-\u2018Upgrade Icon\u2019 disappears sometimes.',
                'files': [u'whatbranch'],
                'project': '',
                'properties': {},
                'repository': '',
                'revision': '3',
                'revlink': '',
                'src': None,
                'when_timestamp': datetime2epoch(when2),
            }])
            self.assertAllCommandsRan()
        def setup_thd(conn):
            metadata = sa.MetaData()
            metadata.bind = conn
            # This table contains basic information about each build.
            builds = sa.Table('builds', metadata,
                              sa.Column('id', sa.Integer, primary_key=True),
                              sa.Column('number', sa.Integer, nullable=False),
                              sa.Column('builderid', sa.Integer),
                              # note that there is 1:N relationship here.
                              # In case of worker loss, build has results RETRY
                              # and buildrequest is unclaimed
                              sa.Column('buildrequestid', sa.Integer,
                                        nullable=False),
                              # worker which performed this build
                              # TODO: ForeignKey to buildworkers table, named buildworkerid
                              # TODO: keep nullable to support worker-free
                              # builds
                              sa.Column('buildworkerid', sa.Integer),
                              # master which controlled this build
                              sa.Column('masterid', sa.Integer,
                                        nullable=False),
                              # start/complete times
                              sa.Column(
                                  'started_at', sa.Integer, nullable=False),
                              sa.Column('complete_at', sa.Integer),
                              # a list of strings describing the build's state
                              sa.Column(
                                  'state_strings_json', sa.Text, nullable=False),
                              sa.Column('results', sa.Integer),
                              )
            builds.create()
            buildsets = sa.Table('buildsets', metadata,
                                 sa.Column('id', sa.Integer, primary_key=True),
                                 sa.Column(
                                     'external_idstring', sa.String(256)),
                                 sa.Column('reason', sa.String(256)),
                                 sa.Column(
                                     'submitted_at', sa.Integer, nullable=False),
                                 sa.Column('complete', sa.SmallInteger, nullable=False,
                                           server_default=sa.DefaultClause("0")),
                                 sa.Column('complete_at', sa.Integer),
                                 sa.Column('results', sa.SmallInteger),
                                 )

            buildsets.create()

            conn.execute(buildsets.insert(), [
                dict(external_idstring='extid', reason='rsn1', sourcestamps=[91],
                     submitted_at=datetime2epoch(
                         datetime.datetime(1978, 6, 15, 12, 31, 15)),
                     complete_at=datetime2epoch(
                         datetime.datetime(1979, 6, 15, 12, 31, 15)),
                     complete=0, results=-1, bsid=91)
            ])
    def formatData(self, data):
        if isinstance(data, dict):
            for key in data:
                if isinstance(data[key], datetime):
                    data[key] = datetime2epoch(data[key])
                elif type(data[key]) in (dict, list, tuple):
                    data[key] = self.formatData(data[key])
        elif type(data) in (list, tuple):
            for index in range(len(data)):
                if isinstance(data[index], datetime):
                    data[index] = datetime2epoch(data[index])
                elif type(data[index]) in (dict, list, tuple):
                    data[index] = self.formatData(data[index])

        return data
Example #5
0
    def _make_ch(cls, changeid, master, chdict):
        change = cls(None, None, None, _fromChdict=True)
        change.who = chdict["author"]
        change.comments = chdict["comments"]
        change.revision = chdict["revision"]
        change.branch = chdict["branch"]
        change.category = chdict["category"]
        change.revlink = chdict["revlink"]
        change.repository = chdict["repository"]
        change.codebase = chdict["codebase"]
        change.project = chdict["project"]
        change.number = chdict["changeid"]

        when = chdict["when_timestamp"]
        if when:
            when = datetime2epoch(when)
        change.when = when

        change.files = chdict["files"][:]
        change.files.sort()

        change.properties = Properties()
        for n, (v, s) in chdict["properties"].iteritems():
            change.properties.setProperty(n, v, s)

        return defer.succeed(change)
Example #6
0
    def command_LAST(self, args):
        # FIXME: NEED TO THINK ABOUT!
        args = self.splitArgs(args)

        if len(args) == 0:
            builders = yield self.getAllBuilders()
        elif len(args) == 1:
            builder = yield self.getBuilder(buildername=args[0])
            if not builder:
                raise UsageError("no such builder")
            builders = [builder]
        else:
            raise UsageError("try 'last <builder>'")

        for builder in builders:
            lastBuild = yield self.getLastCompletedBuild(builder['builderid'])
            if not lastBuild:
                status = "(no builds run since last restart)"
            else:
                complete_at = lastBuild['complete_at']
                if complete_at:
                    complete_at = util.datetime2epoch(complete_at)
                    ago = self.convertTime(int(util.now() - complete_at))
                else:
                    ago = "??"
                status = lastBuild['state_string']
                status = 'last build %s ago: %s' % (ago, status)
            self.send("last build [%s]: %s" % (builder['name'], status))
Example #7
0
    def _make_ch(cls, changeid, master, chdict):
        change = cls(None, None, None, _fromChdict=True)
        change.who = chdict['author']
        change.comments = chdict['comments']
        change.revision = chdict['revision']
        change.branch = chdict['branch']
        change.category = chdict['category']
        change.revlink = chdict['revlink']
        change.repository = chdict['repository']
        change.codebase = chdict['codebase']
        change.project = chdict['project']
        change.number = chdict['changeid']

        when = chdict['when_timestamp']
        if when:
            when = datetime2epoch(when)
        change.when = when

        change.files = sorted(chdict['files'])

        change.properties = Properties()
        for n, (v, s) in iteritems(chdict['properties']):
            change.properties.setProperty(n, v, s)

        return defer.succeed(change)
    def test_server_tz(self):
        """Verify that the server_tz parameter is handled correctly"""
        self.attachChangeSource(
            P4Source(p4port=None, p4user=None,
                     p4base='//depot/myproject/',
                     split_file=get_simple_split,
                     server_tz="Europe/Berlin"))
        self.expectCommands(
            gpo.Expect(
                'p4', 'changes', '//depot/myproject/...@51,#head').stdout(third_p4changes),
        )
        self.add_p4_describe_result(5, p4change[5])

        self.changesource.last_change = 50
        yield self.changesource.poll()

        # when_timestamp is converted from 21:55:39 Berlin time to UTC
        when_berlin = self.makeTime("2006/04/13 21:55:39")
        when_berlin = when_berlin.replace(
            tzinfo=dateutil.tz.gettz('Europe/Berlin'))
        when = datetime2epoch(when_berlin)

        self.assertEqual([ch['when_timestamp']
                          for ch in self.master.data.updates.changesAdded],
                         [when, when])
        self.assertAllCommandsRan()
    def insert_sourcestamps_changes(self, conn, sourcestampid, repository, codebase, changeid):
        conn.execute(self.sourcestamps.insert(),
                     id=sourcestampid,
                     sourcestampsetid=sourcestampid,
                     branch='this_branch',
                     revision='this_revision',
                     patchid=None,
                     repository=repository,
                     project='',
                     codebase=codebase)

        dt_when = datetime.datetime(1978, 6, 15, 12, 31, 15, tzinfo=UTC)
        conn.execute(self.changes.insert(),
                     changeid=changeid,
                     author='develop',
                     comments='no comment',
                     is_dir=0,
                     branch='default',
                     revision='FD56A89',
                     revling=None,
                     when_timestamp=datetime2epoch(dt_when),
                     category=None,
                     repository=repository,
                     codebase=codebase,
                     project='')
Example #10
0
    def addChange(self, author=None, files=None, comments=None, is_dir=0,
                  revision=None, when_timestamp=None, branch=None,
                  category=None, revlink='', properties={}, repository='',
                  project='', codebase='', uid=None):
        if self.changes:
            changeid = max(self.changes.iterkeys()) + 1
        else:
            changeid = 500

        self.changes[changeid] = dict(
            changeid=changeid,
            author=author,
            comments=comments,
            is_dir=is_dir,
            revision=revision,
            when_timestamp=datetime2epoch(when_timestamp),
            branch=branch,
            category=category,
            revlink=revlink,
            repository=repository,
            project=project,
            codebase=codebase,
            files=files,
            properties=properties)

        return defer.succeed(changeid)
Example #11
0
    def completeBuildRequests(self, brids, results, complete_at=None, _reactor=reactor):
        assert results != RETRY, "a buildrequest cannot be completed with a retry status!"
        if complete_at is not None:
            complete_at = datetime2epoch(complete_at)
        else:
            complete_at = _reactor.seconds()

        def thd(conn):
            transaction = conn.begin()

            # the update here is simple, but a number of conditions are
            # attached to ensure that we do not update a row inappropriately,
            # Note that checking that the request is mine would require a
            # subquery, so for efficiency that is not checked.

            reqs_tbl = self.db.model.buildrequests

            # we'll need to batch the brids into groups of 100, so that the
            # parameter lists supported by the DBAPI aren't exhausted
            for batch in self.doBatch(brids, 100):

                q = reqs_tbl.update()
                q = q.where(reqs_tbl.c.id.in_(batch))
                q = q.where(reqs_tbl.c.complete != 1)
                res = conn.execute(q, complete=1, results=results, complete_at=complete_at)

                # if an incorrect number of rows were updated, then we failed.
                if res.rowcount != len(batch):
                    log.msg("tried to complete %d buildrequests, " "but only completed %d" % (len(batch), res.rowcount))
                    transaction.rollback()
                    raise NotClaimedError
            transaction.commit()

        return self.db.pool.do(thd)
Example #12
0
    def _processChanges(self, page):
        result = json.loads(page, encoding=self.encoding)
        for pr in result["values"]:
            branch = pr["source"]["branch"]["name"]
            nr = int(pr["id"])
            # Note that this is a short hash. The full length hash can be accessed via the
            # commit api resource but we want to avoid requesting multiple pages as long as
            # we are not sure that the pull request is new or updated.
            revision = pr["source"]["commit"]["hash"]

            # check branch
            if not self.branch or branch in self.branch:
                current = yield self._getCurrentRev(nr)

                if not current or current != revision:
                    # parse pull request api page (required for the filter)
                    page = yield client.getPage(str(pr["links"]["self"]["href"]))
                    pr_json = json.loads(page, encoding=self.encoding)

                    # filter pull requests by user function
                    if not self.pullrequest_filter(pr_json):
                        log.msg("pull request does not match filter")
                        continue

                    # access additional information
                    author = pr["author"]["display_name"]
                    prlink = pr["links"]["html"]["href"]
                    # Get time updated time. Note that the timezone offset is ignored.
                    if self.useTimestamps:
                        updated = datetime.strptime(pr["updated_on"].split(".")[0], "%Y-%m-%dT%H:%M:%S")
                    else:
                        updated = epoch2datetime(reactor.seconds())
                    title = pr["title"]
                    # parse commit api page
                    page = yield client.getPage(str(pr["source"]["commit"]["links"]["self"]["href"]))
                    commit_json = json.loads(page, encoding=self.encoding)
                    # use the full-length hash from now on
                    revision = commit_json["hash"]
                    revlink = commit_json["links"]["html"]["href"]
                    # parse repo api page
                    page = yield client.getPage(str(pr["source"]["repository"]["links"]["self"]["href"]))
                    repo_json = json.loads(page, encoding=self.encoding)
                    repo = repo_json["links"]["html"]["href"]

                    # update database
                    yield self._setCurrentRev(nr, revision)
                    # emit the change
                    yield self.master.data.updates.addChange(
                        author=ascii2unicode(author),
                        revision=ascii2unicode(revision),
                        revlink=ascii2unicode(revlink),
                        comments=u"pull-request #%d: %s\n%s" % (nr, title, prlink),
                        when_timestamp=datetime2epoch(updated),
                        branch=self.branch,
                        category=self.category,
                        project=self.project,
                        repository=ascii2unicode(repo),
                        src=u"bitbucket",
                    )
Example #13
0
 def check(bsdicts):
     bsdicts = [(bsdict['bsid'], bsdict['complete'],
                 datetime2epoch(bsdict['complete_at']),
                 bsdict['results'])
                for bsdict in bsdicts]
     self.assertEqual(sorted(bsdicts), sorted([
         (91, 1, 72759, 6),
         (92, 1, 298297876, 7)]))
Example #14
0
 def sendBuildFinishedMessage(self, buildid, results=0):
     self.master.db.builds.finishBuild(buildid=buildid, results=SUCCESS)
     build = yield self.master.db.builds.getBuild(buildid)
     self.master.mq.callConsumer(('builds', str(buildid), 'complete'),
                                 dict(
                                     buildid=buildid,
                                     number=build['number'],
                                     builderid=build['builderid'],
                                     buildrequestid=build['buildrequestid'],
                                     workerid=build['workerid'],
                                     masterid=build['masterid'],
                                     started_at=datetime2epoch(build['started_at']),
                                     complete=True,
                                     complete_at=datetime2epoch(build['complete_at']),
                                     state_string=u'',
                                     results=results,
         ))
Example #15
0
    def addChange(self, who=None, files=None, comments=None, **kwargs):
        # deprecated in 0.9.0; will be removed in 1.0.0
        log.msg(
            "WARNING: change source is using deprecated "
            "self.master.addChange method; this method will disappear in "
            "Buildbot-1.0.0"
        )
        # handle positional arguments
        kwargs["who"] = who
        kwargs["files"] = files
        kwargs["comments"] = comments

        def handle_deprec(oldname, newname):
            if oldname not in kwargs:
                return
            old = kwargs.pop(oldname)
            if old is not None:
                if kwargs.get(newname) is None:
                    log.msg("WARNING: change source is using deprecated " "addChange parameter '%s'" % oldname)
                    return old
                raise TypeError("Cannot provide '%s' and '%s' to addChange" % (oldname, newname))
            return kwargs.get(newname)

        kwargs["author"] = handle_deprec("who", "author")
        kwargs["when_timestamp"] = handle_deprec("when", "when_timestamp")

        # timestamp must be an epoch timestamp now
        if isinstance(kwargs.get("when_timestamp"), datetime.datetime):
            kwargs["when_timestamp"] = datetime2epoch(kwargs["when_timestamp"])

        # unicodify stuff
        for k in (
            "comments",
            "author",
            "revision",
            "branch",
            "category",
            "revlink",
            "repository",
            "codebase",
            "project",
        ):
            if k in kwargs:
                kwargs[k] = ascii2unicode(kwargs[k])
        if kwargs.get("files"):
            kwargs["files"] = [ascii2unicode(f) for f in kwargs["files"]]
        if kwargs.get("properties"):
            kwargs["properties"] = dict((ascii2unicode(k), v) for k, v in iteritems(kwargs["properties"]))

        # pass the converted call on to the data API
        changeid = yield self.data.updates.addChange(**kwargs)

        # and turn that changeid into a change object, since that's what
        # callers expected (and why this method was deprecated)
        chdict = yield self.db.changes.getChange(changeid)
        change = yield changes.Change.fromChdict(self, chdict)
        defer.returnValue(change)
 def test_basic(self):
     self.setupStep(
         LogChunksJanitor(logHorizon=timedelta(weeks=1)))
     self.master.db.logs.deleteOldLogChunks = mock.Mock(return_value=3)
     self.expectOutcome(result=SUCCESS,
                        state_string=u"deleted 3 logchunks")
     yield self.runStep()
     expected_timestamp = datetime2epoch(datetime.datetime(year=2016, month=12, day=25))
     self.master.db.logs.deleteOldLogChunks.assert_called_with(expected_timestamp)
        def check(res):
            # when_timestamp is converted from a local time spec, so just
            # replicate that here
            when = self.makeTime("2006/04/13 21:55:39")

            def changeKey(change):
                """ Let's sort the array of changes by branch,
                    because in P4Source._poll(), changeAdded()
                    is called by iterating over a dictionary of
                    branches"""
                return change['branch']

            self.assertEqual(sorted(self.master.data.updates.changesAdded, key=changeKey),
                sorted([{
                'author': u'mpatel',
                'branch': u'branch_c',
                'category': None,
                'codebase': None,
                'comments': u'This is a multiline comment with tabs and spaces\n\nA list:\n  Item 1\n\tItem 2',
                'files': [u'branch_c_file'],
                'project': '',
                'properties': {},
                'repository': '',
                'revision': '5',
                'revlink': '',
                'src': None,
                'when_timestamp': datetime2epoch(when),
            }, {
                'author': u'mpatel',
                'branch': u'branch_b',
                'category': None,
                'codebase': None,
                'comments': u'This is a multiline comment with tabs and spaces\n\nA list:\n  Item 1\n\tItem 2',
                'files': [u'branch_b_file'],
                'project': '',
                'properties': {},
                'repository': '',
                'revision': '5',
                'revlink': '',
                'src': None,
                'when_timestamp': datetime2epoch(when),
            }], key=changeKey))
            self.assertEqual(self.changesource.last_change, 5)
            self.assertAllCommandsRan()
Example #18
0
    def _fixChange(self, change):
        # TODO: make these mods in the DB API
        if change:
            change = change.copy()
            change['when_timestamp'] = datetime2epoch(change['when_timestamp'])

            sskey = ('sourcestamps', str(change['sourcestampid']))
            change['sourcestamp'] = yield self.master.data.get(sskey)
            del change['sourcestampid']
        defer.returnValue(change)
        def check(res):
            # when_timestamp is converted from 21:55:39 Berlin time to UTC
            when_berlin = self.makeTime("2006/04/13 21:55:39")
            when_berlin = when_berlin.replace(tzinfo=dateutil.tz.gettz('Europe/Berlin'))
            when = datetime2epoch(when_berlin)

            self.assertEqual([ch['when_timestamp']
                              for ch in self.master.data.updates.changesAdded],
                             [when, when])
            self.assertAllCommandsRan()
Example #20
0
    def test_completeBuildset(self):
        yield self.insert_test_getBuildsets_data()
        yield self.db.buildsets.completeBuildset(bsid=91, results=6)
        bsdicts = yield self.db.buildsets.getBuildsets()

        bsdicts = [(bsdict['bsid'], bsdict['complete'],
                    datetime2epoch(bsdict['complete_at']),
                    bsdict['results'])
                   for bsdict in bsdicts]
        self.assertEqual(sorted(bsdicts), sorted([
            (91, 1, self.now, 6),
            (92, 1, 298297876, 7)]))
Example #21
0
        def thd(conn):
            # note that in a read-uncommitted database like SQLite this
            # transaction does not buy atomicitiy - other database users may
            # still come across a change without its links, files, properties,
            # etc.  That's OK, since we don't announce the change until it's
            # all in the database, but beware.

            transaction = conn.begin()

            # Trim long comment fields to 1024 characters, but preserve header
            # and footer with important tags such as Cr-Commit-Position.
            trimmed_comments = comments
            if len(trimmed_comments) > 1024:
              header, footer = trimmed_comments[:506], trimmed_comments[-506:]
              trimmed_comments = '%s\n...skip...\n%s' % (header, footer)

            ins = self.db.model.changes.insert()
            r = conn.execute(ins, dict(
                author=author,
                comments=trimmed_comments,
                is_dir=is_dir,
                branch=branch,
                revision=revision,
                revlink=revlink,
                when_timestamp=datetime2epoch(when_timestamp),
                category=category,
                repository=repository,
                project=project))
            changeid = r.inserted_primary_key[0]
            if links:
                ins = self.db.model.change_links.insert()
                conn.execute(ins, [
                    dict(changeid=changeid, link=l)
                        for l in links
                    ])
            if files:
                ins = self.db.model.change_files.insert()
                conn.execute(ins, [
                    dict(changeid=changeid, filename=f)
                        for f in files
                    ])
            if properties:
                ins = self.db.model.change_properties.insert()
                conn.execute(ins, [
                    dict(changeid=changeid,
                        property_name=k,
                        property_value=json.dumps(v))
                    for k,v in properties.iteritems()
                ])

            transaction.commit()

            return changeid
Example #22
0
        def thd(conn):
            # note that in a read-uncommitted database like SQLite this
            # transaction does not buy atomicity - other database users may
            # still come across a change without its files, properties,
            # etc.  That's OK, since we don't announce the change until it's
            # all in the database, but beware.

            transaction = conn.begin()

            r = conn.execute(ch_tbl.insert(), dict(
                author=author,
                comments=comments,
                branch=branch,
                revision=revision,
                revlink=revlink,
                when_timestamp=datetime2epoch(when_timestamp),
                category=category,
                repository=repository,
                codebase=codebase,
                project=project,
                sourcestampid=ssid,
                parent_changeids=parent_changeid))
            changeid = r.inserted_primary_key[0]
            if files:
                tbl = self.db.model.change_files
                for f in files:
                    self.checkLength(tbl.c.filename, f)
                conn.execute(tbl.insert(), [
                    dict(changeid=changeid, filename=f)
                    for f in files
                ])
            if properties:
                tbl = self.db.model.change_properties
                inserts = [
                    dict(changeid=changeid,
                         property_name=k,
                         property_value=json.dumps(v))
                    for k, v in iteritems(properties)
                ]
                for i in inserts:
                    self.checkLength(tbl.c.property_name,
                                     i['property_name'])
                    self.checkLength(tbl.c.property_value,
                                     i['property_value'])

                conn.execute(tbl.insert(), inserts)
            if uid:
                ins = self.db.model.change_users.insert()
                conn.execute(ins, dict(changeid=changeid, uid=uid))

            transaction.commit()

            return changeid
Example #23
0
    def db2data(self, bsdict):
        if not bsdict:
            defer.returnValue(None)

        buildset = bsdict.copy()

        # gather the actual sourcestamps, in parallel
        sourcestamps = []

        @defer.inlineCallbacks
        def getSs(ssid):
            ss = yield self.master.data.get(('sourcestamps', str(ssid)))
            sourcestamps.append(ss)
        yield defer.DeferredList([getSs(id)
                                  for id in buildset['sourcestamps']],
                                 fireOnOneErrback=True, consumeErrors=True)
        buildset['sourcestamps'] = sourcestamps

        # minor modifications
        buildset['submitted_at'] = datetime2epoch(buildset['submitted_at'])
        buildset['complete_at'] = datetime2epoch(buildset['complete_at'])

        defer.returnValue(buildset)
Example #24
0
    def claimBuildRequests(self, brids, claimed_at=None, _reactor=reactor):
        for brid in brids:
            if brid not in self.reqs or brid in self.claims:
                raise buildrequests.AlreadyClaimedError

        claimed_at = datetime2epoch(claimed_at)
        if not claimed_at:
            claimed_at = _reactor.seconds()

        # now that we've thrown any necessary exceptions, get started
        for brid in brids:
            self.claims[brid] = BuildRequestClaim(brid=brid,
                                                  objectid=self.MASTER_ID, claimed_at=claimed_at)
        return defer.succeed(None)
Example #25
0
        def thd(conn):
            # note that in a read-uncommitted database like SQLite this
            # transaction does not buy atomicitiy - other database users may
            # still come across a change without its links, files, properties,
            # etc.  That's OK, since we don't announce the change until it's
            # all in the database, but beware.

            transaction = conn.begin()

            ins = self.db.model.changes.insert()
            r = conn.execute(ins, dict(
                author=author,
                comments=comments,
                is_dir=is_dir,
                branch=branch,
                revision=revision,
                revlink=revlink,
                when_timestamp=datetime2epoch(when_timestamp),
                category=category,
                repository=repository,
                project=project))
            changeid = r.inserted_primary_key[0]
            if links:
                ins = self.db.model.change_links.insert()
                conn.execute(ins, [
                    dict(changeid=changeid, link=l)
                        for l in links
                    ])
            if files:
                ins = self.db.model.change_files.insert()
                conn.execute(ins, [
                    dict(changeid=changeid, filename=f)
                        for f in files
                    ])
            if properties:
                ins = self.db.model.change_properties.insert()
                conn.execute(ins, [
                    dict(changeid=changeid,
                        property_name=k,
                        property_value=json.dumps(v))
                    for k,v in properties.iteritems()
                ])
            if uid:
                ins = self.db.model.change_users.insert()
                conn.execute(ins, dict(changeid=changeid, uid=uid))

            transaction.commit()

            return changeid
        def check(res):
            # when_timestamp is converted from a local time spec, so just
            # replicate that here
            when = self.makeTime("2006/04/13 21:55:39")

            self.assertEqual(self.master.data.updates.changesAdded, [{
                'author': u'mpatel',
                'branch': u'branch_c',
                'category': None,
                'codebase': None,
                'comments': u'This is a multiline comment with tabs and spaces\n\nA list:\n  Item 1\n\tItem 2',
                'files': [u'branch_c_file'],
                'project': '',
                'properties': {},
                'repository': '',
                'revision': '5',
                'revlink': '',
                'src': None,
                'when_timestamp': datetime2epoch(when),
            }, {
                'author': u'mpatel',
                'branch': u'branch_b',
                'category': None,
                'codebase': None,
                'comments': u'This is a multiline comment with tabs and spaces\n\nA list:\n  Item 1\n\tItem 2',
                'files': [u'branch_b_file'],
                'project': '',
                'properties': {},
                'repository': '',
                'revision': '5',
                'revlink': '',
                'src': None,
                'when_timestamp': datetime2epoch(when),
            }])
            self.assertEquals(self.changesource.last_change, 5)
            self.assertAllCommandsRan()
Example #27
0
    def completeBuildRequests(self, brids, results, complete_at=None,
                              _reactor=reactor):
        if complete_at is not None:
            complete_at = datetime2epoch(complete_at)
        else:
            complete_at = _reactor.seconds()

        for brid in brids:
            if brid not in self.reqs or self.reqs[brid].complete == 1:
                raise buildrequests.NotClaimedError

        for brid in brids:
            self.reqs[brid].complete = 1
            self.reqs[brid].results = results
            self.reqs[brid].complete_at = complete_at
        def check(res):
            # when_timestamp is converted from a local time spec, so just
            # replicate that here
            when = self.makeTime("2006/04/13 21:55:39")

            self.assertEqual(self.master.data.updates.changesAdded, [{
                'author': u'mpatel',
                'branch': u'branch_c',
                'category': None,
                'codebase': None,
                'comments': u'Change 4 by mpatel@testclient on 2006/04/13 21:55:39\n\n\tshort desc truncated because this is a long description.\n',
                'files': [u'branch_c_file'],
                'project': '',
                'properties': {},
                'repository': '',
                'revision': '5',
                'revlink': '',
                'src': None,
                'when_timestamp': datetime2epoch(when),
            }, {
                'author': u'mpatel',
                'branch': u'branch_b',
                'category': None,
                'codebase': None,
                'comments': u'Change 4 by mpatel@testclient on 2006/04/13 21:55:39\n\n\tshort desc truncated because this is a long description.\n',
                'files': [u'branch_b_file'],
                'project': '',
                'properties': {},
                'repository': '',
                'revision': '5',
                'revlink': '',
                'src': None,
                'when_timestamp': datetime2epoch(when),
            }])
            self.assertEquals(self.changesource.last_change, 5)
            self.assertAllCommandsRan()
Example #29
0
    def completeBuildset(self, bsid, results, complete_at=None, _reactor=reactor):
        if complete_at is not None:
            complete_at = datetime2epoch(complete_at)
        else:
            complete_at = _reactor.seconds()

        def thd(conn):
            tbl = self.db.model.buildsets

            q = tbl.update(whereclause=((tbl.c.id == bsid) & ((tbl.c.complete == NULL) | (tbl.c.complete != 1))))
            res = conn.execute(q, complete=1, results=results, complete_at=complete_at)

            if res.rowcount != 1:
                raise KeyError

        return self.db.pool.do(thd)
Example #30
0
 def submitChanges(self, changes, request, src):
     for chdict in changes:
         when_timestamp = chdict.get('when_timestamp')
         if isinstance(when_timestamp, datetime):
             chdict['when_timestamp'] = datetime2epoch(when_timestamp)
         # unicodify stuff
         for k in ('comments', 'author', 'revision', 'branch', 'category',
                 'revlink', 'repository', 'codebase', 'project'):
             if k in chdict:
                 chdict[k] = bytes2unicode(chdict[k])
         if chdict.get('files'):
             chdict['files'] = [bytes2unicode(f)
                             for f in chdict['files']]
         if chdict.get('properties'):
             chdict['properties'] = dict((bytes2unicode(k), v)
                                         for k, v in chdict['properties'].items())
         chid = yield self.master.data.updates.addChange(src=bytes2unicode(src), **chdict)
         log.msg("injected change %s" % chid)
Example #31
0
    def _processChanges(self, page):
        result = json.loads(page, encoding=self.encoding)
        for pr in result['values']:
            branch = pr['source']['branch']['name']
            nr = int(pr['id'])
            # Note that this is a short hash. The full length hash can be accessed via the
            # commit api resource but we want to avoid requesting multiple pages as long as
            # we are not sure that the pull request is new or updated.
            revision = pr['source']['commit']['hash']

            # check branch
            if not self.branch or branch in self.branch:
                current = yield self._getCurrentRev(nr)

                # compare _short_ hashes to check if the PR has been updated
                if not current or current[0:12] != revision[0:12]:
                    # parse pull request api page (required for the filter)
                    page = yield client.getPage(str(pr['links']['self']['href']))
                    pr_json = json.loads(page, encoding=self.encoding)

                    # filter pull requests by user function
                    if not self.pullrequest_filter(pr_json):
                        log.msg('pull request does not match filter')
                        continue

                    # access additional information
                    author = pr['author']['display_name']
                    prlink = pr['links']['html']['href']
                    # Get time updated time. Note that the timezone offset is
                    # ignored.
                    if self.useTimestamps:
                        updated = datetime.strptime(
                            pr['updated_on'].split('.')[0],
                            '%Y-%m-%dT%H:%M:%S')
                    else:
                        updated = epoch2datetime(reactor.seconds())
                    title = pr['title']
                    # parse commit api page
                    page = yield client.getPage(str(pr['source']['commit']['links']['self']['href']))
                    commit_json = json.loads(page, encoding=self.encoding)
                    # use the full-length hash from now on
                    revision = commit_json['hash']
                    revlink = commit_json['links']['html']['href']
                    # parse repo api page
                    page = yield client.getPage(str(pr['source']['repository']['links']['self']['href']))
                    repo_json = json.loads(page, encoding=self.encoding)
                    repo = repo_json['links']['html']['href']

                    # update database
                    yield self._setCurrentRev(nr, revision)
                    # emit the change
                    yield self.master.data.updates.addChange(
                        author=bytes2unicode(author),
                        revision=bytes2unicode(revision),
                        revlink=bytes2unicode(revlink),
                        comments=u'pull-request #%d: %s\n%s' % (
                            nr, title, prlink),
                        when_timestamp=datetime2epoch(updated),
                        branch=bytes2unicode(branch),
                        category=self.category,
                        project=self.project,
                        repository=bytes2unicode(repo),
                        src=u'bitbucket',
                    )
Example #32
0
 def test_datetime2epoch(self):
     dt = datetime.datetime(1970, 1, 1, 0, 0, 0, tzinfo=util.UTC)
     self.assertEqual(util.datetime2epoch(dt), 0)
     dt = datetime.datetime(2011, 3, 13, 7, 6, 40, tzinfo=util.UTC)
     self.assertEqual(util.datetime2epoch(dt), 1300000000)
Example #33
0
    def addBuildset(self,
                    sourcestamps,
                    reason,
                    properties,
                    builderids,
                    waited_for,
                    external_idstring=None,
                    submitted_at=None,
                    parent_buildid=None,
                    parent_relationship=None,
                    _reactor=reactor):
        if submitted_at:
            submitted_at = datetime2epoch(submitted_at)
        else:
            submitted_at = _reactor.seconds()

        # convert to sourcestamp IDs first, as necessary
        def toSsid(sourcestamp):
            if isinstance(sourcestamp, integer_types):
                return defer.succeed(sourcestamp)
            else:
                ssConnector = self.master.db.sourcestamps
                return ssConnector.findSourceStampId(**sourcestamp)

        sourcestamps = yield defer.DeferredList(
            [toSsid(ss) for ss in sourcestamps],
            fireOnOneErrback=True,
            consumeErrors=True)
        sourcestampids = [r[1] for r in sourcestamps]

        def thd(conn):
            buildsets_tbl = self.db.model.buildsets

            self.checkLength(buildsets_tbl.c.reason, reason)
            self.checkLength(buildsets_tbl.c.external_idstring,
                             external_idstring)

            transaction = conn.begin()

            # insert the buildset itself
            r = conn.execute(
                buildsets_tbl.insert(),
                dict(submitted_at=submitted_at,
                     reason=reason,
                     complete=0,
                     complete_at=None,
                     results=-1,
                     external_idstring=external_idstring,
                     parent_buildid=parent_buildid,
                     parent_relationship=parent_relationship))
            bsid = r.inserted_primary_key[0]

            # add any properties
            if properties:
                bs_props_tbl = self.db.model.buildset_properties

                inserts = [
                    dict(buildsetid=bsid,
                         property_name=k,
                         property_value=json.dumps([v, s]))
                    for k, (v, s) in iteritems(properties)
                ]
                for i in inserts:
                    self.checkLength(bs_props_tbl.c.property_name,
                                     i['property_name'])

                conn.execute(bs_props_tbl.insert(), inserts)

            # add sourcestamp ids
            r = conn.execute(self.db.model.buildset_sourcestamps.insert(), [
                dict(buildsetid=bsid, sourcestampid=ssid)
                for ssid in sourcestampids
            ])

            # and finish with a build request for each builder.  Note that
            # sqlalchemy and the Python DBAPI do not provide a way to recover
            # inserted IDs from a multi-row insert, so this is done one row at
            # a time.
            brids = {}
            br_tbl = self.db.model.buildrequests
            ins = br_tbl.insert()
            for builderid in builderids:
                r = conn.execute(
                    ins,
                    dict(buildsetid=bsid,
                         builderid=builderid,
                         priority=0,
                         claimed_at=0,
                         claimed_by_name=None,
                         claimed_by_incarnation=None,
                         complete=0,
                         results=-1,
                         submitted_at=submitted_at,
                         complete_at=None,
                         waited_for=1 if waited_for else 0))

                brids[builderid] = r.inserted_primary_key[0]

            transaction.commit()

            return (bsid, brids)

        bsid, brids = yield self.db.pool.do(thd)

        # Seed the buildset property cache.
        self.getBuildsetProperties.cache.put(bsid, BsProps(properties))

        defer.returnValue((bsid, brids))
Example #34
0
 def run(self):
     older_than_timestamp = datetime2epoch(now() - self.logHorizon)
     deleted = yield self.master.db.logs.deleteOldLogChunks(
         older_than_timestamp)
     self.descriptionDone = ["deleted", str(deleted), "logchunks"]
     defer.returnValue(SUCCESS)
Example #35
0
        def check_second_check(res):

            # when_timestamp is converted from a local time spec, so just
            # replicate that here
            when1 = self.makeTime("2006/04/13 21:46:23")
            when2 = self.makeTime("2006/04/13 21:51:39")

            # these two can happen in either order, since they're from the same
            # perforce change.
            changesAdded = self.master.data.updates.changesAdded
            if changesAdded[1]['branch'] == 'branch_c':
                changesAdded[1:] = reversed(changesAdded[1:])
            self.assertEqual(self.master.data.updates.changesAdded, [{
                'author':
                u'slamb',
                'branch':
                u'trunk',
                'category':
                None,
                'codebase':
                None,
                'comments':
                u'creation',
                'files': [u'whatbranch'],
                'project':
                '',
                'properties': {},
                'repository':
                '',
                'revision':
                '2',
                'revlink':
                '',
                'src':
                None,
                'when_timestamp':
                datetime2epoch(when1),
            }, {
                'author':
                u'bob',
                'branch':
                u'branch_b',
                'category':
                None,
                'codebase':
                None,
                'comments':
                u'short desc truncated because this is a long description.\nASDF-GUI-P3-\u2018Upgrade Icon\u2019 disappears sometimes.',
                'files': [u'branch_b_file', u'whatbranch'],
                'project':
                '',
                'properties': {},
                'repository':
                '',
                'revision':
                '3',
                'revlink':
                '',
                'src':
                None,
                'when_timestamp':
                datetime2epoch(when2),
            }, {
                'author':
                u'bob',
                'branch':
                u'branch_c',
                'category':
                None,
                'codebase':
                None,
                'comments':
                u'short desc truncated because this is a long description.\nASDF-GUI-P3-\u2018Upgrade Icon\u2019 disappears sometimes.',
                'files': [u'whatbranch'],
                'project':
                '',
                'properties': {},
                'repository':
                '',
                'revision':
                '3',
                'revlink':
                '',
                'src':
                None,
                'when_timestamp':
                datetime2epoch(when2),
            }])
            self.assertAllCommandsRan()
Example #36
0
    def _processChanges(self, github_result):
        for pr in github_result:
            # Track PRs for specified branches
            base_branch = pr['base']['ref']
            prnumber = pr['number']
            revision = pr['head']['sha']

            # Check to see if the branch is set or matches
            if self.branches is not None and base_branch not in self.branches:
                continue
            if (self.pullrequest_filter is not None
                    and not self.pullrequest_filter(pr)):
                continue
            current = yield self._getCurrentRev(prnumber)
            if not current or current[0:12] != revision[0:12]:
                # Access title, repo, html link, and comments
                pr = yield self._getPullInformation(prnumber)
                title = pr['title']
                if self.magic_link:
                    branch = 'refs/pull/{:d}/merge'.format(prnumber)
                    repo = pr['base']['repo'][self.repository_type]
                else:
                    branch = pr['head']['ref']
                    repo = pr['head']['repo'][self.repository_type]
                revlink = pr['html_url']
                comments = pr['body']
                updated = datetime.strptime(pr['updated_at'],
                                            '%Y-%m-%dT%H:%M:%SZ')
                # update database
                yield self._setCurrentRev(prnumber, revision)

                author = pr['user']['login']
                project = pr['base']['repo']['full_name']
                commits = pr['commits']

                dl = defer.DeferredList(
                    [self._getFiles(prnumber),
                     self._getEmail(author)],
                    consumeErrors=True)

                results = yield dl
                failures = [r[1] for r in results if not r[0]]
                if failures:
                    for failure in failures:
                        log.error("while processing changes for "
                                  "Pullrequest {} revision {}".format(
                                      prnumber, revision))
                        # Fail on the first error!
                        failures[0].raiseException()
                [files, email] = [r[1] for r in results]

                if email is not None and email != "null":
                    author += " <" + str(email) + ">"

                properties = self.extractProperties(pr)

                # emit the change
                yield self.master.data.updates.addChange(
                    author=bytes2unicode(author),
                    revision=bytes2unicode(revision),
                    revlink=bytes2unicode(revlink),
                    comments='GitHub Pull Request #{0} ({1} commit{2})\n{3}\n{4}'
                    .format(prnumber, commits, 's' if commits > 0 else '',
                            title, comments),
                    when_timestamp=datetime2epoch(updated),
                    branch=bytes2unicode(branch),
                    category=self.category,
                    project=project,
                    repository=bytes2unicode(repo),
                    files=files,
                    properties=properties,
                    src='git')
Example #37
0
        def thd(conn):
            # note that in a read-uncommitted database like SQLite this
            # transaction does not buy atomicitiy - other database users may
            # still come across a change without its files, properties,
            # etc.  That's OK, since we don't announce the change until it's
            # all in the database, but beware.

            transaction = conn.begin()

            ch_tbl = self.db.model.changes

            self.check_length(ch_tbl.c.author, author)
            self.check_length(ch_tbl.c.comments, comments)
            self.check_length(ch_tbl.c.branch, branch)
            self.check_length(ch_tbl.c.revision, revision)
            self.check_length(ch_tbl.c.revlink, revlink)
            self.check_length(ch_tbl.c.category, category)
            self.check_length(ch_tbl.c.repository, repository)
            self.check_length(ch_tbl.c.project, project)

            r = conn.execute(
                ch_tbl.insert(),
                dict(author=author,
                     comments=comments,
                     is_dir=is_dir,
                     branch=branch,
                     revision=revision,
                     revlink=revlink,
                     when_timestamp=datetime2epoch(when_timestamp),
                     category=category,
                     repository=repository,
                     codebase=codebase,
                     project=project))
            changeid = r.inserted_primary_key[0]
            if files:
                tbl = self.db.model.change_files
                for f in files:
                    self.check_length(tbl.c.filename, f)
                conn.execute(
                    tbl.insert(),
                    [dict(changeid=changeid, filename=f) for f in files])
            if properties:
                tbl = self.db.model.change_properties
                inserts = [
                    dict(changeid=changeid,
                         property_name=k,
                         property_value=json.dumps(v))
                    for k, v in properties.iteritems()
                ]
                for i in inserts:
                    self.check_length(tbl.c.property_name, i['property_name'])
                    self.check_length(tbl.c.property_value,
                                      i['property_value'])

                conn.execute(tbl.insert(), inserts)
            if uid:
                ins = self.db.model.change_users.insert()
                conn.execute(ins, dict(changeid=changeid, uid=uid))

            transaction.commit()

            return changeid
Example #38
0
    def test_poll_split_file(self):
        """Make sure split file works on branch only changes"""
        yield self.attachChangeSource(
            P4Source(p4port=None, p4user=None,
                     p4base='//depot/myproject/',
                     split_file=get_simple_split))
        self.expect_commands(
            ExpectMasterShell(['p4', 'changes', '//depot/myproject/...@51,#head'])
            .stdout(third_p4changes),
        )
        self.add_p4_describe_result(5, p4change[5])

        self.changesource.last_change = 50
        yield self.changesource.poll()

        # when_timestamp is converted from a local time spec, so just
        # replicate that here
        when = self.makeTime("2006/04/13 21:55:39")

        def changeKey(change):
            """ Let's sort the array of changes by branch,
                because in P4Source._poll(), changeAdded()
                is called by iterating over a dictionary of
                branches"""
            return change['branch']

        self.assertEqual(sorted(self.master.data.updates.changesAdded, key=changeKey),
            sorted([{
            'author': 'mpatel',
            'committer': None,
            'branch': 'branch_c',
            'category': None,
            'codebase': None,
            'comments': 'This is a multiline comment with tabs and spaces\n\nA list:\n  '
                        'Item 1\n\tItem 2',
            'files': ['branch_c_file'],
            'project': '',
            'properties': {},
            'repository': '',
            'revision': '5',
            'revlink': '',
            'src': None,
            'when_timestamp': datetime2epoch(when),
        }, {
            'author': 'mpatel',
            'committer': None,
            'branch': 'branch_b',
            'category': None,
            'codebase': None,
            'comments': 'This is a multiline comment with tabs and spaces\n\nA list:\n  '
                        'Item 1\n\tItem 2',
            'files': ['branch_b_file'],
            'project': '',
            'properties': {},
            'repository': '',
            'revision': '5',
            'revlink': '',
            'src': None,
            'when_timestamp': datetime2epoch(when),
        }], key=changeKey))
        self.assertEqual(self.changesource.last_change, 5)
        self.assert_all_commands_ran()
    def _poll(self):
        if self.use_tickets:
            self._ticket_login_counter -= 1
            if self._ticket_login_counter <= 0:
                # Re-acquire the ticket and reset the counter.
                log.msg("P4Poller: (re)acquiring P4 ticket for %s..." %
                        self.p4base)
                protocol = TicketLoginProtocol(self.p4passwd + "\n",
                                               self.p4base)
                self._acquireTicket(protocol)
                yield protocol.deferred

                self._ticket_passwd = self._parseTicketPassword(
                    protocol.stdout)
                self._ticket_login_counter = max(
                    self.ticket_login_interval / self.pollInterval, 1)
                if debug_logging:
                    log.msg("P4Poller: got ticket password: %s" %
                            self._ticket_passwd)
                    log.msg("P4Poller: next ticket acquisition in %d polls" %
                            self._ticket_login_counter)

        args = []
        if self.p4port:
            args.extend(['-p', self.p4port])
        if self.p4user:
            args.extend(['-u', self.p4user])
        if self.p4passwd:
            args.extend(['-P', self._getPasswd()])
        args.extend(['changes'])
        if self.last_change is not None:
            args.extend(
                ['%s...@%d,#head' % (self.p4base, self.last_change + 1)])
        else:
            args.extend(['-m', '1', '%s...' % (self.p4base, )])

        result = yield self._get_process_output(args)
        # decode the result from its designated encoding
        try:
            result = bytes2unicode(result, self.encoding)
        except UnicodeError as ex:
            log.msg(u"Warning: cannot fully decode {} in {}".format(
                repr(result), self.encoding))
            result = bytes2unicode(result,
                                   encoding=self.encoding,
                                   errors="replace")

        last_change = self.last_change
        changelists = []
        for line in result.split('\n'):
            line = line.strip()
            if not line:
                continue
            m = self.changes_line_re.match(line)
            if not m:
                raise P4PollerError("Unexpected 'p4 changes' output: %r" %
                                    result)
            num = int(m.group('num'))
            if last_change is None:
                # first time through, the poller just gets a "baseline" for where to
                # start on the next poll
                log.msg('P4Poller: starting at change %d' % num)
                self.last_change = num
                return
            changelists.append(num)
        changelists.reverse()  # oldest first

        # Retrieve each sequentially.
        for num in changelists:
            args = []
            if self.p4port:
                args.extend(['-p', self.p4port])
            if self.p4user:
                args.extend(['-u', self.p4user])
            if self.p4passwd:
                args.extend(['-P', self._getPasswd()])
            args.extend(['describe', '-s', str(num)])
            result = yield self._get_process_output(args)

            # decode the result from its designated encoding
            try:
                result = bytes2unicode(result, self.encoding)
            except UnicodeError as ex:
                log.msg(
                    "P4Poller: couldn't decode changelist description: %s" %
                    ex.encoding)
                log.msg("P4Poller: in object: %s" % ex.object)
                log.err("P4Poller: poll failed on %s, %s" %
                        (self.p4port, self.p4base))
                raise

            lines = result.split('\n')
            # SF#1555985: Wade Brainerd reports a stray ^M at the end of the date
            # field. The rstrip() is intended to remove that.
            lines[0] = lines[0].rstrip()
            m = self.describe_header_re.match(lines[0])
            if not m:
                raise P4PollerError("Unexpected 'p4 describe -s' result: %r" %
                                    result)
            who = m.group('who')
            when = datetime.datetime.strptime(m.group('when'), self.datefmt)
            if self.server_tz:
                # Convert from the server's timezone to the local timezone.
                when = when.replace(tzinfo=self.server_tz)
            when = util.datetime2epoch(when)

            comment_lines = []
            lines.pop(0)  # describe header
            lines.pop(0)  # blank line
            while not lines[0].startswith('Affected files'):
                if lines[0].startswith('\t'):  # comment is indented by one tab
                    comment_lines.append(lines.pop(0)[1:])
                else:
                    lines.pop(0)  # discard non comment line
            comments = '\n'.join(comment_lines)

            lines.pop(0)  # affected files
            branch_files = {}  # dict for branch mapped to file(s)
            while lines:
                line = lines.pop(0).strip()
                if not line:
                    continue
                m = self.file_re.match(line)
                if not m:
                    raise P4PollerError("Invalid file line: %r" % line)
                path = m.group('path')
                if path.startswith(self.p4base):
                    branch, file = self.split_file(path[len(self.p4base):])
                    if (branch is None and file is None):
                        continue
                    if branch in branch_files:
                        branch_files[branch].append(file)
                    else:
                        branch_files[branch] = [file]

            for branch in branch_files:
                yield self.master.data.updates.addChange(
                    author=who,
                    files=branch_files[branch],
                    comments=comments,
                    revision=text_type(num),
                    when_timestamp=when,
                    branch=branch,
                    project=self.project)

            self.last_change = num
Example #40
0
 def run(self):
     older_than_timestamp = datetime2epoch(now() - self.build_data_horizon)
     deleted = yield self.master.db.build_data.deleteOldBuildData(older_than_timestamp)
     self.descriptionDone = ["deleted", str(deleted), "build data key-value pairs"]
     return SUCCESS
Example #41
0
 def _toJson(self, obj):
     if isinstance(obj, datetime.datetime):
         return datetime2epoch(obj)
Example #42
0
def populate_build(db,
                   build_count,
                   builders_list,
                   projects,
                   user_names,
                   verbose=True):
    """
    :param db: a handler to the DBConnection object
    :param build_count: an integer value with number of new builds
    :param builders_list: a list of builders. The builder is a BuilderConfig object
    :param projects: a list of a ProjectConfig objects
    :param user_names: a list of an usernames (identifier) from the database
    :param verbose: a boolean value indicate to print all information to std output
    """
    from progress_bar import InitBar

    def handler(result, counter, *args):
        result[counter] += 1

    progress_bar = InitBar(size=build_count, stream=sys.stdout)

    if verbose:
        print("Starting creating builds")
    res = {
        'created': 0,
        'skipped': 0,
    }

    for number in range(build_count):
        builder = random.choice(builders_list)
        codebases = random.choice(projects[builder.project].codebases)
        codebase = random.choice(codebases.keys())
        repository = codebases[codebase]
        submitted_at = datetime2epoch(
            datetime.datetime.now() + datetime.timedelta(
                seconds=random.randint(-3 * 60 * 60, -3 * 60 * 60)))
        complete_at = submitted_at + random.randint(60 * 60, 3 * 60 * 60)
        build = {
            'branch':
            repository['branch'],
            'revision':
            "%032x" % random.getrandbits(160),  # Random sha-1 hash
            'repository':
            repository['repository'],
            'codebase':
            codebase,
            'project':
            builder.project,
            'reason':
            'A build was forced by {username} {username}@localhost'.format(
                username=random.choice(user_names)),
            'submitted_at':
            submitted_at,
            'complete_at':
            complete_at,
            'buildername':
            builder.name,
            'slavepool':
            None,
            'number':
            number,
            'slavename':
            random.choice(builder.slavenames),
            'results':
            random.choice(COMPLETED_RESULTS),
        }
        promise = db.builds.createFullBuildObject(**build)
        promise.addCallback(lambda *args: handler(res, 'created'))
        promise.addErrback(lambda *args: handler(res, 'skipped'))
        yield promise

        if verbose:
            progress_bar(number + 1)

    if verbose:
        print()
        print("Created %d new builds, %d skipped" %
              (res['created'], res['skipped']))
Example #43
0
    def do_test_poll_successful(self, **kwargs):
        encoding = kwargs.get('encoding', 'utf8')
        yield self.attachChangeSource(
            P4Source(p4port=None, p4user=None,
                     p4base='//depot/myproject/',
                     split_file=lambda x: x.split('/', 1),
                     **kwargs))
        self.expect_commands(
            ExpectMasterShell(['p4', 'changes', '-m', '1', '//depot/myproject/...'])
            .stdout(first_p4changes),

            ExpectMasterShell(['p4', 'changes', '//depot/myproject/...@2,#head'])
            .stdout(second_p4changes),
        )
        encoded_p4change = p4change.copy()
        encoded_p4change[3] = encoded_p4change[3].encode(encoding)
        self.add_p4_describe_result(2, encoded_p4change[2])
        self.add_p4_describe_result(3, encoded_p4change[3])

        # The first time, it just learns the change to start at.
        self.assertTrue(self.changesource.last_change is None)
        yield self.changesource.poll()

        self.assertEqual(self.master.data.updates.changesAdded, [])
        self.assertEqual(self.changesource.last_change, 1)

        # Subsequent times, it returns Change objects for new changes.
        yield self.changesource.poll()

        # when_timestamp is converted from a local time spec, so just
        # replicate that here
        when1 = self.makeTime("2006/04/13 21:46:23")
        when2 = self.makeTime("2006/04/13 21:51:39")

        # these two can happen in either order, since they're from the same
        # perforce change.
        changesAdded = self.master.data.updates.changesAdded
        if changesAdded[1]['branch'] == 'branch_c':
            changesAdded[1:] = reversed(changesAdded[1:])
        self.assertEqual(self.master.data.updates.changesAdded, [{
            'author': 'slamb',
            'committer': None,
            'branch': 'trunk',
            'category': None,
            'codebase': None,
            'comments': 'creation',
            'files': ['whatbranch'],
            'project': '',
            'properties': {},
            'repository': '',
            'revision': '2',
            'revlink': '',
            'src': None,
            'when_timestamp': datetime2epoch(when1),
        }, {
            'author': 'bob',
            'committer': None,
            'branch': 'branch_b',
            'category': None,
            'codebase': None,
            'comments':
                'short desc truncated because this is a long description.\n'
                'ASDF-GUI-P3-\u2018Upgrade Icon\u2019 disappears sometimes.',
            'files': ['branch_b_file', 'whatbranch'],
            'project': '',
            'properties': {},
            'repository': '',
            'revision': '3',
            'revlink': '',
            'src': None,
            'when_timestamp': datetime2epoch(when2),
        }, {
            'author': 'bob',
            'committer': None,
            'branch': 'branch_c',
            'category': None,
            'codebase': None,
            'comments':
                'short desc truncated because this is a long description.\n'
                'ASDF-GUI-P3-\u2018Upgrade Icon\u2019 disappears sometimes.',
            'files': ['whatbranch'],
            'project': '',
            'properties': {},
            'repository': '',
            'revision': '3',
            'revlink': '',
            'src': None,
            'when_timestamp': datetime2epoch(when2),
        }])
        self.assert_all_commands_ran()