Convert update_blueprint to use the Gerrit REST API

This calls the Gerrit REST API to retrieve subject and topic for a
change instead of querying the Gerrit database. The ReviewDb was
removed in Gerrit 3.0 [1], so we need to use the REST API instead.

This also uses the Gerrit API to get the change commit message instead
of running git commands directly in the git directory.

[1] https://www.gerritcodereview.com/releases-readme.html#30-eol

Change-Id: I25b67745d3943786767d6c8960ff19cdc51b5769
This commit is contained in:
melanie witt 2021-06-11 00:53:48 +00:00
parent 6b1c39df5d
commit faca72ce59
1 changed files with 55 additions and 58 deletions

View File

@ -18,55 +18,28 @@
# corresponding Launchpad blueprints with links back to the change.
import argparse
import six
from six.moves import configparser
import json
import logging
import os
import re
import subprocess
from launchpadlib import launchpad
from launchpadlib import uris
import pymysql
import requests
from jeepyb import projects as p
GERRIT_GIT_DIR = os.environ.get(
'GERRIT_GIT_DIR', '/home/gerrit2/review_site/git')
GERRIT_CACHE_DIR = os.path.expanduser(
os.environ.get('GERRIT_CACHE_DIR',
'~/.launchpadlib/cache'))
GERRIT_CREDENTIALS = os.path.expanduser(
os.environ.get('GERRIT_CREDENTIALS',
'~/.launchpadlib/creds'))
GERRIT_CONFIG = os.environ.get('GERRIT_CONFIG',
'/home/gerrit2/review_site/etc/gerrit.config')
GERRIT_SECURE_CONFIG_DEFAULT = '/home/gerrit2/review_site/etc/secure.config'
GERRIT_SECURE_CONFIG = os.environ.get('GERRIT_SECURE_CONFIG',
GERRIT_SECURE_CONFIG_DEFAULT)
GERRIT_API_URL = 'https://review.opendev.org'
GERRIT_API_CHANGES_URL = GERRIT_API_URL + '/changes/'
SPEC_RE = re.compile(r'\b(blueprint|bp)\b[ \t]*[#:]?[ \t]*(\S+)', re.I)
BODY_RE = re.compile(r'^\s+.*$')
def get_broken_config(filename):
"""gerrit config ini files are broken and have leading tabs."""
text = ""
with open(filename, "r") as conf:
for line in conf.readlines():
text = "%s%s" % (text, line.lstrip())
fp = six.StringIO(text)
c = configparser.ConfigParser(strict=False)
c.readfp(fp)
return c
GERRIT_CONFIG = get_broken_config(GERRIT_CONFIG)
SECURE_CONFIG = get_broken_config(GERRIT_SECURE_CONFIG)
DB_HOST = GERRIT_CONFIG.get("database", "hostname")
DB_USER = GERRIT_CONFIG.get("database", "username")
DB_PASS = SECURE_CONFIG.get("database", "password")
DB_DB = GERRIT_CONFIG.get("database", "database")
LOG = logging.getLogger('update_blueprint')
def update_spec(launchpad, project, name, subject, link, topic=None):
@ -108,28 +81,55 @@ def update_spec(launchpad, project, name, subject, link, topic=None):
spec.lp_save()
def find_specs(launchpad, dbconn, args):
git_dir_arg = '--git-dir={base_dir}/{project}.git'.format(
base_dir=GERRIT_GIT_DIR,
project=args.project)
git_log = subprocess.Popen(
[
'git', git_dir_arg, 'log', '--no-merges',
args.commit + '^1..' + args.commit
],
stdout=subprocess.PIPE).communicate()[0].decode('utf-8')
def find_specs(launchpad, args):
# Newer gerrit provides the change argument in this format:
# gtest-org%2Fgtest~master~I117f34aaa4253e0b82b98de9077f7188d55c3f33
# So this should be unique to a branch and return a single change.
change = args.change
if '~' in change:
# Newer gerrit provides the change argument in this format:
# gtest-org%2Fgtest~master~I117f34aaa4253e0b82b98de9077f7188d55c3f33
# So we need to split off the changeid if there is other data in there.
change = change.rsplit('~', 1)[1]
cur = dbconn.cursor()
cur.execute("select subject, topic from changes where change_key=%s",
change)
subject, topic = cur.fetchone()
specs = set([m.group(2) for m in SPEC_RE.finditer(git_log)])
commit = args.commit
# Get the change to get the subject and topic.
# Get Change: 'GET /changes/{change-id}'
url = GERRIT_API_CHANGES_URL + change
try:
resp = requests.get(url, headers={'Accept': 'application/json'})
except Exception:
LOG.exception('Error calling: %s', url)
return
if resp.status_code == 200:
ret = json.loads(resp.text[4:])
if not ret:
return
else:
LOG.error('Request to %s returned: [%d] %s',
resp.url, resp.status_code, resp.reason)
return
subject = ret['subject']
# topic is optional and update_spec() handles topic=None
topic = ret.get('topic')
# Get the commit to get the commit message.
# Get Commit: 'GET /changes/{change-id}/revisions/{revision-id}/commit'
url = GERRIT_API_CHANGES_URL + change + '/revisions/' + commit + '/commit'
try:
resp = requests.get(url, headers={'Accept': 'application/json'})
except Exception:
LOG.exception('Error calling: %s', url)
return
if resp.status_code == 200:
ret = json.loads(resp.text[4:])
if not ret:
return
else:
LOG.error('Request to %s returned: [%d] %s',
resp.url, resp.status_code, resp.reason)
return
commit_message = ret['message']
specs = set([m.group(2) for m in SPEC_RE.finditer(commit_message)])
if topic:
topicspec = topic.split('/')[-1]
@ -169,10 +169,7 @@ def main():
'Gerrit User Sync', uris.LPNET_SERVICE_ROOT, GERRIT_CACHE_DIR,
credentials_file=GERRIT_CREDENTIALS, version='devel')
conn = pymysql.connect(
host=DB_HOST, user=DB_USER, password=DB_PASS, db=DB_DB)
find_specs(lpconn, conn, args)
find_specs(lpconn, args)
if __name__ == "__main__":