Ejemplo n.º 1
0
 def merge(self):
     auth = HTTPDigestAuthFromNetrc(url=GERRIT_URL)
     rest = GerritRestAPI(url=GERRIT_URL, auth=auth, verify=GERRIT_VERIFY)
     url_path = '/changes/{}/submit'.format(self.id)
     rest.post(url_path)
Ejemplo n.º 2
0
 def merge(self):
     auth = HTTPDigestAuthFromNetrc(url=GERRIT_URL)
     rest = GerritRestAPI(url=GERRIT_URL, auth=auth, verify=GERRIT_VERIFY)
     url_path = '/changes/{}/submit'.format(self.id)
     rest.post(url_path)
Ejemplo n.º 3
0
class Gerrit(object):
    def __init__(self, url, netrc=None, use_internal=False):
        auth = AuthFromNetrc(netrc, url, use_internal)
        self.timeout = 90
        self.rest = GerritRestAPI(url=url, auth=auth)
        self.url = url
        self.change_options = [
            'CURRENT_REVISION', 'MESSAGES', 'DETAILED_LABELS',
            'DETAILED_ACCOUNTS', 'COMMIT_FOOTERS'
        ]

    def get_change(self, change_id, rev_num=None):
        options = self.change_options
        if rev_num != None:
            options += ['ALL_REVISIONS']
        uri = '/changes/{}?o={}'.format(change_id, '&o='.join(options))

        rest = self.rest.get(uri, timeout=self.timeout)
        c = GerritChange(self.url, rest)

        # The modifications to change here shouldn't be relied upon, but rolling
        # back to a previous revision is useful for testing. So we'll do our best
        # to act like the requested revision is the current_revision and hope
        # nothing downstream of us gets too confused
        if rev_num != None:
            uri = '/changes/{}/revisions/{}/commit'.format(change_id, rev_num)
            rest = self.rest.get(uri, timeout=self.timeout)
            for r in c.revisions:
                if int(r.number) != int(rev_num):
                    continue
                r.commit_message = rest['message']
                c.subject = rest['subject']
                c.current_revision = r

        uri = '/changes/{}/comments/'.format(change_id)
        rest = self.rest.get(uri, timeout=self.timeout)
        #pprint.PrettyPrinter(indent=4).pprint(rest)
        c.add_comments(rest)

        return c

    def get_ancestor_changes(self, change):
        uri = '/changes/{}/revisions/current/related'.format(change.id)
        related_changes = self.rest.get(uri, timeout=self.timeout)['changes']
        changes = []
        parents = []

        for c in related_changes:
            if c['change_id'] == change.change_id:
                parents = c['commit']['parents']
                break

        while True:
            new_parents = []
            for p in parents:
                for c in related_changes:
                    if c['commit']['commit'] == p['commit']:
                        new_parents += c['commit']['parents']
                        changes.append(self.get_change(c['_change_number']))
                        break
            if new_parents:
                parents = new_parents
            else:
                break

        return changes

    def query_changes(self,
                      status=None,
                      message=None,
                      after=None,
                      age_days=None,
                      change_id=None,
                      change_num=None,
                      project=None,
                      owner=None,
                      branches=None):
        query = []
        if message:
            query.append('message:"{}"'.format(urllib.parse.quote(message)))
        if status:
            query.append('status:{}'.format(status))
        if after:
            query.append('after:"{}"'.format(after.isoformat()))
        if age_days:
            query.append('age:{}d'.format(age_days))
        if change_id:
            query.append('change:{}'.format(change_id))
        if change_num:
            query.append('change:{}'.format(change_num))
        if project:
            query.append('project:{}'.format(project))
        if owner:
            query.append('owner:{}'.format(owner))
        if branches:
            if len(branches) == 1:
                q = 'branch:{}'.format(branches[0])
            else:
                q = '(branch:'
                q += ' OR branch:'.join(branches)
                q += ')'
            query.append(q)

        uri = '/changes/?q={}&o={}'.format('+'.join(query),
                                           '&o='.join(self.change_options))
        changes = []
        for c in self.rest.get(uri, timeout=self.timeout):
            changes.append(GerritChange(self.url, c))
        return changes

    def get_patch(self, change):
        uri = '/changes/{}/revisions/{}/patch'.format(
            change.id, change.current_revision.id)
        return self.rest.get(uri, timeout=self.timeout)

    def get_messages(self, change):
        uri = '/changes/{}/messages'.format(change.id)
        return self.rest.get(uri, timeout=self.timeout)

    def set_topic(self, change):
        # https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#set-topic
        uri = '/changes/{}/topic'.format(change.id)
        options = {'topic': change.topic}
        try:
            self.rest.put(uri, data=options, timeout=self.timeout)
            return True
        except requests.exceptions.HTTPError:
            return False

    def remove_reviewer(self, change):
        uri = '/changes/{}/reviewers/self/delete'.format(change.id)
        options = {
            'notify': 'NONE',
        }
        try:
            self.rest.post(uri, data=options, timeout=self.timeout)
            return True
        except requests.exceptions.HTTPError:
            return False

    def abandon(self, change):
        uri = '/changes/{}/abandon'.format(change.id)
        try:
            self.rest.post(uri, timeout=self.timeout)
            return True
        except requests.exceptions.HTTPError:
            return False

    def review(self,
               change,
               tag,
               message,
               notify_owner,
               vote_code_review=None,
               vote_verified=None,
               vote_cq_ready=None,
               inline_comments=None):
        review = {
            'tag': tag,
            'message': message,
            'notify': 'OWNER' if notify_owner else 'NONE',
            'omit_duplicate_comments': True,
        }

        labels = {}
        if vote_code_review != None:
            labels['Code-Review'] = vote_code_review
        if vote_verified != None:
            labels['Verified'] = vote_verified
        if vote_cq_ready != None:
            labels['Commit-Queue'] = vote_cq_ready

        if labels:
            review['labels'] = labels

        if inline_comments:
            review['comments'] = inline_comments

        #pprint.PrettyPrinter(indent=4).pprint(review)
        #pprint.PrettyPrinter(indent=4).pprint(json.dumps(review))
        uri = "changes/{}/revisions/{}/review".format(
            change.id, change.current_revision.id)
        return self.rest.post(uri,
                              data=json.dumps(review),
                              headers={"Content-Type": "application/json"},
                              timeout=self.timeout)
Ejemplo n.º 4
0
class Gerrit(object):
    def __init__(self, url, use_internal=False):
        auth = AuthFromNetrc(url, use_internal)
        self.rest = GerritRestAPI(url=url, auth=auth)
        self.url = url
        self.change_options = [
            'CURRENT_REVISION', 'MESSAGES', 'DETAILED_LABELS',
            'DETAILED_ACCOUNTS', 'COMMIT_FOOTERS'
        ]

    def get_change(self, change_id, rev_num=None):
        options = self.change_options
        if rev_num != None:
            options += ['ALL_REVISIONS']
        uri = '/changes/{}?o={}'.format(change_id, '&o='.join(options))

        rest = self.rest.get(uri)
        c = GerritChange(self.url, rest)

        # The modifications to change here shouldn't be relied upon, but rolling
        # back to a previous revision is useful for testing. So we'll do our best
        # to act like the requested revision is the current_revision and hope
        # nothing downstream of us gets too confused
        if rev_num != None:
            uri = '/changes/{}/revisions/{}/commit'.format(change_id, rev_num)
            rest = self.rest.get(uri)
            for r in c.revisions:
                if int(r.number) != int(rev_num):
                    continue
                r.commit_message = rest['message']
                c.subject = rest['subject']
                c.current_revision = r

        return c

    def get_related_changes(self, change):
        uri = '/changes/{}/revisions/current/related'.format(change.id)
        changes = []
        for c in self.rest.get(uri)['changes']:
            changes.append(self.get_change(c['change_id']))
        return changes

    def query_changes(self,
                      status=None,
                      message=None,
                      after=None,
                      age_days=None,
                      change_id=None,
                      change_num=None,
                      project=None):
        query = []
        if message:
            query.append('message:"{}"'.format(urllib.parse.quote(message)))
        if status:
            query.append('status:{}'.format(status))
        if after:
            query.append('after:"{}"'.format(after.isoformat()))
        if age_days:
            query.append('age:{}d'.format(age_days))
        if change_id:
            query.append('change:{}'.format(change_id))
        if change_num:
            query.append('change:{}'.format(change_num))
        if project:
            query.append('project:{}'.format(project))

        uri = '/changes/?q={}&o={}'.format('+'.join(query),
                                           '&o='.join(self.change_options))
        changes = []
        for c in self.rest.get(uri):
            changes.append(GerritChange(self.url, c))
        return changes

    def get_patch(self, change):
        uri = '/changes/{}/revisions/{}/patch'.format(
            change.id, change.current_revision.id)
        return self.rest.get(uri)

    def get_messages(self, change):
        uri = '/changes/{}/messages'.format(change.id)
        return self.rest.get(uri)

    def remove_reviewer(self, change):
        uri = '/changes/{}/reviewers/self/delete'.format(change.id)
        options = {
            'notify': 'NONE',
        }
        try:
            self.rest.post(uri, data=options)
            return True
        except requests.exceptions.HTTPError as e:
            return False

    def review(self,
               change,
               tag,
               message,
               notify_owner,
               vote_code_review=None,
               vote_verified=None,
               vote_cq_ready=None,
               inline_comments=None):
        review = {
            'tag': tag,
            'message': message,
            'notify': 'OWNER' if notify_owner else 'NONE',
            'omit_duplicate_comments': True,
        }

        labels = {}
        if vote_code_review != None:
            labels['Code-Review'] = vote_code_review
        if vote_verified != None:
            labels['Verified'] = vote_verified
        if vote_cq_ready != None:
            labels['Commit-Queue'] = vote_cq_ready

        if labels:
            review['labels'] = labels

        if inline_comments:
            review['comments'] = inline_comments

        #pprint.PrettyPrinter(indent=4).pprint(review)
        #pprint.PrettyPrinter(indent=4).pprint(json.dumps(review))
        return self.rest.review(change.id, change.current_revision.id,
                                json.dumps(review))
Ejemplo n.º 5
0
class Reindexer:
    """Class for reindexing Gerrit changes"""
    def __init__(self):
        self.options = _parse_options()
        self._init_logger()
        credentials = self._authenticate()
        if self.options.cert:
            certs = os.path.expanduser(self.options.cert)
            self.api = GerritRestAPI(url=self.options.url,
                                     auth=credentials,
                                     verify=certs)
        else:
            self.api = GerritRestAPI(url=self.options.url, auth=credentials)

    def _init_logger(self):
        self.logger = logging.getLogger("Reindexer")
        self.logger.setLevel(logging.DEBUG)
        h = logging.StreamHandler()
        if self.options.verbose:
            h.setLevel(logging.DEBUG)
        else:
            h.setLevel(logging.INFO)
        formatter = logging.Formatter("%(message)s")
        h.setFormatter(formatter)
        self.logger.addHandler(h)

    def _authenticate(self):
        username = password = None
        if self.options.netrc:
            auth = HTTPBasicAuthFromNetrc(url=self.options.url)
            username = auth.username
            password = auth.password
        if not username:
            username = os.environ.get("USERNAME")
        if not password:
            password = os.environ.get("PASSWORD")
        while not username:
            username = input("user: "******"password: "******"since:{self.options.time}&start={start}&skip-visibility"
            for change in self.api.get(f"changes/?q={query}"):
                more_changes = change.get("_more_changes") is not None
                start += 1
                yield change.get("_number")
            break

    def _query_to_file(self):
        self.logger.debug(
            f"writing changes since {self.options.time} to file {self.options.file}:"
        )
        with open(self.options.file, "w") as output:
            for id in self._query():
                self.logger.debug(id)
                output.write(f"{id}\n")

    def _reindex_chunk(self, chunk):
        self.logger.debug(f"indexing {chunk}")
        response = self.api.post(
            "/config/server/index.changes",
            chunk,
        )
        self.logger.debug(f"response: {response}")

    def _reindex(self):
        self.logger.debug(f"indexing changes from file {self.options.file}")
        with open(self.options.file, "r") as f:
            with tqdm(unit="changes", desc="Indexed") as pbar:
                for chunk in _chunker(f, self.options.chunksize):
                    self._reindex_chunk(chunk)
                    pbar.update(len(chunk))

    def execute(self):
        if self.options.time:
            self._query_to_file()
        else:
            self._reindex()