def process_request(self, req): if req.method != 'POST': msg = u'Method not allowed (%s)\n' % req.method req.send(msg.encode('utf-8'), 'text/plain', 405) if req.args.get('token') != self.token: msg = u'Invalid token (%s)\n' % req.args.get('token') req.send(msg.encode('utf-8'), 'text/plain', 403) path = req.args.get('path', '/') rm = RepositoryManager(self.env) reponame, repos, path = rm.get_repository_by_path(path) output = u'Running hook on %s\n' % (reponame or '(default)') if self.autofetch: git = repos.git.repo output += u'* Running git fetch\n' output += git.fetch() output += u'* Updating references\n' remote_refs = git.for_each_ref( "--format=%(refname)", "refs/remotes/origin").split() for remote_ref in remote_refs: local_ref = remote_ref.replace('remotes/origin', 'heads', 1) output += git.update_ref(local_ref, remote_ref) data = req.args.get('payload') if data: revs = [commit['id'] for commit in json.loads(data)['commits']] if revs: output += u'* Adding changesets %s\n' % u', '.join(revs) rm.notify('changeset_added', reponame, revs) req.send(output.encode('utf-8'), 'text/plain', 200 if output else 204)
class ChangesetIndexerEventsTestCase(BaseBloodhoundSearchTest): def setUp(self): super(ChangesetIndexerEventsTestCase, self).setUp() self.whoosh_backend = WhooshBackend(self.env) self.whoosh_backend.recreate_index() self.search_api = BloodhoundSearchApi(self.env) self.repository_manager = RepositoryManager(self.env) self.inject_dummy_repository() def test_can_index_added_changeset(self): rev = self.insert_changeset("Changed document 1.") results = self.search_api.query("*:*") self.assertEqual(1, results.hits) doc = results.docs[0] self.assertEqual('%s/dummy' % rev, doc["id"]) self.assertEqual('dummy', doc["repository"]) self.assertEqual('1', doc["revision"]) self.assertEqual("Changed document 1.", doc["message"]) def test_can_index_modified_changeset(self): rev = self.insert_changeset("Changed document 1.") self.modify_changeset(rev, "Added document 1.") results = self.search_api.query("*:*") self.assertEqual(1, results.hits) doc = results.docs[0] self.assertEqual('%s/dummy' % rev, doc["id"]) self.assertEqual('dummy', doc["repository"]) self.assertEqual('1', doc["revision"]) self.assertEqual("Added document 1.", doc["message"]) def insert_changeset(self, message, author=None, date=None, revision=None): rev = self.repository.add_changeset(revision, message, author, date) self.repository_manager.notify("changeset_added", 'dummy', [rev]) return rev def modify_changeset(self, rev, message=None, author=None, date=None): changeset = self.repository.get_changeset(rev) if message is not None: changeset.message = message if author is not None: changeset.author = author if date is not None: changeset.date = date self.repository_manager.notify("changeset_modified", "dummy", [rev]) def inject_dummy_repository(self): # pylint: disable=protected-access,attribute-defined-outside-init self.repository = DummyRepositry() self.repository_connector = DummyRepositoryConnector(self.env) self.repository_connector.repository = self.repository self.repository_manager._all_repositories = { 'dummy': dict(dir='dirname', type='dummy') } self.repository_manager._connectors = { 'dummy': (self.repository_connector, 100) }
class ChangesetIndexerEventsTestCase(BaseBloodhoundSearchTest): def setUp(self): super(ChangesetIndexerEventsTestCase, self).setUp() self.whoosh_backend = WhooshBackend(self.env) self.whoosh_backend.recreate_index() self.search_api = BloodhoundSearchApi(self.env) self.repository_manager = RepositoryManager(self.env) self.inject_dummy_repository() def test_can_index_added_changeset(self): rev = self.insert_changeset("Changed document 1.") results = self.search_api.query("*:*") self.assertEqual(1, results.hits) doc = results.docs[0] self.assertEqual('%s/dummy' % rev, doc["id"]) self.assertEqual('dummy', doc["repository"]) self.assertEqual('1', doc["revision"]) self.assertEqual("Changed document 1.", doc["message"]) def test_can_index_modified_changeset(self): rev = self.insert_changeset("Changed document 1.") self.modify_changeset(rev, "Added document 1.") results = self.search_api.query("*:*") self.assertEqual(1, results.hits) doc = results.docs[0] self.assertEqual('%s/dummy' % rev, doc["id"]) self.assertEqual('dummy', doc["repository"]) self.assertEqual('1', doc["revision"]) self.assertEqual("Added document 1.", doc["message"]) def insert_changeset(self, message, author=None, date=None, revision=None): rev = self.repository.add_changeset(revision, message, author, date) self.repository_manager.notify("changeset_added", 'dummy', [rev]) return rev def modify_changeset(self, rev, message=None, author=None, date=None): changeset = self.repository.get_changeset(rev) if message is not None: changeset.message = message if author is not None: changeset.author = author if date is not None: changeset.date = date self.repository_manager.notify("changeset_modified", "dummy", [rev]) def inject_dummy_repository(self): # pylint: disable=protected-access,attribute-defined-outside-init self.repository = DummyRepositry() self.repository_connector = DummyRepositoryConnector(self.env) self.repository_connector.repository = self.repository self.repository_manager._all_repositories = { 'dummy': dict(dir='dirname', type='dummy')} self.repository_manager._connectors = { 'dummy': (self.repository_connector, 100)}
def process_request(self, req): if req.method != 'POST': msg = u'Method not allowed (%s)\n' % req.method self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 405) path = req.args['path'] rm = RepositoryManager(self.env) reponame, repos, path = rm.get_repository_by_path(path) if path != '/': msg = u'No such repository (%s)\n' % path self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 400) output = u'Running hook on %s\n' % (reponame or '(default)') output += u'* Updating clone\n' repos.git.repo.remote('update', '--prune') output += u'* Synchronizing with clone\n' repos.git.sync() try: payload = json.loads(req.args['payload']) revs = [ commit['id'] for commit in payload['commits'] if commit['distinct'] ] except (ValueError, KeyError): msg = u'Invalid payload\n' self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 400) branches = self.get_branches(reponame) added, skipped, unknown = classify_commits(revs, repos, branches) if added: output += u'* Adding %s\n' % describe_commits(added) # This is where Trac gets notified of the commits in the changeset rm.notify('changeset_added', reponame, added) if skipped: output += u'* Skipping %s\n' % describe_commits(skipped) if unknown: output += u'* Unknown %s\n' % describe_commits(unknown) self.log.error(u'Payload contains unknown %s', describe_commits(unknown)) for line in output.splitlines(): self.log.debug(line) req.send(output.encode('utf-8'), 'text/plain', 200 if output else 204)
def process_request(self, req): if req.method != 'POST': msg = u'Method not allowed (%s)\n' % req.method self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 405) path = req.args['path'] rm = RepositoryManager(self.env) reponame, repos, path = rm.get_repository_by_path(path) if path != '/': msg = u'No such repository (%s)\n' % path self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 400) output = u'Running hook on %s\n' % (reponame or '(default)') output += u'* Updating clone\n' repos.git.repo.remote('update', '--prune') output += u'* Synchronizing with clone\n' repos.git.sync() try: payload = json.loads(req.args['payload']) revs = [commit['id'] for commit in payload['commits'] if commit['distinct']] except (ValueError, KeyError): msg = u'Invalid payload\n' self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 400) branches = self.get_branches(reponame) added, skipped, unknown = classify_commits(revs, repos, branches) if added: output += u'* Adding %s\n' % describe_commits(added) # This is where Trac gets notified of the commits in the changeset rm.notify('changeset_added', reponame, added) if skipped: output += u'* Skipping %s\n' % describe_commits(skipped) if unknown: output += u'* Unknown %s\n' % describe_commits(unknown) self.log.error(u'Payload contains unknown %s', describe_commits(unknown)) for line in output.splitlines(): self.log.debug(line) req.send(output.encode('utf-8'), 'text/plain', 200 if output else 204)
def process_request(self, req): if req.method != "POST": msg = u"Method not allowed (%s)\n" % req.method self.log.warning(msg.rstrip("\n")) req.send(msg.encode("utf-8"), "text/plain", 405) path = req.args["path"] rm = RepositoryManager(self.env) reponame, repos, path = rm.get_repository_by_path(path) if path != "/": msg = u"No such repository (%s)\n" % path self.log.warning(msg.rstrip("\n")) req.send(msg.encode("utf-8"), "text/plain", 400) output = u"Running hook on %s\n" % (reponame or "(default)") output += u"* Updating clone\n" output += repos.git.repo.remote("update", "--prune") try: payload = json.loads(req.args["payload"]) revs = [commit["id"] for commit in payload["commits"] if commit["distinct"]] except (ValueError, KeyError): msg = u"Invalid payload\n" self.log.warning(msg.rstrip("\n")) req.send(msg.encode("utf-8"), "text/plain", 400) branches = self.get_branches(reponame) added_revs, skipped_revs = [], [] for rev in revs: if rev_in_branches(repos.get_changeset(rev), branches): added_revs.append(rev) else: skipped_revs.append(rev) if added_revs: output += u"* Adding %s\n" % describe_commits(added_revs) # This is where Trac gets notified of the commits in the changeset rm.notify("changeset_added", reponame, added_revs) if skipped_revs: output += u"* Skipping %s\n" % describe_commits(skipped_revs) for line in output.splitlines(): self.log.debug(line) req.send(output.encode("utf-8"), "text/plain", 200 if output else 204)
def process_request(self, req): path = req.args['path'] rm = RepositoryManager(self.env) reponame, repos, path = rm.get_repository_by_path(path) if repos is None or path != '/': msg = u'No such repository (%s)\n' % path self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 400) if req.method != 'POST': msg = u'Endpoint is ready to accept GitHub notifications.\n' self.log.warning(u'Method not allowed (%s)' % req.method) req.send(msg.encode('utf-8'), 'text/plain', 405) event = req.get_header('X-GitHub-Event') if event == 'ping': payload = json.loads(req.read()) req.send(payload['zen'].encode('utf-8'), 'text/plain', 200) elif event != 'push': msg = u'Only ping and push are supported\n' self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 400) output = u'Running hook on %s\n' % (reponame or '(default)') output += u'* Updating clone\n' try: git = repos.git.repo # GitRepository except AttributeError: git = repos.repos.git.repo # GitCachedRepository git.remote('update', '--prune') # Ensure that repos.get_changeset can find the new changesets. output += u'* Synchronizing with clone\n' repos.sync() try: payload = json.loads(req.read()) revs = [commit['id'] for commit in payload['commits'] if commit['distinct']] except (ValueError, KeyError): msg = u'Invalid payload\n' self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 400) branches = self.get_branches(reponame) added, skipped, unknown = classify_commits(revs, repos, branches) if added: output += u'* Adding %s\n' % describe_commits(added) # This is where Trac gets notified of the commits in the changeset rm.notify('changeset_added', reponame, added) if skipped: output += u'* Skipping %s\n' % describe_commits(skipped) if unknown: output += u'* Unknown %s\n' % describe_commits(unknown) self.log.error(u'Payload contains unknown %s', describe_commits(unknown)) for line in output.splitlines(): self.log.debug(line) req.send(output.encode('utf-8'), 'text/plain', 200 if output else 204)
def process_request(self, req): path = req.args['path'] rm = RepositoryManager(self.env) reponame, repos, path = rm.get_repository_by_path(path) if repos is None or path != '/': msg = u'No such repository (%s)\n' % path self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 400) if req.method != 'POST': msg = u'Endpoint is ready to accept GitHub notifications.\n' self.log.warning(u'Method not allowed (%s)' % req.method) req.send(msg.encode('utf-8'), 'text/plain', 405) event = req.get_header('X-GitHub-Event') if event == 'ping': payload = json.loads(req.read()) req.send(payload['zen'].encode('utf-8'), 'text/plain', 200) elif event != 'push': msg = u'Only ping and push are supported\n' self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 400) output = u'Running hook on %s\n' % (reponame or '(default)') output += u'* Updating clone\n' try: git = repos.git.repo # GitRepository except AttributeError: git = repos.repos.git.repo # GitCachedRepository git.remote('update', '--prune') # Ensure that repos.get_changeset can find the new changesets. output += u'* Synchronizing with clone\n' repos.sync() try: payload = json.loads(req.read()) revs = [ commit['id'] for commit in payload['commits'] if commit['distinct'] ] except (ValueError, KeyError): msg = u'Invalid payload\n' self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 400) branches = self.get_branches(reponame) added, skipped, unknown = classify_commits(revs, repos, branches) if added: output += u'* Adding %s\n' % describe_commits(added) # This is where Trac gets notified of the commits in the changeset rm.notify('changeset_added', reponame, added) if skipped: output += u'* Skipping %s\n' % describe_commits(skipped) if unknown: output += u'* Unknown %s\n' % describe_commits(unknown) self.log.error(u'Payload contains unknown %s', describe_commits(unknown)) for line in output.splitlines(): self.log.debug(line) req.send(output.encode('utf-8'), 'text/plain', 200 if output else 204)
def process_request(self, req): if req.method != 'POST': msg = u'Method not allowed (%s)\n' % req.method self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 405) path = req.args['path'] rm = RepositoryManager(self.env) reponame, repos, path = rm.get_repository_by_path(path) key = 'branches' if is_default(reponame) else '%s.branches' % reponame branches = self.config.getlist('github', key, sep=' ') if path != '/': msg = u'No such repository (%s)\n' % path self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 400) output = u'Running hook on %s\n' % (reponame or '(default)') output += u'* Updating clone\n' output += repos.git.repo.remote('update', '--prune') try: payload = json.loads(req.args['payload']) revs = [commit['id'] for commit in payload['commits']] except (ValueError, KeyError): msg = u'Invalid payload\n' self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 400) if branches: added_revs, skipped_revs = [], [] for rev in revs: if allow_revision(rev, repos, branches): added_revs.append(rev) else: skipped_revs.append(rev) else: added_revs, skipped_revs = revs, [] if added_revs: if len(added_revs) == 1: output += u'* Adding commit %s\n' % added_revs[0] else: output += u'* Adding commits %s\n' % u', '.join(added_revs) # This is where Trac gets notified of the commits in the changeset rm.notify('changeset_added', reponame, added_revs) if skipped_revs: if len(skipped_revs) == 1: output += u'* Skipping commit %s\n' % skipped_revs[0] else: output += u'* Skipping commits %s\n' % u', '.join(skipped_revs) for line in output.splitlines(): self.log.debug(line) req.send(output.encode('utf-8'), 'text/plain', 200 if output else 204)
def process_request(self, req): path = req.args['path'] rm = RepositoryManager(self.env) reponame, repos, path = rm.get_repository_by_path(path) if repos is None or path != '/': msg = u'No such repository (%s)\n' % path self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 400) if req.method != 'POST': msg = u'Endpoint is ready to accept GitHub notifications.\n' self.log.warning(u'Method not allowed (%s)', req.method) req.send(msg.encode('utf-8'), 'text/plain', 405) # Verify the event's signature reqdata = req.read() signature = req.get_header('X-Hub-Signature') if not self._verify_webhook_signature(signature, reqdata): msg = u'Webhook signature verification failed\n' self.log.warning(msg.rstrip('\n')) # pylint: disable=no-member req.send(msg.encode('utf-8'), 'text/plain', 403) event = req.get_header('X-GitHub-Event') if event == 'ping': payload = json.loads(reqdata) req.send(payload['zen'].encode('utf-8'), 'text/plain', 200) elif event != 'push': msg = u'Only ping and push are supported\n' self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 400) output = u'Running hook on %s\n' % (reponame or '(default)') output += u'* Updating clone\n' try: git = repos.git.repo # GitRepository except AttributeError: git = repos.repos.git.repo # GitCachedRepository git.remote('update', '--prune') # Ensure that repos.get_changeset can find the new changesets. output += u'* Synchronizing with clone\n' repos.sync() try: payload = json.loads(reqdata) revs = [commit['id'] for commit in payload['commits'] if commit['distinct']] except (ValueError, KeyError): msg = u'Invalid payload\n' self.log.warning(msg.rstrip('\n')) req.send(msg.encode('utf-8'), 'text/plain', 400) branches = self.get_branches(reponame) added, skipped, unknown = classify_commits(revs, repos, branches) if added: output += u'* Adding %s\n' % describe_commits(added) # This is where Trac gets notified of the commits in the changeset rm.notify('changeset_added', reponame, added) if skipped: output += u'* Skipping %s\n' % describe_commits(skipped) if unknown: output += u'* Unknown %s\n' % describe_commits(unknown) self.log.error(u'Payload contains unknown %s', describe_commits(unknown)) status = 200 git_dir = git.rev_parse('--git-dir').rstrip('\n') hook = os.path.join(git_dir, 'hooks', 'trac-github-update') if os.path.isfile(hook): output += u'* Running trac-github-update hook\n' try: p = Popen(hook, cwd=git_dir, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=trac.util.compat.close_fds) except Exception as e: output += u'Error: hook execution failed with exception\n%s' % (traceback.format_exc(),) status = 500 else: hookoutput = p.communicate(input=reqdata)[0] output += hookoutput.decode('utf-8') if p.returncode != 0: output += u'Error: hook failed with exit code %d\n' % (p.returncode,) status = 500 for line in output.splitlines(): self.log.debug(line) if status == 200 and not output: status = 204 req.send(output.encode('utf-8'), 'text/plain', status)