Ejemplo n.º 1
0
    def handle_trigger_request(self, request):
        payload = request.get_json()
        if not payload:
            raise InvalidPayloadException()

        logger.debug("GitLab trigger payload %s", payload)

        # Lookup the default branch.
        gl_client = self._get_authorized_client()
        gl_project = gl_client.projects.get(self.config["build_source"])
        if not gl_project:
            logger.debug("Skipping GitLab build; project %s not found", self.config["build_source"])
            raise InvalidPayloadException()

        def lookup_commit(repo_id, commit_sha):
            commit = self.lookup_commit(repo_id, commit_sha)
            if commit is None:
                return None

            return dict(commit.attributes)

        default_branch = gl_project.attributes["default_branch"]
        metadata = get_transformed_webhook_payload(
            payload,
            default_branch=default_branch,
            lookup_user=self.lookup_user,
            lookup_commit=lookup_commit,
        )
        prepared = self.prepare_build(metadata)

        # Check if we should skip this build.
        raise_if_skipped_build(prepared, self.config)
        return prepared
Ejemplo n.º 2
0
    def handle_trigger_request(self, request):
        # Check the payload to see if we should skip it based on the lack of a head_commit.
        payload = request.get_json()
        if payload is None:
            raise InvalidPayloadException("Missing payload")

        # This is for GitHub's probing/testing.
        if "zen" in payload:
            raise SkipRequestException()

        # Lookup the default branch for the repository.
        if "repository" not in payload:
            raise InvalidPayloadException("Missing 'repository' on request")

        if "owner" not in payload["repository"]:
            raise InvalidPayloadException("Missing 'owner' on repository")

        if "name" not in payload["repository"]["owner"]:
            raise InvalidPayloadException("Missing owner 'name' on repository")

        if "name" not in payload["repository"]:
            raise InvalidPayloadException("Missing 'name' on repository")

        default_branch = None
        lookup_user = None
        try:
            repo_full_name = "%s/%s" % (
                payload["repository"]["owner"]["name"],
                payload["repository"]["name"],
            )

            gh_client = self._get_client()
            repo = gh_client.get_repo(repo_full_name)
            default_branch = repo.default_branch
            lookup_user = self.lookup_user
        except GitHubBadCredentialsException:
            logger.exception(
                "Got GitHub Credentials Exception; Cannot lookup default branch"
            )
        except GithubException:
            logger.exception(
                "Got GitHub Exception when trying to start trigger %s",
                self.trigger.id)
            raise SkipRequestException()

        logger.debug("GitHub trigger payload %s", payload)
        metadata = get_transformed_webhook_payload(
            payload, default_branch=default_branch, lookup_user=lookup_user)
        prepared = self.prepare_build(metadata)

        # Check if we should skip this build.
        raise_if_skipped_build(prepared, self.config)
        return prepared
Ejemplo n.º 3
0
def get_transformed_commit_info(bb_commit, ref, default_branch, repository_name, lookup_author):
    """ Returns the BitBucket commit information transformed into our own
      payload format.
  """
    try:
        validate(bb_commit, BITBUCKET_COMMIT_INFO_SCHEMA)
    except Exception as exc:
        logger.exception(
            "Exception when validating Bitbucket commit information: %s from %s",
            exc.message,
            bb_commit,
        )
        raise InvalidPayloadException(exc.message)

    commit = JSONPathDict(bb_commit)

    config = SafeDictSetter()
    config["commit"] = commit["node"]
    config["ref"] = ref
    config["default_branch"] = default_branch
    config["git_url"] = "[email protected]:%s.git" % repository_name

    config["commit_info.url"] = _BITBUCKET_COMMIT_URL % (repository_name, commit["node"])
    config["commit_info.message"] = commit["message"]
    config["commit_info.date"] = commit["timestamp"]

    match = _RAW_AUTHOR_REGEX.match(commit["raw_author"])
    if match:
        author = lookup_author(match.group(1))
        author_info = JSONPathDict(author) if author is not None else None
        if author_info:
            config["commit_info.author.username"] = author_info["user.display_name"]
            config["commit_info.author.avatar_url"] = author_info["user.avatar"]

    return config.dict_value()
Ejemplo n.º 4
0
def custom_trigger_payload(metadata, git_url):
  # First try the customhandler schema. If it matches, nothing more to do.
  custom_handler_validation_error = None
  try:
    validate(metadata, CustomBuildTrigger.payload_schema)
  except ValidationError as vex:
    custom_handler_validation_error = vex

  # Otherwise, try the defined schemas, in order, until we find a match.
  for schema, handler in SCHEMA_AND_HANDLERS:
    try:
      validate(metadata, schema)
    except ValidationError:
      continue

    result = handler(metadata)
    result['git_url'] = git_url
    return result

  # If we have reached this point and no other schemas validated, then raise the error for the
  # custom schema.
  if custom_handler_validation_error is not None:
    raise InvalidPayloadException(custom_handler_validation_error.message)

  metadata['git_url'] = git_url
  return metadata
Ejemplo n.º 5
0
def get_transformed_webhook_payload(gh_payload,
                                    default_branch=None,
                                    lookup_user=None):
    """ Returns the GitHub webhook JSON payload transformed into our own payload
      format. If the gh_payload is not valid, returns None.
  """
    try:
        validate(gh_payload, GITHUB_WEBHOOK_PAYLOAD_SCHEMA)
    except Exception as exc:
        raise InvalidPayloadException(exc.message)

    payload = JSONPathDict(gh_payload)

    if payload["head_commit"] is None:
        raise SkipRequestException

    config = SafeDictSetter()
    config["commit"] = payload["head_commit.id"]
    config["ref"] = payload["ref"]
    config["default_branch"] = payload[
        "repository.default_branch"] or default_branch
    config["git_url"] = payload["repository.ssh_url"]

    config["commit_info.url"] = payload["head_commit.url"]
    config["commit_info.message"] = payload["head_commit.message"]
    config["commit_info.date"] = payload["head_commit.timestamp"]

    config["commit_info.author.username"] = payload[
        "head_commit.author.username"]
    config["commit_info.author.url"] = payload.get(
        "head_commit.author.html_url")
    config["commit_info.author.avatar_url"] = payload.get(
        "head_commit.author.avatar_url")

    config["commit_info.committer.username"] = payload.get(
        "head_commit.committer.username")
    config["commit_info.committer.url"] = payload.get(
        "head_commit.committer.html_url")
    config["commit_info.committer.avatar_url"] = payload.get(
        "head_commit.committer.avatar_url")

    # Note: GitHub doesn't always return the extra information for users, so we do the lookup
    # manually if possible.
    if (lookup_user and not payload.get("head_commit.author.html_url")
            and payload.get("head_commit.author.username")):
        author_info = lookup_user(payload["head_commit.author.username"])
        if author_info:
            config["commit_info.author.url"] = author_info["html_url"]
            config["commit_info.author.avatar_url"] = author_info["avatar_url"]

    if (lookup_user and payload.get("head_commit.committer.username")
            and not payload.get("head_commit.committer.html_url")):
        committer_info = lookup_user(payload["head_commit.committer.username"])
        if committer_info:
            config["commit_info.committer.url"] = committer_info["html_url"]
            config["commit_info.committer.avatar_url"] = committer_info[
                "avatar_url"]

    return config.dict_value()
Ejemplo n.º 6
0
  def _metadata_from_payload(self, payload, git_url):
   # Parse the JSON payload.
    try:
      metadata = json.loads(payload)
    except ValueError as vex:
      raise InvalidPayloadException(vex.message)

    return custom_trigger_payload(metadata, git_url)
Ejemplo n.º 7
0
  def handle_trigger_request(self, request):
    payload = request.data
    if not payload:
      raise InvalidPayloadException('Missing expected payload')

    logger.debug('Payload %s', payload)

    metadata = self._metadata_from_payload(payload, self.config['build_source'])
    prepared = self.prepare_build(metadata)

    # Check if we should skip this build.
    raise_if_skipped_build(prepared, self.config)

    return prepared
Ejemplo n.º 8
0
    def handle_trigger_request(self, request):
        payload = request.get_json()
        if payload is None:
            raise InvalidPayloadException("Missing payload")

        logger.debug("Got BitBucket request: %s", payload)

        repository = self._get_repository_client()
        default_branch = self._get_default_branch(repository)

        metadata = get_transformed_webhook_payload(payload, default_branch=default_branch)
        prepared = self.prepare_build(metadata)

        # Check if we should skip this build.
        raise_if_skipped_build(prepared, self.config)
        return prepared
Ejemplo n.º 9
0
def get_transformed_webhook_payload(bb_payload, default_branch=None):
    """
    Returns the BitBucket webhook JSON payload transformed into our own payload format.

    If the bb_payload is not valid, returns None.
    """
    try:
        validate(bb_payload, BITBUCKET_WEBHOOK_PAYLOAD_SCHEMA)
    except Exception as exc:
        logger.exception(
            "Exception when validating Bitbucket webhook payload: %s from %s",
            exc.message,
            bb_payload,
        )
        raise InvalidPayloadException(exc.message)

    payload = JSONPathDict(bb_payload)
    change = payload["push.changes[-1].new"]
    if not change:
        raise SkipRequestException

    is_branch = change["type"] == "branch"
    ref = "refs/heads/" + change[
        "name"] if is_branch else "refs/tags/" + change["name"]

    repository_name = payload["repository.full_name"]
    target = change["target"]

    config = SafeDictSetter()
    config["commit"] = target["hash"]
    config["ref"] = ref
    config["default_branch"] = default_branch
    config["git_url"] = "[email protected]:%s.git" % repository_name

    config["commit_info.url"] = target["links.html.href"] or ""
    config["commit_info.message"] = target["message"]
    config["commit_info.date"] = target["date"]

    config["commit_info.author.username"] = target["author.user.display_name"]
    config["commit_info.author.avatar_url"] = target[
        "author.user.links.avatar.href"]

    config["commit_info.committer.username"] = payload["actor.display_name"]
    config["commit_info.committer.avatar_url"] = payload[
        "actor.links.avatar.href"]
    return config.dict_value()
Ejemplo n.º 10
0
def get_transformed_webhook_payload(bb_payload, default_branch=None):
    """ Returns the BitBucket webhook JSON payload transformed into our own payload
      format. If the bb_payload is not valid, returns None.
  """
    try:
        validate(bb_payload, BITBUCKET_WEBHOOK_PAYLOAD_SCHEMA)
    except Exception as exc:
        logger.exception(
            'Exception when validating Bitbucket webhook payload: %s from %s',
            exc.message, bb_payload)
        raise InvalidPayloadException(exc.message)

    payload = JSONPathDict(bb_payload)
    change = payload['push.changes[-1].new']
    if not change:
        raise SkipRequestException

    is_branch = change['type'] == 'branch'
    ref = 'refs/heads/' + change[
        'name'] if is_branch else 'refs/tags/' + change['name']

    repository_name = payload['repository.full_name']
    target = change['target']

    config = SafeDictSetter()
    config['commit'] = target['hash']
    config['ref'] = ref
    config['default_branch'] = default_branch
    config['git_url'] = '[email protected]:%s.git' % repository_name

    config['commit_info.url'] = target['links.html.href'] or ''
    config['commit_info.message'] = target['message']
    config['commit_info.date'] = target['date']

    config['commit_info.author.username'] = target['author.user.display_name']
    config['commit_info.author.avatar_url'] = target[
        'author.user.links.avatar.href']

    config['commit_info.committer.username'] = payload['actor.display_name']
    config['commit_info.committer.avatar_url'] = payload[
        'actor.links.avatar.href']
    return config.dict_value()
Ejemplo n.º 11
0
def get_transformed_webhook_payload(
    gl_payload, default_branch=None, lookup_user=None, lookup_commit=None
):
    """
    Returns the Gitlab webhook JSON payload transformed into our own payload format.

    If the gl_payload is not valid, returns None.
    """
    try:
        validate(gl_payload, GITLAB_WEBHOOK_PAYLOAD_SCHEMA)
    except Exception as exc:
        raise InvalidPayloadException(exc.message)

    payload = JSONPathDict(gl_payload)

    if payload["object_kind"] != "push" and payload["object_kind"] != "tag_push":
        # Unknown kind of webhook.
        raise SkipRequestException

    # Check for empty commits. The commits list will be empty if the branch is deleted.
    commits = payload["commits"]
    if payload["object_kind"] == "push" and not commits:
        raise SkipRequestException

    # Check for missing commit information.
    commit_sha = payload["checkout_sha"] or payload["after"]
    if commit_sha is None or commit_sha == "0000000000000000000000000000000000000000":
        raise SkipRequestException

    config = SafeDictSetter()
    config["commit"] = commit_sha
    config["ref"] = payload["ref"]
    config["default_branch"] = default_branch
    config["git_url"] = payload["repository.git_ssh_url"]

    found_commit = JSONPathDict({})
    if payload["object_kind"] == "push" or payload["object_kind"] == "tag_push":
        # Find the commit associated with the checkout_sha. Gitlab doesn't (necessary) send this in
        # any order, so we cannot simply index into the commits list.
        found_commit = None
        if commits is not None:
            for commit in commits:
                if commit["id"] == payload["checkout_sha"]:
                    found_commit = JSONPathDict(commit)
                    break

        if found_commit is None and lookup_commit:
            checkout_sha = payload["checkout_sha"] or payload["after"]
            found_commit_info = lookup_commit(payload["project_id"], checkout_sha)
            found_commit = JSONPathDict(dict(found_commit_info) if found_commit_info else {})

        if found_commit is None:
            raise SkipRequestException

    config["commit_info.url"] = found_commit["url"]
    config["commit_info.message"] = found_commit["message"]
    config["commit_info.date"] = found_commit["timestamp"]

    # Note: Gitlab does not send full user information with the payload, so we have to
    # (optionally) look it up.
    author_email = found_commit["author.email"] or found_commit["author_email"]
    if lookup_user and author_email:
        author_info = lookup_user(author_email)
        if author_info:
            config["commit_info.author.username"] = author_info["username"]
            config["commit_info.author.url"] = author_info["html_url"]
            config["commit_info.author.avatar_url"] = author_info["avatar_url"]

    return config.dict_value()