jeepyb/jeepyb/cmd/update_blueprint.py

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()