import logging import json from jsonschema import validate from buildtrigger.triggerutil import (RepositoryReadException, TriggerActivationException, TriggerStartException, ValidationRequestException, InvalidPayloadException, SkipRequestException, raise_if_skipped_build, find_matching_branches) from buildtrigger.basehandler import BuildTriggerHandler from util.security.ssh import generate_ssh_keypair logger = logging.getLogger(__name__) class CustomBuildTrigger(BuildTriggerHandler): payload_schema = { 'type': 'object', 'properties': { 'commit': { 'type': 'string', 'description': 'first 7 characters of the SHA-1 identifier for a git commit', 'pattern': '^([A-Fa-f0-9]{7,})$', }, 'ref': { 'type': 'string', 'description': 'git reference for a git commit', 'pattern': '^refs\/(heads|tags|remotes)\/(.+)$', }, 'default_branch': { 'type': 'string', 'description': 'default branch of the git repository', }, 'commit_info': { 'type': 'object', 'description': 'metadata about a git commit', 'properties': { 'url': { 'type': 'string', 'description': 'URL to view a git commit', }, 'message': { 'type': 'string', 'description': 'git commit message', }, 'date': { 'type': 'string', 'description': 'timestamp for a git commit' }, 'author': { 'type': 'object', 'description': 'metadata about the author of a git commit', 'properties': { 'username': { 'type': 'string', 'description': 'username of the author', }, 'url': { 'type': 'string', 'description': 'URL to view the profile of the author', }, 'avatar_url': { 'type': 'string', 'description': 'URL to view the avatar of the author', }, }, 'required': ['username', 'url', 'avatar_url'], }, 'committer': { 'type': 'object', 'description': 'metadata about the committer of a git commit', 'properties': { 'username': { 'type': 'string', 'description': 'username of the committer', }, 'url': { 'type': 'string', 'description': 'URL to view the profile of the committer', }, 'avatar_url': { 'type': 'string', 'description': 'URL to view the avatar of the committer', }, }, 'required': ['username', 'url', 'avatar_url'], }, }, 'required': ['url', 'message', 'date'], }, }, 'required': ['commit', 'ref', 'default_branch'], } @classmethod def service_name(cls): return 'custom-git' def is_active(self): return self.config.has_key('credentials') def _metadata_from_payload(self, payload): try: metadata = json.loads(payload) validate(metadata, self.payload_schema) except Exception as e: raise InvalidPayloadException(e.message) return metadata def handle_trigger_request(self, request): payload = request.data if not payload: raise InvalidPayloadException() logger.debug('Payload %s', payload) metadata = self._metadata_from_payload(payload) metadata['git_url'] = self.config['build_source'] prepared = self.prepare_build(metadata) # Check if we should skip this build. raise_if_skipped_build(prepared) return prepared def manual_start(self, run_parameters=None): # commit_sha is the only required parameter commit_sha = run_parameters.get('commit_sha') if commit_sha is None: raise TriggerStartException('missing required parameter') config = self.config metadata = { 'commit': commit_sha, 'git_url': config['build_source'], } return self.prepare_build(metadata, is_manual=True) def activate(self, standard_webhook_url): config = self.config public_key, private_key = generate_ssh_keypair() config['credentials'] = [ { 'name': 'SSH Public Key', 'value': public_key, }, { 'name': 'Webhook Endpoint URL', 'value': standard_webhook_url, }, ] self.config = config return config, {'private_key': private_key} def deactivate(self): config = self.config config.pop('credentials', None) self.config = config return config def get_repository_url(self): return None