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
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
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()
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
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()
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)
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
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
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()
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()
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()