def post(self, repo: Repository):
        """
        Create a new build.
        """
        schema = BuildCreateSchema(context={"repository": repo})
        build = self.schema_from_request(schema)
        db.session.add(build)

        try:
            db.session.commit()
        except IntegrityError as exc:
            if "duplicate" in str(exc):
                db.session.rollback()
                return self.respond(status=422)
            raise

        if not build.revision_sha:
            from zeus.tasks import resolve_ref_for_build

            resolve_ref_for_build.delay(build_id=build.id)

        build_schema.validate(build)
        data = build_schema.dump(build)
        publish("builds", "build.create", data)

        return self.respond(data, 200)
Beispiel #2
0
    def post(self, repo: Repository):
        """
        Create a new build.
        """
        schema = BuildCreateSchema(strict=True, context={"repository": repo})
        result = self.schema_from_request(schema, partial=True)
        if result.errors:
            return self.respond(result.errors, 403)

        data = result.data

        # TODO(dcramer): only if we create a source via a patch will we need the author
        # author_data = data.pop('author')
        # if author_data.get('email'):
        #     author = Author.query.filter(
        #         Author.repository_id == repo.id, Author.email == author_data['email']
        #     ).first()
        # else:
        #     author = None
        # if not author:
        #     author = Author(repository_id=repo.id, **author_data)
        #     db.session.add(author)
        #     db.session.flush()

        # TODO(dcramer): need to handle patch case yet
        source = (Source.query.options(
            joinedload("author"), joinedload("revision")).filter(
                Source.revision_sha == data.pop("ref"),
                Source.repository_id == repo.id).first())

        build = Build(repository=repo, **data)
        # TODO(dcramer): we should convert source in the schema
        build.source = source
        # build.source_id = source.id
        build.author = source.author
        if not source.patch_id:
            if not build.label:
                build.label = source.revision.message.split("\n")[0]

        if not build.label:
            return self.error("missing build label")

        db.session.add(build)

        try:
            db.session.commit()
        except IntegrityError:
            db.session.rollback()
            return self.respond(status=422)

        result = build_schema.dump(build)
        assert not result.errors, "this should never happen"
        publish("builds", "build.create", result.data)
        return self.respond(result.data, 200)
Beispiel #3
0
def resolve_ref_for_build(build_id: UUID):
    lock_key = f"resolve-build-ref:{build_id}"
    with redis.lock(lock_key, timeout=60.0, nowait=True):
        build = Build.query.unrestricted_unsafe().get(build_id)
        if not build:
            raise ValueError(
                "Unable to find build with id = {}".format(build_id))

        if build.revision_sha:
            return

        auth.set_current_tenant(
            auth.RepositoryTenant(repository_id=build.repository_id))

        revision: Optional[Revision] = None
        try:
            revision = revisions.identify_revision(build.repository,
                                                   build.ref,
                                                   with_vcs=True)
        except UnknownRevision:
            build.result = Result.errored
            build.status = Status.finished
            try:
                with db.session.begin_nested():
                    db.session.add(
                        FailureReason(
                            repository_id=build.repository_id,
                            build_id=build.id,
                            reason=FailureReason.Reason.unresolvable_ref,
                        ))
                    db.session.flush()
            except IntegrityError as exc:
                if "duplicate" not in str(exc):
                    raise

        except InvalidPublicKey:
            pass

        if revision:
            build.revision_sha = revision.sha
            if not build.authors and revision.authors:
                build.authors = revision.authors
            if not build.label:
                build.label = revision.message.split("\n")[0]
        db.session.add(build)
        db.session.commit()

    data = build_schema.dump(build)
    publish("builds", "build.update", data)
Beispiel #4
0
    def put(self, build: Build):
        """
        Update a build.
        """
        result = self.schema_from_request(build_schema, partial=True)

        for key, value in result.items():
            if getattr(build, key) != value:
                setattr(build, key, value)
        if db.session.is_modified(build):
            db.session.add(build)
            db.session.commit()

        result = build_schema.dump(build)
        publish("builds", "build.update", result)
        return self.respond(result, 200)
Beispiel #5
0
    def put(self, build: Build):
        """
        Update a build.
        """
        result = self.schema_from_request(build_schema, partial=True)
        if result.errors:
            return self.respond(result.errors, 403)
        for key, value in result.data.items():
            if getattr(build, key) != value:
                setattr(build, key, value)
        if db.session.is_modified(build):
            db.session.add(build)
            db.session.commit()

        result = build_schema.dump(build)
        if result.errors:
            return self.error('invalid schema supplied')
        publish('builds', 'build.update', result.data)
        return self.respond(result.data, 200)
Beispiel #6
0
def mock_build(repo: models.Repository, parent_revision: models.Revision=None,
               user_ids=(), file_list=()):
    if user_ids and randint(0, 1) == 0:
        chosen_user_id = choice(user_ids)
        author = mock_author(repo, chosen_user_id)
    else:
        author = None

    revision = factories.RevisionFactory.create(
        repository=repo,
        parents=[parent_revision.sha] if parent_revision else None,
        **{'author': author} if author else {}
    )
    source = factories.SourceFactory.create(
        revision=revision,
        patch=factories.PatchFactory(
            parent_revision=parent_revision,
        ) if parent_revision and random() > 0.8 else None,
    )
    parent_revision = revision

    build = factories.BuildFactory.create(source=source, travis=True)

    result = build_schema.dump(build)
    publish('builds', 'build.create', result.data)
    click.echo('Created {!r}'.format(build))

    # we need to find some filenames for the repo
    if file_list is None:
        file_list = find_files_in_repo(repo)

    for n in range(randint(0, 50)):
        try:
            with db.session.begin_nested():
                factories.FileCoverageFactory.create(
                    filename=choice(file_list),
                    build=build, in_diff=randint(0, 5) == 0)
        except IntegrityError:
            continue

    for n in range(1, 4):
        has_failure = randint(0, 2) == 0
        job = factories.JobFactory.create(
            build=build,
            failed=has_failure,
            passed=not has_failure,
            travis=True,
            allow_failure=n == 3,
        )

        for n in range(randint(0, 50)):
            test_failed = has_failure and randint(0, 5) == 0
            factories.TestCaseFactory.create(
                job=job,
                failed=test_failed,
                passed=not test_failed,
            )
            if has_failure and randint(0, 2) == 0:
                for n in range(1, 5):
                    factories.StyleViolationFactory.create(
                        job=job,
                    )

        for n in range(randint(0, 2)):
            bundle = factories.BundleFactory.create(
                job=job,
            )
            for n in range(randint(0, 4)):
                factories.BundleAssetFactory.create(
                    bundle=bundle,
                    job=job,
                )

        artifact_count = randrange(3) \
            if job.status == Status.finished and job.result == Result.passed \
            else 0
        for n in range(0, artifact_count):
            factories.ArtifactFactory.create(job=job, repository=repo)

        db.session.commit()

        aggregate_build_stats_for_job(job_id=job.id)

        result = build_schema.dump(build)
        publish('builds', 'build.create', result.data)
        click.echo('Created {!r}'.format(build))

    db.session.commit()
    return build
Beispiel #7
0
def mock_build(
        repo: models.Repository,
        revision: models.Revision = None,
        parent_revision: models.Revision = None,
        user_ids=(),
        file_list=(),
        with_change_request=True,
) -> models.Build:
    if user_ids and randint(0, 1) == 0:
        chosen_user_id = choice(user_ids)
        author = mock_author(repo, chosen_user_id)
    else:
        author = None

    if not revision:
        revision, source = mock_revision(repo, parent_revision, author)
    else:
        for n in range(2):
            source = (models.Source.query.unrestricted_unsafe().filter(
                models.Source.repository_id == repo.id,
                models.Source.revision_sha == revision.sha,
            ).first())
            if source:
                break
            try_create(
                models.Source,
                {
                    "revision_sha": revision.sha,
                    "repository": repo,
                    "author_id": revision.author_id,
                },
            )
        else:
            raise NotImplementedError

    if with_change_request and parent_revision is None:
        parent_revision = factories.RevisionFactory.create(repository=repo)

    if with_change_request:
        factories.ChangeRequestFactory.create(
            repository=repo,
            head_revision=revision,
            head_revision_sha=revision.sha,
            parent_revision=parent_revision,
            github=True,
            **{"author": author} if author else {})

    parent_revision = revision

    build = factories.BuildFactory.create(source=source, travis=True)

    result = build_schema.dump(build)
    publish("builds", "build.create", result.data)
    click.echo("Created {!r}".format(build))

    # we need to find some filenames for the repo
    if file_list is None:
        file_list = find_files_in_repo(repo)

    for n in range(randint(0, 50)):
        try:
            with db.session.begin_nested():
                factories.FileCoverageFactory.create(
                    filename=choice(file_list),
                    build=build,
                    in_diff=randint(0, 5) == 0)
        except IntegrityError:
            continue

    for n in range(1, 4):
        has_failure = randint(0, 2) == 0
        job = factories.JobFactory.create(
            build=build,
            failed=has_failure,
            passed=not has_failure,
            travis=True,
            allow_failure=n == 3,
        )

        for n in range(randint(0, 50)):
            test_failed = has_failure and randint(0, 5) == 0
            factories.TestCaseFactory.create(job=job,
                                             failed=test_failed,
                                             passed=not test_failed)
            if has_failure and randint(0, 2) == 0:
                for n in range(1, 5):
                    factories.StyleViolationFactory.create(job=job)

        for n in range(randint(0, 2)):
            bundle = factories.BundleFactory.create(job=job)
            for n in range(randint(0, 4)):
                factories.BundleAssetFactory.create(bundle=bundle, job=job)

        artifact_count = (randrange(3) if job.status == Status.finished
                          and job.result == Result.passed else 0)
        for n in range(0, artifact_count):
            factories.ArtifactFactory.create(job=job,
                                             repository=repo,
                                             finished=True)

        db.session.commit()

        aggregate_build_stats_for_job(job_id=job.id)

        result = build_schema.dump(build)
        publish("builds", "build.update", result.data)
        click.echo("Created {!r}".format(job))

    db.session.commit()
    return build
Beispiel #8
0
    def post(self, repo: Repository):
        """
        Create a new build.
        """
        result = self.schema_from_request(build_create_schema, partial=True)
        if result.errors:
            return self.respond(result.errors, 403)
        data = result.data

        ref = data.pop('ref', None)
        if ref is None:
            return self.error('missing ref')

        try:
            revision = identify_revision(repo, ref)
        except UnknownRevision:
            current_app.logger.warn('invalid ref received', exc_info=True)
            return self.error('unable to find a revision matching ref')

        # TODO(dcramer): only if we create a source via a patch will we need the author
        # author_data = data.pop('author')
        # if author_data.get('email'):
        #     author = Author.query.filter(
        #         Author.repository_id == repo.id, Author.email == author_data['email']
        #     ).first()
        # else:
        #     author = None
        # if not author:
        #     author = Author(repository_id=repo.id, **author_data)
        #     db.session.add(author)
        #     db.session.flush()

        # TODO(dcramer): need to handle patch case yet
        source = Source.query.options(
            joinedload('author'),
        ).filter(
            Source.revision_sha == revision.sha,
            Source.repository_id == repo.id,
        ).first()

        build = Build(repository=repo, **data)
        # TODO(dcramer): we should convert source in the schema
        build.source = source
        # build.source_id = source.id
        build.author = source.author
        if not source.patch_id:
            if not build.label:
                build.label = source.revision.message.split('\n')[0]

        if not build.label:
            return self.error('missing build label')

        db.session.add(build)

        try:
            db.session.commit()
        except IntegrityError:
            db.session.rollback()
            return self.respond(status=422)

        result = build_schema.dump(build)
        assert not result.errors, 'this should never happen'
        publish('builds', 'build.create', result.data)
        return self.respond(result.data, 200)
Beispiel #9
0
async def mock_build(
        repo: models.Repository,
        revision: models.Revision = None,
        parent_revision: models.Revision = None,
        user_ids=(),
        file_list=(),
        with_change_request=True,
) -> models.Build:
    author: Optional[models.Author] = None
    if user_ids and randint(0, 1) == 0:
        chosen_user_id = choice(user_ids)
        author = await mock_author(repo, chosen_user_id)

    if not revision:
        revision = await mock_revision(repo, parent_revision, author)

    if with_change_request and parent_revision is None:
        parent_revision = factories.RevisionFactory.create(repository=repo)

    if with_change_request:
        factories.ChangeRequestFactory.create(
            repository=repo,
            head_revision=revision,
            head_revision_sha=revision.sha,
            parent_revision=parent_revision,
            github=True,
            **{"authors": [author]} if author else {})

    parent_revision = revision

    build = factories.BuildFactory.create(revision=revision, travis=True)

    data = build_schema.dump(build)
    publish("builds", "build.create", data)
    click.echo("Created {!r}".format(build))

    # we need to find some filenames for the repo
    if file_list is None:
        file_list = find_files_in_repo(repo)

    for n in range(randint(0, 50)):
        try:
            with db.session.begin_nested():
                factories.FileCoverageFactory.create(
                    filename=choice(file_list),
                    build=build,
                    in_diff=randint(0, 5) == 0)
        except IntegrityError:
            continue

    for n in range(1, 4):
        has_failure = randint(0, 2) == 0
        job = factories.JobFactory.create(
            build=build,
            failed=has_failure,
            passed=not has_failure,
            travis=True,
            allow_failure=n == 3,
        )

        for n in range(randint(0, 50)):
            test_failed = has_failure and randint(0, 5) == 0
            factories.TestCaseFactory.create(job=job,
                                             failed=test_failed,
                                             passed=not test_failed)
            if has_failure and randint(0, 2) == 0:
                for n in range(1, 5):
                    factories.StyleViolationFactory.create(job=job)

        for n in range(randint(0, 2)):
            bundle = factories.BundleFactory.create(job=job)
            for n in range(randint(0, 4)):
                factories.BundleAssetFactory.create(bundle=bundle, job=job)

        factories.FailureReasonFactory.create(build=build,
                                              job=job,
                                              failing_tests=True)

        artifact_count = (randrange(3) if job.status == Status.finished
                          and job.result == Result.passed else 0)
        for n in range(0, artifact_count):
            factories.ArtifactFactory.create(job=job,
                                             repository=repo,
                                             finished=True)

        db.session.commit()

        aggregate_build_stats_for_job(job_id=job.id)

        data = build_schema.dump(build)
        publish("builds", "build.update", data)
        click.echo("Created {!r}".format(job))

    db.session.commit()
    return build