177 lines
5.5 KiB
Python
177 lines
5.5 KiB
Python
#!/usr/bin/env python
|
|
# Copyright (c) 2011 OpenStack Foundation
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
# This is designed to be called by a gerrit hook. It searched new
|
|
# patchsets for strings like "blueprint FOO" or "bp FOO" and updates
|
|
# corresponding Launchpad blueprints with links back to the change.
|
|
|
|
import argparse
|
|
import json
|
|
import logging
|
|
import os
|
|
import re
|
|
|
|
from launchpadlib import launchpad
|
|
from launchpadlib import uris
|
|
import requests
|
|
|
|
from jeepyb import projects as p
|
|
|
|
|
|
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_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)
|
|
LOG = logging.getLogger('update_blueprint')
|
|
|
|
|
|
def update_spec(launchpad, project, name, subject, link, topic=None):
|
|
spec = None
|
|
|
|
if p.is_no_launchpad_blueprints(project):
|
|
return
|
|
|
|
projects = p.project_to_groups(project)
|
|
|
|
for project in projects:
|
|
spec = launchpad.projects[project].getSpecification(name=name)
|
|
if spec:
|
|
break
|
|
|
|
if not spec:
|
|
return
|
|
|
|
if spec.whiteboard:
|
|
wb = spec.whiteboard.strip()
|
|
else:
|
|
wb = ''
|
|
changed = False
|
|
if topic:
|
|
topiclink = '%s/#/q/topic:%s' % (link[:link.find('/', 8)],
|
|
topic)
|
|
if topiclink not in wb:
|
|
wb += "\n\n\nGerrit topic: %(link)s" % dict(link=topiclink)
|
|
changed = True
|
|
|
|
if link not in wb:
|
|
wb += ("\n\n\nAddressed by: {link}\n"
|
|
" {subject}\n").format(subject=subject,
|
|
link=link)
|
|
changed = True
|
|
|
|
if changed:
|
|
spec.whiteboard = wb
|
|
spec.lp_save()
|
|
|
|
|
|
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
|
|
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]
|
|
specs |= set([topicspec])
|
|
|
|
for spec in specs:
|
|
update_spec(launchpad, args.project, spec, subject,
|
|
args.change_url, topic)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('hook')
|
|
# common
|
|
parser.add_argument('--change', default=None)
|
|
parser.add_argument('--change-url', default=None)
|
|
parser.add_argument('--project', default=None)
|
|
parser.add_argument('--branch', default=None)
|
|
parser.add_argument('--commit', default=None)
|
|
parser.add_argument('--topic', default=None)
|
|
parser.add_argument('--change-owner', default=None)
|
|
# patchset-abandoned
|
|
parser.add_argument('--abandoner', default=None)
|
|
parser.add_argument('--reason', default=None)
|
|
# change-merged
|
|
parser.add_argument('--submitter', default=None)
|
|
parser.add_argument('--newrev', default=None)
|
|
# patchset-created
|
|
parser.add_argument('--uploader', default=None)
|
|
parser.add_argument('--patchset', default=None)
|
|
parser.add_argument('--is-draft', default=None)
|
|
parser.add_argument('--kind', default=None)
|
|
|
|
args = parser.parse_args()
|
|
|
|
lpconn = launchpad.Launchpad.login_with(
|
|
'Gerrit User Sync', uris.LPNET_SERVICE_ROOT, GERRIT_CACHE_DIR,
|
|
credentials_file=GERRIT_CREDENTIALS, version='devel')
|
|
|
|
find_specs(lpconn, args)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|