def _main():
    myauth = HTTPDigestAuth('account', 'password')
    rest = GerritRestAPI(url='http://code...', auth=myauth)

    try:
        """
        conditions
        """
        query = ["status:open"]
        query += ["owner:leon5209"]
        query += ["age:1week"]
        changes = rest.get("/changes/?q=%s" % "%20".join(query))
        logging.debug("there are %d changes", len(changes))
        """
        abandon
        """
        for change in changes:
            logging.debug("subject : %s ", change['subject'])
            logging.debug("change id : %s ", change['change_id'])

            # we don't kill draft
            if change['status'] == "DRAFT":
                logging.debug("skip, we dont abandon draft")
            else:
                logging.debug("commit out of date , abandon!")
                rest.post("/changes/" + change['change_id'] + "/abandon",
                          json={
                              "message":
                              "This Commit is out of date, auto abandon! "
                          })

    except RequestException as err:
        logging.error("Error: %s", str(err))
Example #2
0
def get_change(url, repo, branch, change_id):
    """
    Fetches a change from upstream repo
    :param url: URL of upstream gerrit
    :param repo: name of repo
    :param branch: branch of repo
    :param change_id: SHA change id
    :return: change if found and not abandoned, closed
    """
    rest = GerritRestAPI(url=url)
    change_path = "{}~{}~{}".format(quote_plus(repo), quote_plus(branch),
                                    change_id)
    change_str = "changes/{}?o=CURRENT_REVISION".format(change_path)
    change = rest.get(change_str)
    try:
        assert change['status'] not in 'ABANDONED' 'CLOSED', \
            'Change {} is in {} state'.format(change_id, change['status'])
        logging.debug('Change found: {}'.format(change))
        return change

    except KeyError:
        logging.error('Failed to get valid change data structure from url '
                      '{}/{}, data returned: \n{}'.format(
                          change_id, change_str, change))
        raise
Example #3
0
class Connection_Setup:

    def __init__(self,url,username,password):
        self.url=url
        self.gQ=Gerrit_Queries()

        if username=='' and password=='':
            self.auth=None
        else:
            self.username=username
            self.password=password

            self.auth = HTTPDigestAuth(self.username, self.password)


    def setConnection(self):

        try:
            self.rest = GerritRestAPI(url=self.url,auth=self.auth)  #############################################
            dummy = self.rest.get(self.gQ.testingQuery())

        except:
            try:
                if self.auth is not None:
                    self.auth = HTTPBasicAuth(self.username, self.password)
                self.rest = GerritRestAPI(url=self.url, auth=self.auth)
                dummy = self.rest.get(self.gQ.testingQuery())
            except:
                sys.exit('Authentication Failed!')

        return self.rest
Example #4
0
def get_patch(change_id, repo, branch, url=con.OPENSTACK_GERRIT):
    logging.info("Fetching patch for change id {}".format(change_id))
    change = get_change(url, repo, branch, change_id)
    if change:
        current_revision = change['current_revision']
        rest = GerritRestAPI(url=url)
        change_path = "{}~{}~{}".format(quote_plus(repo), quote_plus(branch),
                                        change_id)
        patch_url = "changes/{}/revisions/{}/patch".format(
            change_path, current_revision)
        return strip_patch_sections(rest.get(patch_url))
 def __init__(self):
     self.user = '******'
     self.password = os.getenv('GERRIT_PASSWORD')
     auth = HTTPDigestAuth(self.user, self.password)
     #gerrit site
     ip = "gerrit.zte.com.cn"
     self.url = 'http://{}'.format(ip)
     self.ssh_url = 'ssh://{}@{}:29418'.format(self.user, ip)
     self.rest = GerritRestAPI(url=self.url, auth=auth)
     self.project_info = 'projects_info.txt'
     self.project_config_template = "project_config.template"
     self.group_types = ('admin', 'core', 'team')
Example #6
0
def clone_fork(args):
    ref = None
    logging.info("Cloning {}".format(args.repo))

    try:
        cm = git.Repo(search_parent_directories=True).commit().message
    except git.exc.InvalidGitRepositoryError:
        logging.debug('Current Apex directory is not a git repo: {}'.format(
            os.getcwd()))
        cm = ''

    logging.info("Current commit message: {}".format(cm))
    m = re.search('{}:\s*(\S+)'.format(args.repo), cm)

    if m:
        change_id = m.group(1)
        logging.info("Using change ID {} from {}".format(change_id, args.repo))
        rest = GerritRestAPI(url=args.url)
        change_str = "changes/{}?o=CURRENT_REVISION".format(change_id)
        change = rest.get(change_str)
        try:
            assert change['status'] not in 'ABANDONED' 'CLOSED',\
                'Change {} is in {} state'.format(change_id, change['status'])
            if change['status'] == 'MERGED':
                logging.info(
                    'Change {} is merged, ignoring...'.format(change_id))
            else:
                current_revision = change['current_revision']
                ref = change['revisions'][current_revision]['ref']
                logging.info('setting ref to {}'.format(ref))
        except KeyError:
            logging.error('Failed to get valid change data structure from url '
                          '{}/{}, data returned: \n{}'.format(
                              change_id, change_str, change))
            raise

    # remove existing file or directory named repo
    if os.path.exists(args.repo):
        if os.path.isdir(args.repo):
            shutil.rmtree(args.repo)
        else:
            os.remove(args.repo)

    ws = git.Repo.clone_from("{}/{}".format(args.url, args.repo),
                             args.repo,
                             b=args.branch)
    if ref:
        git_cmd = ws.git
        git_cmd.fetch("{}/{}".format(args.url, args.repo), ref)
        git_cmd.checkout('FETCH_HEAD')
        logging.info('Checked out commit:\n{}'.format(ws.head.commit.message))
Example #7
0
    def setConnection(self):

        try:
            self.rest = GerritRestAPI(url=self.url,auth=self.auth)  #############################################
            dummy = self.rest.get(self.gQ.testingQuery())

        except:
            try:
                if self.auth is not None:
                    self.auth = HTTPBasicAuth(self.username, self.password)
                self.rest = GerritRestAPI(url=self.url, auth=self.auth)
                dummy = self.rest.get(self.gQ.testingQuery())
            except:
                sys.exit('Authentication Failed!')

        return self.rest
Example #8
0
def main():
    """Given a yamlfile that follows the release syntax, create branches
    in Gerrit listed under branches"""

    config = ConfigParser.ConfigParser()
    config.read(
        os.path.join(os.path.abspath(os.path.dirname(__file__)),
                     'defaults.cfg'))
    config.read([os.path.expanduser('~/releases.cfg'), 'releases.cfg'])

    gerrit_url = config.get('gerrit', 'url')

    parser = argparse.ArgumentParser()
    parser.add_argument('--file',
                        '-f',
                        type=argparse.FileType('r'),
                        required=True)
    parser.add_argument('--basicauth', '-b', action='store_true')
    args = parser.parse_args()

    GerritAuth = HTTPDigestAuthFromNetrc
    if args.basicauth:
        GerritAuth = HTTPBasicAuthFromNetrc

    try:
        auth = GerritAuth(url=gerrit_url)
    except ValueError as err:
        logging.error("%s for %s", err, gerrit_url)
        quit(1)
    restapi = GerritRestAPI(url=gerrit_url, auth=auth)

    project = yaml.safe_load(args.file)

    create_branches(restapi, project)
Example #9
0
def _get_client():
    """Get the client for making requests."""
    try:
        auth = HTTPBasicAuth(CONFIG['username'], CONFIG['password'])
    except KeyError:
        # Username and password weren't provided, try falling back to .netrc
        auth = HTTPBasicAuthFromNetrc(CONFIG['base_url'])
    return GerritRestAPI(url=CONFIG['base_url'], auth=auth)
Example #10
0
    def __init__(self, gerrit_host="gerrit.mmt.com"):
        self.client = None
        self.ELK_HOST = "127.0.0.1:9200" # elastic search
        self.index_name = datetime.datetime.now().strftime('gerrit-stats-%Y-%m')

        url = "http://127.0.0.1:8080" # gerrit servers
        auth = HTTPDigestAuth('admin', 'pass')
        self.rest_client = GerritRestAPI(url=url, auth=auth)

        # establish connection with jira
        self.jira = JIRA(basic_auth=('jira', 'pass'), options = {'server': '127.0.0.1'}) # Jira server
        self.regex = r'([A-Z]+-[0-9]+)'

        log.info("creating a new connection with %s" % (gerrit_host))
        self.client = GerritClient(gerrit_host)
        log.info("Gerrit version is %s" % (self.client.gerrit_version()))
        self.start_event_stream()
Example #11
0
    def __init__(self):
        self.nlsr_exp_file = os.path.abspath("exp_file")
        self.work_dir = os.path.abspath("work-dir")
        self.exp_names = []

        self.ndncxx_src = SourceManager("{}/ndn-cxx".format(self.work_dir))
        self.nfd_src = SourceManager("{}/NFD".format(self.work_dir))
        self.chronosync_src = SourceManager("{}/Chronosync".format(
            self.work_dir))
        self.psync_src = SourceManager("{}/PSync".format(self.work_dir))
        self.nlsr_src = SourceManager("{}/NLSR".format(self.work_dir))
        self.minindn_src = SourceManager("{}/mini-ndn".format(self.work_dir))

        self.url = "https://gerrit.named-data.net"
        self.auth = HTTPBasicAuthFromNetrc(self.url)
        self.rest = GerritRestAPI(url=self.url, auth=self.auth)
        self.rev = GerritReview()
        self.message = ""
        self.score = 0
        self.labels = {}
        self.clear_tmp()
Example #12
0
 def __iter__(self):
     # @todo #18 Возможно мы можем написать декоратор для Auth
     #  Потому что у меня возникло желание вынести это в функцию,
     #  что не правильно.
     if self.config.value('gerrit.auth') == 'digest':
         auth = HTTPDigestAuth(self.config.value('gerrit.user'),
                               self.config.value('gerrit.password'))
     else:
         auth = None
     return (GerritReview(i) for i in GerritRestAPI(
         url=self.config.value('gerrit.url'), auth=auth).get(
             '/changes/?o=LABELS&o=CURRENT_REVISION'))
Example #13
0
def gerrit_api(request):
    """Create a Gerrit container for the given version and return an API."""
    with GerritContainer(request.param) as gerrit:
        port = gerrit.get_exposed_port(8080)
        url = "http://localhost:%s" % port
        if request.param == "2.13.11":
            auth = HTTPDigestAuth("admin", "secret")
        else:
            auth = HTTPBasicAuth("admin", "secret")
        api = GerritRestAPI(url=url, auth=auth)
        _connect(api)
        yield api
    def query(self, project_name, limit=10):
        if limit is None:
            limitRange = ""
        else:
            limitRange = "&n=" + str(limit)

        self.project_name = project_name
        self.limit = limit

        self.rest = GerritRestAPI(url=self.url)
        self.changes = self.rest.get("/changes/?q=project:" +
                                     self.project_name + limitRange)
        #self.changes = self.rest.get("/changes/?q=status:merged" + "&n=" + str(self.limit))

        #print(self.changes)
        #self.ownerDupList=[]
        index = 1
        for change in self.changes:
            print("Change Collecting Index in ReviewExtractor.query() %s" %
                  index)
            index += 1
            reviewDict = self.getReviewDict(change)
            if reviewDict is not None:
                self.changeList.append(reviewDict)
Example #15
0
def _main():
    descr = 'Send request using Gerrit HTTP API'
    parser = argparse.ArgumentParser(
        description=descr,
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('-g',
                        '--gerrit-url',
                        dest='gerrit_url',
                        required=True,
                        help='gerrit server url')
    parser.add_argument('-b',
                        '--basic-auth',
                        dest='basic_auth',
                        action='store_true',
                        help='use basic auth instead of digest')
    if _kerberos_support:
        parser.add_argument('-k',
                            '--kerberos-auth',
                            dest='kerberos_auth',
                            action='store_true',
                            help='use kerberos auth')
    parser.add_argument('-u', '--username', dest='username', help='username')
    parser.add_argument('-p', '--password', dest='password', help='password')
    parser.add_argument('-n',
                        '--netrc',
                        dest='netrc',
                        action='store_true',
                        help='Use credentials from netrc')
    parser.add_argument('-v',
                        '--verbose',
                        dest='verbose',
                        action='store_true',
                        help='enable verbose (debug) logging')

    options = parser.parse_args()

    level = logging.DEBUG if options.verbose else logging.INFO
    logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
                        level=level)

    if _kerberos_support and options.kerberos_auth:
        if options.username or options.password \
                or options.basic_auth or options.netrc:
            parser.error("--kerberos-auth may not be used together with "
                         "--username, --password, --basic-auth or --netrc")
        auth = HTTPKerberosAuth(mutual_authentication=OPTIONAL)
    elif options.username and options.password:
        if options.netrc:
            logging.warning("--netrc option ignored")
        if options.basic_auth:
            auth = HTTPBasicAuth(options.username, options.password)
        else:
            auth = HTTPDigestAuth(options.username, options.password)
    elif options.netrc:
        if options.basic_auth:
            auth = HTTPBasicAuthFromNetrc(url=options.gerrit_url)
        else:
            auth = HTTPDigestAuthFromNetrc(url=options.gerrit_url)
    else:
        auth = None

    rest = GerritRestAPI(url=options.gerrit_url, auth=auth)

    try:
        query = ["status:open"]
        if auth:
            query += ["owner:self"]
        else:
            query += ["limit:10"]
        changes = rest.get("/changes/?q=%s" % "%20".join(query))
        logging.info("%d changes", len(changes))
        for change in changes:
            logging.info(change['change_id'])
    except RequestException as err:
        logging.error("Error: %s", str(err))
Example #16
0
def _main():
    parser = optparse.OptionParser()
    parser.add_option('-g', '--gerrit-url', dest='gerrit_url',
                      metavar='URL',
                      default=None,
                      help='gerrit server URL')
    parser.add_option('-b', '--basic-auth', dest='basic_auth',
                      action='store_true',
                      help='use HTTP basic authentication instead of digest')
    parser.add_option('-n', '--dry-run', dest='dry_run',
                      action='store_true',
                      help='enable dry-run mode: show stale changes but do '
                           'not abandon them')
    parser.add_option('-a', '--age', dest='age',
                      metavar='AGE',
                      default="6months",
                      help='age of change since last update '
                           '(default: %default)')
    parser.add_option('-m', '--message', dest='message',
                      metavar='STRING', default=None,
                      help='Custom message to append to abandon message')
    parser.add_option('--branch', dest='branches', metavar='BRANCH_NAME',
                      default=[], action='append',
                      help='Abandon changes only on the given branch')
    parser.add_option('--exclude-branch', dest='exclude_branches',
                      metavar='BRANCH_NAME',
                      default=[],
                      action='append',
                      help='Do not abandon changes on given branch')
    parser.add_option('--project', dest='projects', metavar='PROJECT_NAME',
                      default=[], action='append',
                      help='Abandon changes only on the given project')
    parser.add_option('--exclude-project', dest='exclude_projects',
                      metavar='PROJECT_NAME',
                      default=[],
                      action='append',
                      help='Do not abandon changes on given project')
    parser.add_option('--owner', dest='owner',
                      metavar='USERNAME',
                      default=None,
                      action='store',
                      help='Only abandon changes owned by the given user')
    parser.add_option('-v', '--verbose', dest='verbose',
                      action='store_true',
                      help='enable verbose (debug) logging')

    (options, _args) = parser.parse_args()

    level = logging.DEBUG if options.verbose else logging.INFO
    logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
                        level=level)

    if not options.gerrit_url:
        logging.error("Gerrit URL is required")
        return 1

    pattern = re.compile(r"^([\d]+)(month[s]?|year[s]?|week[s]?)")
    match = pattern.match(options.age)
    if not match:
        logging.error("Invalid age: %s", options.age)
        return 1
    message = "Abandoning after %s %s or more of inactivity." % \
        (match.group(1), match.group(2))

    if options.basic_auth:
        auth_type = HTTPBasicAuthFromNetrc
    else:
        auth_type = HTTPDigestAuthFromNetrc

    try:
        auth = auth_type(url=options.gerrit_url)
        gerrit = GerritRestAPI(url=options.gerrit_url, auth=auth)
    except Exception as e:
        logging.error(e)
        return 1

    logging.info(message)
    try:
        stale_changes = []
        offset = 0
        step = 500
        query_terms = ["status:new", "age:%s" % options.age]
        if options.branches:
            query_terms += ["branch:%s" % b for b in options.branches]
        elif options.exclude_branches:
            query_terms += ["-branch:%s" % b for b in options.exclude_branches]
        if options.projects:
            query_terms += ["project:%s" % p for p in options.projects]
        elif options.exclude_projects:
            query_terms = ["-project:%s" % p for p in options.exclude_projects]
        if options.owner:
            query_terms += ["owner:%s" % options.owner]
        query = "%20".join(query_terms)
        while True:
            q = query + "&n=%d&S=%d" % (step, offset)
            logging.debug("Query: %s", q)
            url = "/changes/?q=" + q
            result = gerrit.get(url)
            logging.debug("%d changes", len(result))
            if not result:
                break
            stale_changes += result
            last = result[-1]
            if "_more_changes" in last:
                logging.debug("More...")
                offset += step
            else:
                break
    except Exception as e:
        logging.error(e)
        return 1

    abandoned = 0
    errors = 0
    abandon_message = message
    if options.message:
        abandon_message += "\n\n" + options.message
    for change in stale_changes:
        number = change["_number"]
        try:
            owner = change["owner"]["name"]
        except:
            owner = "Unknown"
        subject = change["subject"]
        if len(subject) > 70:
            subject = subject[:65] + " [...]"
        change_id = change["id"]
        logging.info("%s (%s): %s", number, owner, subject)
        if options.dry_run:
            continue

        try:
            gerrit.post("/changes/" + change_id + "/abandon",
                        data='{"message" : "%s"}' % abandon_message)
            abandoned += 1
        except Exception as e:
            errors += 1
            logging.error(e)
    logging.info("Total %d stale open changes", len(stale_changes))
    if not options.dry_run:
        logging.info("Abandoned %d changes. %d errors.", abandoned, errors)
Example #17
0
class DGerritHandler():

    def __init__(self, gerrit_host="gerrit.mmt.com"):
        self.client = None
        self.ELK_HOST = "127.0.0.1:9200" # elastic search
        self.index_name = datetime.datetime.now().strftime('gerrit-stats-%Y-%m')

        url = "http://127.0.0.1:8080" # gerrit servers
        auth = HTTPDigestAuth('admin', 'pass')
        self.rest_client = GerritRestAPI(url=url, auth=auth)

        # establish connection with jira
        self.jira = JIRA(basic_auth=('jira', 'pass'), options = {'server': '127.0.0.1'}) # Jira server
        self.regex = r'([A-Z]+-[0-9]+)'

        log.info("creating a new connection with %s" % (gerrit_host))
        self.client = GerritClient(gerrit_host)
        log.info("Gerrit version is %s" % (self.client.gerrit_version()))
        self.start_event_stream()

    def start_event_stream(self):
        # start listening to event stream
        log.info("initiating listening to event stream")
        self.client.start_event_stream()

    def event_listen(self):

        iter = 0
        while True:
            try:
                elog = {}
                event = self.client.get_event()
                log.info("==============START=====================================")
                log.info("got a new event %s -- %s" % (event.name, type(event.json)))
                log.info("actual event is %s" % pformat(event.json))
                elog['type'] = event.name
		if event.name == "error-event":
			log.info("got an error-event, exiting the script.............")
			sys.exit()

                elog['gerrit_id'] = event.change.number
                log.info(dir(event))
                if hasattr(event, 'author'):
                    elog['author_username'] = event.author.username if hasattr(event, 'author') else None 
                    elog['author_email'] = event.author.email if hasattr(event, 'author') else None
                elif hasattr(event, 'patchset'):
                    elog['author_username'] = event.patchset.author.username if hasattr(event.patchset, 'author') else None
                    elog['author_email'] = event.patchset.author.email if hasattr(event.patchset, 'author') else None

                elog['project'] = event.change.project
                elog['owner'] = event.change.owner.username
                elog['branch'] = event.change.branch
                elog['patchset_number'] = event.patchset.number
                elog['patchset_size_deletions'] = event.json.get('patchSet').get('sizeDeletions')
                elog['patchset_size_insertions'] = event.json.get('patchSet').get('sizeInsertions')
                elog['subject'] = event.change.subject

                if event.name == 'reviewer-added':
                    elog['reviewers'] = event.reviewer.username

                elif event.name == 'change-merged':
                    elog['submitter'] = event.submitter.username

                elif event.name == 'comment-added' and 'approvals' in event.json.keys():
                    for i in event.json.get('approvals'):
                        log.info(i)
                        if 'oldValue' in i:
                            log.info("----found old value----")
                            elog['approval_approver'] = event.author.username
                            elog['approver_type'] = i.get('type')
                            elog['approval_value'] = i.get('value')
                            elog['approval_description'] = i.get('description')
                            break
                        else:
                            elog['approval_approver'] = event.author.username
                            elog['approver_type'] = 'comment-added'
                            elog['approval_value'] = '0'
                            elog['approval_description'] = 'comment-added'

                log.info("~~~~~~~~~~~~~~~~~~~ Start JIRA Analysis ~~~~~~~~~~~~~~~~~~~")
                issue_type = []
                elog['issue_id'] = re.findall(self.regex, elog['subject'])
                for issue in elog['issue_id']:
                    issue_type.append(self.jira.issue(issue).fields.issuetype.name)

                elog['issue_id_type'] = issue_type
                log.info("~~~~~~~~~~~~~~~~~~~ End JIRA Analysis ~~~~~~~~~~~~~~~~~~~")

                log.info("~~~~~~~~~~~~~~~~~~~ Start Gerrit File Actions ~~~~~~~~~~~~~~~~~~~")
                files_info = {
                    "ADDED": {
                      "lines_added": 0,
                      "lines_removed": 0,
                      "count": 0
                    },
                    "MODIFIED": {
                      "lines_added": 0,
                      "lines_removed": 0,
                      "count": 0
                    },
                    "DELETED": {
                      "lines_added": 0,
                      "lines_removed": 0,
                      "count": 0
                    },
                    "RENAMED": {
                      "lines_added": 0,
                      "lines_removed": 0,
                      "count": 0
                    },
                    "COPIED": {
                      "lines_added": 0,
                      "lines_removed": 0,
                      "count": 0
                    },
                    "REWRITE": {
                      "lines_added": 0,
                      "lines_removed": 0,
                      "count": 0
                    }
                }
                query_result = self.client.run_command("query --current-patch-set --format JSON --files change:{}".format(elog['gerrit_id']))
                output = query_result.stdout.read()
                output = output.split('\n')
                files = json.loads(output[0])
                log.info(elog['project'])
                for file in files['currentPatchSet']['files']:
                    if file['file'] not in ['/COMMIT_MSG', '/MERGE_LIST']:
                        files_info[file['type']]['lines_added'] += file['insertions']
                        files_info[file['type']]['lines_removed'] += file['deletions']
                        files_info[file['type']]['count'] += 1

                elog['files'] = files_info
                log.info("~~~~~~~~~~~~~~~~~~~ End Gerrit File Actions ~~~~~~~~~~~~~~~~~~~")

                log.info("elk message %d is %s" % (iter, json.dumps(elog, indent=2)))
                log.info("==============END=====================================")

                self.log_to_elk(elog)
            except Exception as e:
                log.exception(e)
                if event:
                    log.info(str(event.json))
            finally:
                iter += 1

    def stop_event_stream(self):
        # stop listening to gerrit event stream
        log.info("stop listening to event stream")
        self.client.stop_event_stream()

    def log_to_elk(self, log):
        log['timestamp'] = datetime.datetime.now()
        elk = Elasticsearch(self.ELK_HOST)
        elk.index(index=self.index_name, doc_type='gerrit_info', body=log)

    def get_reviewer_list(self, change_id):

        endpoint = "/changes/%s/reviewers/" % change_id
        data = self.rest_client.get(endpoint)
        reviewers = []
        for i in data:
            if i.get('username') is not None:
                reviewers.append(i.get('username'))

        return reviewers
Example #18
0
 def conn(self):
     auth = HTTPDigestAuth(self.user, self.passwd)
     rest = GerritRestAPI(url=self.url, auth=auth)
     return rest
Example #19
0
class TestNLSR(object):
    """ Test NLSR class """

    # pylint: disable=too-many-instance-attributes
    def __init__(self):
        self.nlsr_exp_file = os.path.abspath("exp_file")
        self.work_dir = os.path.abspath("work-dir")
        self.exp_names = []

        self.ndncxx_src = SourceManager("{}/ndn-cxx".format(self.work_dir))
        self.nfd_src = SourceManager("{}/NFD".format(self.work_dir))
        self.chronosync_src = SourceManager("{}/Chronosync".format(
            self.work_dir))
        self.psync_src = SourceManager("{}/PSync".format(self.work_dir))
        self.nlsr_src = SourceManager("{}/NLSR".format(self.work_dir))
        self.minindn_src = SourceManager("{}/mini-ndn".format(self.work_dir))

        self.url = "https://gerrit.named-data.net"
        self.auth = HTTPBasicAuthFromNetrc(self.url)
        self.rest = GerritRestAPI(url=self.url, auth=self.auth)
        self.rev = GerritReview()
        self.message = ""
        self.score = 0
        self.labels = {}
        self.clear_tmp()

    def clear_tmp(self):
        os.chdir("/tmp/minindn")
        dir = [
            d for d in os.listdir('/tmp/minindn')
            if os.path.isdir(os.path.join('/tmp/minindn', d))
        ]
        for f in dir:
            if not f.startswith('.'):
                shutil.rmtree(f)

    def run_tests(self):
        self.exp_names = []
        with open(self.nlsr_exp_file) as test_file:
            for line in test_file:
                if line[0] == "#":
                    continue

                exp = line.split(":")
                test_name = exp[0]

                # Run two more times if test fails
                i = 0
                while (i < 3):
                    print "Running minindn test {}".format(test_name)
                    print test_name
                    if i == 0:
                        self.exp_names.append(test_name)
                    proc = subprocess.Popen(exp[1].split())
                    proc.wait()
                    self.clear_tmp()
                    subprocess.call("mn --clean".split())

                    if proc.returncode != 0:
                        if i == 2:
                            return 1, test_name
                        time.sleep(30)
                    else:
                        # Test was successful
                        break
                    i += 1

                time.sleep(30)
        return 0, test_name

    def test_nlsr(self):
        """ Update and run NLSR test """
        self.message = ""
        if self.nlsr_src.install() != 0:
            self.message = "Unable to compile NLSR"
            self.score = -1
            return 1
        code, test = self.run_tests()
        if code != 0:
            print "Test {} failed!".format(test)
            self.message += '\n\n'.join(self.exp_names[:len(self.exp_names) -
                                                       1])
            self.message += "\n\nNLSR tester bot: Test {} failed!".format(test)
            self.score = -1
            return 1
        else:
            print "All tests passed!"
            self.message = "NLSR tester bot: \n\nAll tests passed! \n\n"
            self.message += '\n\n'.join(self.exp_names)
            print self.message
            self.score = 1
        return 0

    def update_dep(self):
        """ Update dependencies """
        git_source = [
            self.ndncxx_src, self.nfd_src, self.chronosync_src, self.psync_src,
            self.nlsr_src, self.minindn_src
        ]
        for source in git_source:
            if source.update_and_install() != 0:
                return 1
        return 0

    def get_and_test_changes(self):
        """ Pull the changes testable patches """
        # Get open NLSR changes already verified by Jenkins and mergable and not verified by self
        changes = self.rest.get(
            "changes/?q=status:open+project:NLSR+branch:master+is:mergeable+label:verified+label:Verified-Integration=0"
        )
        #changes = self.rest.get("changes/?q=4549")

        print("changes", changes)

        # iterate over testable changes
        for change in changes:
            print "Checking patch: {}".format(change['subject'])
            change_id = change['change_id']
            print change_id
            change_num = change['_number']

            current_rev = self.rest.get(
                "/changes/?q={}&o=CURRENT_REVISION".format(change_num))
            #print current_rev
            tmp = current_rev[0]['revisions']
            for item in tmp:
                patch = tmp[item]['_number']
                ref = tmp[item]['ref']
            print patch
            print ref

            # update source
            if self.update_dep() != 0:
                print "Unable to compile and install ndn-cxx, NFD, NLSR!"
                self.rev.set_message(
                    "NLSR tester bot: Unable to compile dependencies!")
                self.rev.add_labels({'Verified-Integration': 0})
            else:
                print "Pulling NLSR patch to a new branch..."
                self.nlsr_src.checkout_new_branch(change_id)
                self.nlsr_src.pull_from_gerrit("{}/NLSR".format(self.url), ref)

                # Check if there has been a change in cpp, hpp, or wscript files
                if self.nlsr_src.has_code_changes():
                    # Test the change
                    print "Testing NLSR patch"
                    self.test_nlsr()
                    print "Commenting"
                    self.rev.set_message(self.message)
                    self.rev.add_labels({'Verified-Integration': self.score})
                else:
                    print "No change in code"
                    self.rev.set_message(
                        "NLSR tester bot: No change in code, skipped testing!")
                    self.rev.add_labels({'Verified-Integration': 1})
                self.nlsr_src.clean_up(change_id)

            print self.rev
            self.rest.review(change_id, patch, self.rev)

            print "\n--------------------------------------------------------\n"
            time.sleep(60)
Example #20
0
from pygerrit2.rest import GerritRestAPI
from requests.auth import HTTPDigestAuth

auth = HTTPDigestAuth('username', 'password')

query = ["status:open"]
query += ["limit:1"]

rest = GerritRestAPI(url='https://gerrit.iotivity.org/gerrit/')
#changes = rest.get("/changes/I5eefd50d6dcfcc35fd20ffd3e6e147acbf924e45/detail")
projects = rest.get("/projects/?d")
print(projects)
print(len(projects))
changeOwnerDupList = []
for change in projects:
    #print(change['change_id'])
    #print(change['subject'])
    #print(change['status'])
    changeOwnerDupList.append(change['owner']['_account_id'])
    #print((changeOwnerDupList))

    #changes = rest.get("/changes/" + change['change_id'] + "/detail")

#print(len(changeOwnerDupList))
changeOwnerList = []
#changeOwnerList=set(changeOwnerDupList)
#print(len(changeOwnerList))
changeOwners = []
for index, change in enumerate(projects, 1):
    print("Index %s" % index)
    changeDetail = rest.get("/changes/" + change['id'] + "/detail")
class ReviewExtractor:
    def __init__(self, url='https://gerrit.iotivity.org/gerrit/'):
        self.changeList = []
        self.url = url

    def query(self, project_name, limit=10):
        if limit is None:
            limitRange = ""
        else:
            limitRange = "&n=" + str(limit)

        self.project_name = project_name
        self.limit = limit

        self.rest = GerritRestAPI(url=self.url)
        self.changes = self.rest.get("/changes/?q=project:" +
                                     self.project_name + limitRange)
        #self.changes = self.rest.get("/changes/?q=status:merged" + "&n=" + str(self.limit))

        #print(self.changes)
        #self.ownerDupList=[]
        index = 1
        for change in self.changes:
            print("Change Collecting Index in ReviewExtractor.query() %s" %
                  index)
            index += 1
            reviewDict = self.getReviewDict(change)
            if reviewDict is not None:
                self.changeList.append(reviewDict)
            #self.ownerDupList.append(self.changeList[-1]['changeDetail']['owner']['name'])

    def getChangeOwner(self, change):
        changeDetail = change['changeDetail']
        changeOwner = changeDetail['owner']['name']
        #return changeOwner.encode('utf-8')
        return changeOwner

    def getOwnerList(self, limit=None):
        if limit is None:
            limitRange = ""
        else:
            limitRange = "&n=" + str(limit)

        self.ownerDupList = []
        changes = self.rest.get("/changes/?q=project:" + self.project_name +
                                limitRange)
        for index, change in enumerate(changes, 1):
            print(
                "Owner Collecting Index in ReviewExtractor.getOwnerList() %s" %
                index)
            try:
                changeDetail = self.rest.get("/changes/" + change['id'] +
                                             "/detail")
            except:
                print(
                    "Change['id'] = %s is broken while extracting detail in getOwnerList()."
                    % str(change['id']))
                continue
            else:
                owner = changeDetail['owner']['name']
                #self.ownerDupList.append(owner.encode('utf-8'))
                self.ownerDupList.append(owner)
        ownerList = set(self.ownerDupList)
        return ownerList

    def getProjectReviewers(self):
        rl = []

        for change in self.changeList:
            reviewInfo = self.getReviewInfo(change)
            for review in reviewInfo:
                reviewer = self.getReviewer(review)
                if (reviewer.startswith("jenkin")):
                    continue
                rl.append(reviewer)

        projectReviewers = set(rl)
        return projectReviewers

    def getReviewDict(self, change):
        reviewDict = {}

        try:
            changeDetail = self.rest.get("/changes/" + change['id'] +
                                         "/detail")
        except:
            print(
                "Change['id'] = %s is broken while extracting detail in getReviewDict()."
                % str(change['id']))
            return None
        else:
            reviewDict['changeDetail'] = changeDetail
            messages = changeDetail['messages']
            reviewDict['messages'] = messages
            comments = self.rest.get("/changes/" + change['id'] + "/comments/")
            reviewDict['comments'] = comments

            modifiedMessages = messages
            for review in modifiedMessages:
                # print("Author:"+str(change['author']['name'])+"  Message:"+str(change['message']),end='\n')
                review['comments'] = []
                for link in comments.keys():
                    extraMessage = ''
                    isFound = False
                    for listElem in comments[link]:
                        author = listElem['author']
                        try:
                            if ((review['author']['_account_id']
                                 == author['_account_id']) and
                                (review['date'] == listElem['updated'])):
                                isFound = True
                                if not link in review.keys():
                                    review[link] = []
                                if not link in review['comments']:
                                    review['comments'].append(link)
                                if not listElem['id'] in review[link]:
                                    review[link].append(listElem['id'])
                                extraMessage = extraMessage + '\n' + 'Line ' + str(
                                    listElem['line']
                                ) + ': ' + listElem['message']
                        except:
                            isFound = False

                    if isFound:
                        review['message'] = review[
                            'message'] + '\n' + link + extraMessage + '\n'

            reviewDict['reviewInfo'] = modifiedMessages

            return reviewDict

    def getChangeList(self):
        return self.changeList

    def getChangeListSubjects(self):
        subjectLists = []
        for change in self.changeList:
            subjectLists.append(self.getChangeSubject(change))
        return subjectLists

    def getChangeId(self, change):
        changeDetail = change['changeDetail']
        return changeDetail['id']

    def getChangeSubject(self, change):
        changeDetail = change['changeDetail']
        return changeDetail['subject']

    def getChangeSubject(self, change):
        changeDetail = change['changeDetail']
        return changeDetail['subject']

    def getLastPatchCount(self, change):
        changeDetail = change['changeDetail']
        message = changeDetail['messages']
        return (message[-1]['_revision_number'])

    def isLast(self, change, review):
        changeDetail = change['changeDetail']
        if (changeDetail['status'].lower() == "new"
                or changeDetail['status'].lower() == "open"):
            return 0
        elif (self.getLastPatchCount(change) != review['_revision_number']):
            return 0
        else:
            return 1

    def getReviewInfo(self, change):
        return change['reviewInfo']

    def getReviewId(self, review):
        return review['id']

    def getReviewer(self, review):
        if 'author' in review.keys():
            reviewer = review['author']['name']
            #return reviewer.encode('utf-8')
            return reviewer
        return "Gerrit-Review"

    def getReview(self, review):
        reviewData = review['message']
        #return reviewData.encode('utf-8')
        return reviewData

    def getReviewDate(self, review):
        return review['date']
def _main():
    parser = optparse.OptionParser()
    parser.add_option(
        "-g",
        "--gerrit-url",
        dest="gerrit_url",
        metavar="URL",
        default=None,
        help="gerrit server URL",
    )
    parser.add_option(
        "-b",
        "--basic-auth",
        dest="basic_auth",
        action="store_true",
        help="(deprecated) use HTTP basic authentication instead of digest",
    )
    parser.add_option(
        "-d",
        "--digest-auth",
        dest="digest_auth",
        action="store_true",
        help="use HTTP digest authentication instead of basic",
    )
    parser.add_option(
        "-n",
        "--dry-run",
        dest="dry_run",
        action="store_true",
        help="enable dry-run mode: show stale changes but do not abandon them",
    )
    parser.add_option(
        "-t",
        "--test",
        dest="testmode",
        action="store_true",
        help="test mode: query changes with the `test-abandon` "
        "topic and ignore age option",
    )
    parser.add_option(
        "-a",
        "--age",
        dest="age",
        metavar="AGE",
        default="6months",
        help="age of change since last update in days, months"
        " or years (default: %default)",
    )
    parser.add_option(
        "-m",
        "--message",
        dest="message",
        metavar="STRING",
        default=None,
        help="custom message to append to abandon message",
    )
    parser.add_option(
        "--branch",
        dest="branches",
        metavar="BRANCH_NAME",
        default=[],
        action="append",
        help="abandon changes only on the given branch",
    )
    parser.add_option(
        "--exclude-branch",
        dest="exclude_branches",
        metavar="BRANCH_NAME",
        default=[],
        action="append",
        help="do not abandon changes on given branch",
    )
    parser.add_option(
        "--project",
        dest="projects",
        metavar="PROJECT_NAME",
        default=[],
        action="append",
        help="abandon changes only on the given project",
    )
    parser.add_option(
        "--exclude-project",
        dest="exclude_projects",
        metavar="PROJECT_NAME",
        default=[],
        action="append",
        help="do not abandon changes on given project",
    )
    parser.add_option(
        "--owner",
        dest="owner",
        metavar="USERNAME",
        default=None,
        action="store",
        help="only abandon changes owned by the given user",
    )
    parser.add_option(
        "--exclude-wip",
        dest="exclude_wip",
        action="store_true",
        help="Exclude changes that are Work-in-Progress",
    )
    parser.add_option(
        "-v",
        "--verbose",
        dest="verbose",
        action="store_true",
        help="enable verbose (debug) logging",
    )

    (options, _args) = parser.parse_args()

    level = logging.DEBUG if options.verbose else logging.INFO
    logging.basicConfig(format="%(asctime)s %(levelname)s %(message)s",
                        level=level)

    if not options.gerrit_url:
        logging.error("Gerrit URL is required")
        return 1

    if options.testmode:
        message = "Abandoning in test mode"
    else:
        pattern = re.compile(r"^([\d]+)(month[s]?|year[s]?|week[s]?)")
        match = pattern.match(options.age)
        if not match:
            logging.error("Invalid age: %s", options.age)
            return 1
        message = "Abandoning after %s %s or more of inactivity." % (
            match.group(1),
            match.group(2),
        )

    if options.digest_auth:
        auth_type = HTTPDigestAuthFromNetrc
    else:
        auth_type = HTTPBasicAuthFromNetrc

    try:
        auth = auth_type(url=options.gerrit_url)
        gerrit = GerritRestAPI(url=options.gerrit_url, auth=auth)
    except Exception as e:
        logging.error(e)
        return 1

    logging.info(message)
    try:
        stale_changes = []
        offset = 0
        step = 500
        if options.testmode:
            query_terms = ["status:new", "owner:self", "topic:test-abandon"]
        else:
            query_terms = ["status:new", "age:%s" % options.age]
        if options.exclude_wip:
            query_terms += ["-is:wip"]
        if options.branches:
            query_terms += ["branch:%s" % b for b in options.branches]
        elif options.exclude_branches:
            query_terms += ["-branch:%s" % b for b in options.exclude_branches]
        if options.projects:
            query_terms += ["project:%s" % p for p in options.projects]
        elif options.exclude_projects:
            query_terms = ["-project:%s" % p for p in options.exclude_projects]
        if options.owner and not options.testmode:
            query_terms += ["owner:%s" % options.owner]
        query = "%20".join(query_terms)
        while True:
            q = query + "&o=DETAILED_ACCOUNTS&n=%d&S=%d" % (step, offset)
            logging.debug("Query: %s", q)
            url = "/changes/?q=" + q
            result = gerrit.get(url)
            logging.debug("%d changes", len(result))
            if not result:
                break
            stale_changes += result
            last = result[-1]
            if "_more_changes" in last:
                logging.debug("More...")
                offset += step
            else:
                break
    except Exception as e:
        logging.error(e)
        return 1

    abandoned = 0
    errors = 0
    abandon_message = message
    if options.message:
        abandon_message += "\n\n" + options.message
    for change in stale_changes:
        number = change["_number"]
        project = ""
        if len(options.projects) != 1:
            project = "%s: " % change["project"]
        owner = ""
        if options.verbose:
            try:
                o = change["owner"]["name"]
            except KeyError:
                o = "Unknown"
            owner = " (%s)" % o
        subject = change["subject"]
        if len(subject) > 70:
            subject = subject[:65] + " [...]"
        change_id = change["id"]
        logging.info("%s%s: %s%s", number, owner, project, subject)
        if options.dry_run:
            continue

        try:
            gerrit.post(
                "/changes/" + change_id + "/abandon",
                json={"message": "%s" % abandon_message},
            )
            abandoned += 1
        except Exception as e:
            errors += 1
            logging.error(e)
    logging.info("Total %d stale open changes", len(stale_changes))
    if not options.dry_run:
        logging.info("Abandoned %d changes. %d errors.", abandoned, errors)
class GerritApi():
    def __init__(self):
        self.user = '******'
        self.password = os.getenv('GERRIT_PASSWORD')
        auth = HTTPDigestAuth(self.user, self.password)
        #gerrit site
        ip = "gerrit.zte.com.cn"
        self.url = 'http://{}'.format(ip)
        self.ssh_url = 'ssh://{}@{}:29418'.format(self.user, ip)
        self.rest = GerritRestAPI(url=self.url, auth=auth)
        self.project_info = 'projects_info.txt'
        self.project_config_template = "project_config.template"
        self.group_types = ('admin', 'core', 'team')

    def create_projects(self):
        with open(self.project_info, 'r') as f:
            projects = f.readlines()
        for repo in projects:
            proj_repo, group = repo.split(':')
            group = group.strip('\r\n')

            self.create_project(proj_repo)
            self.update_project_group_config(proj_repo, group)

    def update_project_group_config(self, proj_repo, group):
        #make groups
        groups = ['{}-{}'.format(group, x) for x in self.group_types]
        #set yourself the owner
        #data={"owner":"10064088"}
        #self.rest.put("/groups/{}/owner",data=data)

        #modify project config
        cmd = 'git clone {}/{}'.format(self.ssh_url, proj_repo)
        os.system(cmd)
        origin_folder = os.getcwd()
        folder_name = proj_repo.split('/')[-1]
        os.chdir(folder_name)

        os.system('git fetch origin refs/meta/config:refs/meta/config')
        os.system('git checkout refs/meta/config')

        self.generate_groups_UUID_map(groups)
        #self.generate_project_config(proj_repo.split('/')[0], group)
        self.generate_project_config("Power-RD-Projects", group)

        os.system('git add .')
        os.system('git commit -m "update config access"')
        os.system('git push origin HEAD:refs/meta/config')

        #you should chdir back
        os.chdir(origin_folder)
        #os.system("rm -rf {}".format(folder_name))

    def create_project(self, proj_repo):
        #create
        #you must do this replacement, or else if fails
        proj_repo_id = proj_repo.replace('/', '%2F')

        #you must add this! or else you cannot visit the project after created the project unless you are in administrators
        payload = {"parent": "Power-RD-Projects"}
        #IMPORTART: json=payload is ok, data=payload is not ok!!! f**k! wasting my debug time!
        try:
            ret = self.rest.put('/projects/{}'.format(proj_repo_id),
                                json=payload)
        except:
            print("project {} exists".format(proj_repo))

    def generate_groups_UUID_map(self, groups):
        with open('groups', 'w') as f:
            for group in groups:
                print(group)
                ret = self.rest.get('/groups/{}'.format(group))
                f.write("{}\t{}\n".format(ret['id'], group))

    def generate_project_config(self, institute, group):
        with open(os.path.join("..", self.project_config_template), 'r') as f:
            config_template = Template(f.read())

        with open('project.config', 'w') as f:
            f.write(
                config_template.substitute(Institute=institute, Group=group))
Example #24
0
def Gerrite_Auth():
    auth = HTTPBasicAuth(GERRITE_USER,GERRITE_PWD)
    rest = GerritRestAPI(url=GERRITE_URL_AUTH,auth=auth)
    return rest
Example #25
0
from pygerrit2.rest import GerritRestAPI
from requests.auth import HTTPDigestAuth
import sqlite3

from Classification.Classifier import Classifier
from ReviewExtractor import ReviewExtractor

clf = Classifier()

rest = GerritRestAPI(url='https://gerrit.iotivity.org/gerrit/')
connection = sqlite3.connect('Gerrit.db')
connection.text_factory = str
cursor = connection.cursor()
cursor.execute(
    "CREATE TABLE IF NOT EXISTS ProjectTable(project_name TEXT, project_id TEXT, project_description TEXT)"
)
cursor.execute(
    "CREATE TABLE IF NOT EXISTS ChangeTable(change_id TEXT, project_name TEXT, change_subject TEXT, "
    "change_owner TEXT, FOREIGN KEY(project_name) REFERENCES ProjectTable(project_name) ON DELETE CASCADE)"
)
cursor.execute(
    "CREATE TABLE IF NOT EXISTS ReviewTable(review_id TEXT,change_id TEXT, reviewer TEXT, review_date DATE, reviewData TEXT, "
    "usefulness TEXT, FOREIGN KEY (change_id) REFERENCES ChangeTable(change_id) ON DELETE CASCADE)"
)


def projectInsert(project_name, project_id, project_description):
    cursor.executemany(
        "INSERT INTO ProjectTable(project_name, project_id, project_description)"
        " VALUES(?,?,?)", [(project_name, project_id, project_description)])
    connection.commit()
from requests.auth import HTTPDigestAuth
from pygerrit2.rest import GerritRestAPI
from pprint import pprint
import os

if __name__ == "__main__":
    user = '******'
    password = os.getenv('GERRIT_PASSWORD')
    auth = HTTPDigestAuth(user, password)
    url = 'http://gerrit.zte.com.cn'
    #url = 'http://10.43.177.99'
    rest = GerritRestAPI(url=url, auth=auth)
    #changes=rest.get("/changes/?q=owner:self%20status:open")
    #changes=rest.get("/accounts/self/groups")
    #changes=rest.put("/projects/Power-RD-Projects")
    #changes = rest.delete("/groups/465526c73496969c10b3412a2b76aecf5dda4df9")
    changes = rest.get("/projects/")
    pprint(changes)
MISC = dict()
MISC.update(CONFIG.items('Misc'))

TWILIO = dict()
TWILIO.update(CONFIG.items('Twilio'))

# Paramiko client
SSH_CLIENT = paramiko.SSHClient()
HOSTKEY_PATH = os.path.join(DIR, 'ssh-host-key')
SSH_CLIENT.load_host_keys(HOSTKEY_PATH)
SSH_CLIENT.set_missing_host_key_policy(paramiko.AutoAddPolicy())
SSH_CLIENT.connect(**GERRIT_SSH)

# Rest client
REST_AUTH = HTTPBasicAuth(MISC['auth_username'], MISC['auth_password'])
REST_CLIENT = GerritRestAPI(url=MISC['base_url'], auth=REST_AUTH)

# Twilio client
TWILIO_CLIENT = TwilioRestClient(TWILIO['account_sid'], TWILIO['auth_token'])


class WatchPatchsets(threading.Thread):
    """This class watches gerrit stream event patchset-created
    """
    def run(self):
        while True:
            try:
                cmd_patchset_created = 'gerrit stream-events -s patchset-created'
                _, stdout, _ = SSH_CLIENT.exec_command(cmd_patchset_created)
                for line in stdout:
                    QUEUE.put(json.loads(line))
Example #28
0
def _main():
    parser = optparse.OptionParser()
    parser.add_option('-g', '--gerrit-url', dest='gerrit_url',
                      metavar='URL',
                      default=None,
                      help='gerrit server URL')
    parser.add_option('-b', '--basic-auth', dest='basic_auth',
                      action='store_true',
                      help='(deprecated) use HTTP basic authentication instead'
                      ' of digest')
    parser.add_option('-d', '--digest-auth', dest='digest_auth',
                      action='store_true',
                      help='use HTTP digest authentication instead of basic')
    parser.add_option('-n', '--dry-run', dest='dry_run',
                      action='store_true',
                      help='enable dry-run mode: show stale changes but do '
                           'not abandon them')
    parser.add_option('-a', '--age', dest='age',
                      metavar='AGE',
                      default="6months",
                      help='age of change since last update '
                           '(default: %default)')
    parser.add_option('-m', '--message', dest='message',
                      metavar='STRING', default=None,
                      help='Custom message to append to abandon message')
    parser.add_option('--branch', dest='branches', metavar='BRANCH_NAME',
                      default=[], action='append',
                      help='Abandon changes only on the given branch')
    parser.add_option('--exclude-branch', dest='exclude_branches',
                      metavar='BRANCH_NAME',
                      default=[],
                      action='append',
                      help='Do not abandon changes on given branch')
    parser.add_option('--project', dest='projects', metavar='PROJECT_NAME',
                      default=[], action='append',
                      help='Abandon changes only on the given project')
    parser.add_option('--exclude-project', dest='exclude_projects',
                      metavar='PROJECT_NAME',
                      default=[],
                      action='append',
                      help='Do not abandon changes on given project')
    parser.add_option('--owner', dest='owner',
                      metavar='USERNAME',
                      default=None,
                      action='store',
                      help='Only abandon changes owned by the given user')
    parser.add_option('-v', '--verbose', dest='verbose',
                      action='store_true',
                      help='enable verbose (debug) logging')

    (options, _args) = parser.parse_args()

    level = logging.DEBUG if options.verbose else logging.INFO
    logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
                        level=level)

    if not options.gerrit_url:
        logging.error("Gerrit URL is required")
        return 1

    pattern = re.compile(r"^([\d]+)(month[s]?|year[s]?|week[s]?)")
    match = pattern.match(options.age)
    if not match:
        logging.error("Invalid age: %s", options.age)
        return 1
    message = "Abandoning after %s %s or more of inactivity." % \
        (match.group(1), match.group(2))

    if options.digest_auth:
        auth_type = HTTPDigestAuthFromNetrc
    else:
        auth_type = HTTPBasicAuthFromNetrc

    try:
        auth = auth_type(url=options.gerrit_url)
        gerrit = GerritRestAPI(url=options.gerrit_url, auth=auth)
    except Exception as e:
        logging.error(e)
        return 1

    logging.info(message)
    try:
        stale_changes = []
        offset = 0
        step = 500
        query_terms = ["status:new", "age:%s" % options.age]
        if options.branches:
            query_terms += ["branch:%s" % b for b in options.branches]
        elif options.exclude_branches:
            query_terms += ["-branch:%s" % b for b in options.exclude_branches]
        if options.projects:
            query_terms += ["project:%s" % p for p in options.projects]
        elif options.exclude_projects:
            query_terms = ["-project:%s" % p for p in options.exclude_projects]
        if options.owner:
            query_terms += ["owner:%s" % options.owner]
        query = "%20".join(query_terms)
        while True:
            q = query + "&n=%d&S=%d" % (step, offset)
            logging.debug("Query: %s", q)
            url = "/changes/?q=" + q
            result = gerrit.get(url)
            logging.debug("%d changes", len(result))
            if not result:
                break
            stale_changes += result
            last = result[-1]
            if "_more_changes" in last:
                logging.debug("More...")
                offset += step
            else:
                break
    except Exception as e:
        logging.error(e)
        return 1

    abandoned = 0
    errors = 0
    abandon_message = message
    if options.message:
        abandon_message += "\n\n" + options.message
    for change in stale_changes:
        number = change["_number"]
        try:
            owner = change["owner"]["name"]
        except:
            owner = "Unknown"
        subject = change["subject"]
        if len(subject) > 70:
            subject = subject[:65] + " [...]"
        change_id = change["id"]
        logging.info("%s (%s): %s", number, owner, subject)
        if options.dry_run:
            continue

        try:
            gerrit.post("/changes/" + change_id + "/abandon",
                        data='{"message" : "%s"}' % abandon_message)
            abandoned += 1
        except Exception as e:
            errors += 1
            logging.error(e)
    logging.info("Total %d stale open changes", len(stale_changes))
    if not options.dry_run:
        logging.info("Abandoned %d changes. %d errors.", abandoned, errors)
Example #29
0
def _main():
    descr = "Perform bulk operations on Gerrit"
    parser = argparse.ArgumentParser(
        description=descr, formatter_class=argparse.ArgumentDefaultsHelpFormatter
    )
    parser.add_argument(
        "-u",
        "--gerrit-url",
        dest="url",
        required=False,
        default="https://gerrit-review.googlesource.com",
        help="Gerrit URL",
    )
    parser.add_argument(
        "-q", "--query", dest="query", required=True, action="store", help="query"
    )
    parser.add_argument(
        "-o",
        "--option",
        dest="options",
        required=False,
        action="append",
        help="query options",
    )
    parser.add_argument(
        "-c",
        "--commands",
        dest="commands",
        required=False,
        action="store_true",
        help="how to fetch changes; appends -o " + REVISION + " -o " + COMMANDS,
    )
    parser.add_argument(
        "-a",
        "--approve",
        dest="approve",
        required=False,
        action="store_true",
        help="apply Code-Review+2 to changes",
    )
    parser.add_argument(
        "-v",
        "--verify",
        dest="verify",
        required=False,
        action="store_true",
        help="apply Verified+1 to changes",
    )
    parser.add_argument(
        "-s",
        "--submit",
        dest="submit",
        required=False,
        action="store_true",
        help="submit changes",
    )
    parser.add_argument(
        "-f",
        "--filter",
        dest="filter",
        required=False,
        help="filter changes by project prefix",
    )
    parser.add_argument(
        "-fs",
        "--subject",
        dest="subject",
        required=False,
        help="filter changes by subject prefix",
    )
    parser.add_argument(
        "--abandon",
        dest="abandon",
        required=False,
        action="store_true",
        help="abandon changes",
    )
    parser.add_argument(
        "--hashtag",
        dest="hashtags",
        required=False,
        action="append",
        help="add hashtags",
    )
    parser.add_argument(
        "-r",
        "--reviewer",
        dest="reviewers",
        required=False,
        action="append",
        help="add reviewers",
    )
    options = parser.parse_args()

    api = GerritRestAPI(url=options.url)
    query_terms = options.query.replace(" ", "%20")
    uri = "/changes/?q=" + query_terms
    query_options = [o.upper() for o in options.options] if options.options else []
    if options.commands:
        if REVISION not in query_options:
            query_options.append(REVISION)
        if COMMANDS not in query_options:
            query_options.append(COMMANDS)
    if query_options:
        uri += "".join(["&o=%s" % o for o in query_options])
    changes = api.get(uri)
    changes_count = len(changes)
    print("Found %d changes" % changes_count)
    if options.filter:
        changes = [c for c in changes if c["project"].startswith(options.filter)]
    if options.subject:
        changes = [c for c in changes if c["subject"].startswith(options.subject)]
    filtered_count = len(changes)
    if filtered_count < changes_count:
        print("Filtered out %d changes" % (changes_count - filtered_count))
    labels = {}
    review = {}
    if options.reviewers:
        review["reviewers"] = [{"reviewer": r} for r in options.reviewers]
    if options.verify:
        labels["Verified"] = 1
    if options.approve:
        labels["Code-Review"] = 2
    if labels:
        review["labels"] = labels
    for change in changes:
        print("%s : %s" % (change["project"], change["subject"]))
        try:
            if options.hashtags:
                hashtags = {"add": options.hashtags}
                api.post("/changes/%s/hashtags" % change["id"], json=hashtags)
            if options.abandon:
                api.post("/changes/%s/abandon" % change["id"])
                continue
            if review:
                api.post(
                    "/changes/%s/revisions/current/review" % change["id"], json=review
                )
            if options.submit:
                api.post("/changes/%s/submit" % change["id"])
        except Exception as e:
            print("Operation failed: %s" % e, file=sys.stderr)
    if options.commands:
        for change in changes:
            repo = change["project"].split("/")[-1]
            command = next(iter(change["revisions"].values()))["fetch"]["http"][
                "commands"
            ]["Checkout"]
            print("cd %s && %s && cd -" % (repo, command))
Example #30
0
class GerritChangeFetcher():
    gerrit_url = "https://review.lineageos.org/"  # Needs a trailing slash
    rest = GerritRestAPI(url=gerrit_url)

    @classmethod
    def get_change(self, changenum):
        # Use DETAILED_ACCOUNTS so we don't have to make a second API call for owner email and name
        change = self.rest.get(
            "/changes/{}?o=DETAILED_ACCOUNTS".format(changenum))
        return {
            "fallback":
            "{}#/c/{}: {}".format(self.gerrit_url, change['_number'],
                                  change['subject']),
            "color":
            "good",
            "title":
            "{}: {} ({})".format(
                change['_number'], change['subject'], 'Open' if
                change['status'] == 'NEW' else change['status'].capitalize()),
            "title_link":
            "{}#/c/{}".format(self.gerrit_url, change['_number']),
            "mrkdwn_in": ["text"],
            'text':
            ("*Project*: <{base}#/q/project:{project}|{project}> ({branch})\n"
             "*Topic*: {topic}\n"
             "*Owner*: <{base}#/q/owner:{username}|{name} ({email})>").format(
                 project=change['project'],
                 branch=change['branch'],
                 topic='<{}#/q/{topic}|{topic}>'.format(self.gerrit_url,
                                                        topic=change['topic'])
                 if 'topic' in change else 'None',
                 username=change['owner']['username'],
                 name=change['owner']['name'],
                 email=change['owner']['email'],
                 base=self.gerrit_url,
             )
        }

    @classmethod
    def get_topic(self, topic_name):
        topic = self.rest.get("/changes/?q=topic:{}".format(topic_name))
        t_changes = ocn = mcn = acn = omcn = 0
        # Initialise these separately (unlike before), so we don't end up with
        # projects == branches
        projects, branches = [], []
        for change in topic:
            if change['project'] not in projects:
                projects.append(change['project'])
            if change['branch'] not in branches:
                branches.append(change['branch'])
            if change['status'] == 'NEW':
                ocn = ocn + 1
                if change['mergeable']:
                    omcn = omcn + 1
            if change['status'] == 'MERGED':
                mcn = mcn + 1
            if change['status'] == 'ABANDONED':
                acn = acn + 1
            t_changes = t_changes + 1
        return {
            "fallback":
            "Topic: {}".format(topic_name),
            "color":
            "good",
            "title":
            "Topic: {}".format(topic_name),
            "title_link":
            "{}#/q/topic:{}".format(self.gerrit_url, topic_name),
            "mrkdwn_in": ["text"],
            "text":
            ("{total} commits across {projects} projects on {branches} branch(es)\n"
             "*Open*: <{base}#/q/status:open%20AND%20topic:{name}|{ocn}>, "
             "of which <{base}#/q/status:open%20AND%20is:mergeable%20AND%20topic:{name}|{omcn}> are mergeable\n"
             "*Merged*: <{base}#/q/status:merged%20AND%20topic:{name}|{mcn}>\n"
             "*Abandoned*: <{base}#/q/status:abandoned%20AND%20topic:{name}|{acn}>"
             ).format(
                 projects=len(projects),
                 branches=len(branches),
                 total=t_changes,
                 base=self.gerrit_url,
                 name=topic_name,
                 ocn=ocn,
                 omcn=omcn,
                 mcn=mcn,
                 acn=acn,
             )
        }
Example #31
0
class GerritChangeFetcher(Plugin):
    gerrit_url = "https://review.lineageos.org/"  # Needs a trailing slash
    rest = GerritRestAPI(url=gerrit_url)

    def PostChangesInfo(self, channel, changenum):
        # Use DETAILED_ACCOUNTS so we don't have to make a second API call for owner email and name
        change = self.rest.get(
            "/changes/{}?o=DETAILED_ACCOUNTS".format(changenum))
        self.slack_client.api_call(
            'chat.postMessage',
            channel=channel,
            as_user=True,
            attachments=[{
                "fallback":
                "{}#/c/{}: {}".format(self.gerrit_url, change['_number'],
                                      change['subject']),
                "color":
                "good",
                "title":
                "{}: {} ({})".format(
                    change['_number'], change['subject'],
                    'Open' if change['status'] == 'NEW' else
                    change['status'].capitalize()),
                "title_link":
                "{}#/c/{}".format(self.gerrit_url, change['_number']),
                "mrkdwn_in": ["text"],
                'text':
                ("*Project*: <{base}#/q/project:{project}|{project}> ({branch})\n"
                 "*Topic*: {topic}\n"
                 "*Owner*: <{base}#/q/owner:{username}|{name} ({email})>"
                 ).format(
                     project=change['project'],
                     branch=change['branch'],
                     topic='<{}#/q/{topic}|{topic}>'.format(
                         self.gerrit_url, topic=change['topic'])
                     if 'topic' in change else 'None',
                     username=change['owner']['username'],
                     name=change['owner']['name'],
                     email=change['owner']['email'],
                     base=self.gerrit_url,
                 )
            }])

    def PostTopicInfo(self, channel, topic_name):
        topic = self.rest.get("/changes/?q=topic:{}".format(topic_name))
        t_changes = ocn = mcn = acn = omcn = 0
        # Initialise these separately (unlike before), so we don't end up with
        # projects == branches
        projects, branches = [], []
        for change in topic:
            if change['project'] not in projects:
                projects.append(change['project'])
            if change['branch'] not in branches:
                branches.append(change['branch'])
            if change['status'] == 'NEW':
                ocn = ocn + 1
                if change['mergeable']:
                    omcn = omcn + 1
            if change['status'] == 'MERGED':
                mcn = mcn + 1
            if change['status'] == 'ABANDONED':
                acn = acn + 1
            t_changes = t_changes + 1
        self.slack_client.api_call(
            'chat.postMessage',
            channel=channel,
            as_user=True,
            attachments=[{
                "fallback":
                "Topic: {}".format(topic_name),
                "color":
                "good",
                "title":
                "Topic: {}".format(topic_name),
                "title_link":
                "{}#/q/topic:{}".format(self.gerrit_url, topic_name),
                "mrkdwn_in": ["text"],
                "text":
                ("{total} commits across {projects} projects on {branches} branch(es)\n"
                 "*Open*: <{base}#/q/status:open%20AND%20topic:{name}|{ocn}>, "
                 "of which <{base}#/q/status:open%20AND%20is:mergeable%20AND%20topic:{name}|{omcn}> are mergeable\n"
                 "*Merged*: <{base}#/q/status:merged%20AND%20topic:{name}|{mcn}>\n"
                 "*Abandoned*: <{base}#/q/status:abandoned%20AND%20topic:{name}|{acn}>"
                 ).format(
                     projects=len(projects),
                     branches=len(branches),
                     total=t_changes,
                     base=self.gerrit_url,
                     name=topic_name,
                     ocn=ocn,
                     omcn=omcn,
                     mcn=mcn,
                     acn=acn,
                 )
            }])

    def process_message(self, data):
        text = data['text']
        channel = data['channel']
        changes = topics = []
        number_detections = 0
        if re.search(r'\bignore\b', text):
            return False
        for word in text.split():
            if self.gerrit_url in word:
                if number_detections >= 4:
                    break  # only print first 4 changes. any more is excessive
                number_detections += 1
                topic = re.search(r'(?:topic:)(.+?(?:(?=[%\s+]|$|>)))', word)
                # explicitly check for url as prefix to avoid detecting numbers in project name queries
                change = re.search(
                    r'(?:' + self.gerrit_url.replace('.', r'\.') +
                    ')(?:(?:#\/c\/)|)([0-9]{4,7})', word)
                if change is not None:
                    GerritChangeFetcher.PostChangesInfo(
                        self, channel, change.group(1))
                elif topic is not None:
                    GerritChangeFetcher.PostTopicInfo(self, channel,
                                                      topic.group(1))
                else:
                    return False