246bbfe03b
This takes a list of projects from stdin in the format of aeromancer anvil blazar and renames stackforge/aeromancer, stackforge/anvil, and stackforge/blazar to openstack/aeromancer, openstack/anvil, and openstack/blazar respectively in gerrit/projects.yaml, gerritbot/channels.yaml, zuul/layout.html, and every file in jenkins/jobs/ , as well as renaming acl files. A side effect of this process is that comments will be stripped from gerritbot/channels.yaml ; if you are committing the results of a run of this script, please re-add the comments manually unless we come up with a more elegant solution. This script also has test coverage for verification and documentation. Also included is a WIP list of renames in data/stackforge-renames, as per http://eavesdrop.openstack.org/irclogs/%23openstack-infra/%23openstack-infra.2015-10-13.log.html#t2015-10-13T20:10:17 and a WIP list of retirements in data/stackforge-retirements, which is not used by the script in this change. Co-Authored-By: Augustina Ragwitz <aragwitz+lp@pobox.com> Change-Id: Iaf2a13d8b9b9a840d9fde07ec1ef65d1c9e90e8e
198 lines
6.8 KiB
Python
Executable File
198 lines
6.8 KiB
Python
Executable File
#! /usr/bin/env python
|
|
#
|
|
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
|
#
|
|
# 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 takes a list of projects from stdin in the format of
|
|
# aeromancer
|
|
# anvil
|
|
# blazar
|
|
#
|
|
# and renames stackforge/aeromancer, stackforge/anvil, and stackforge/blazar
|
|
# to openstack/aeromancer, openstack/anvil, and openstack/blazar respectively
|
|
# in
|
|
# gerrit/projects.yaml
|
|
# gerritbot/channels.yaml
|
|
# zuul/layout.yaml
|
|
# jenkins/jobs/*
|
|
# , as well as invoking a series of `git mv` and `git add` commands for
|
|
# renaming acl files and otherwise staging a single commit
|
|
|
|
import functools
|
|
import locale
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import yaml
|
|
from collections import OrderedDict
|
|
import projectconfig_yamllib as pcy
|
|
|
|
def build_list(prefix, renamelist):
|
|
return map(lambda x: "%s/%s" % (prefix, x), renamelist)
|
|
|
|
def load_yaml_data(filename):
|
|
data = yaml.load(open(filename)) # TODO raise error if open fails
|
|
return data
|
|
|
|
class ProjectData:
|
|
def __init__(self, data, gitmoves):
|
|
self.data = data
|
|
self.gitmoves = gitmoves
|
|
|
|
def build_project_data(stacklist, data):
|
|
gitmoves = {}
|
|
|
|
for project in data:
|
|
sproject = project['project']
|
|
oproject = sproject.replace('stackforge','openstack',1)
|
|
if sproject in stacklist:
|
|
project['project'] = oproject
|
|
try:
|
|
old = project['acl-config']
|
|
new = old.replace('stackforge','openstack',1)
|
|
project['acl-config'] = new
|
|
gitmoves[old.replace('/home/gerrit2','gerrit')] = new.replace('/home/gerrit2','gerrit')
|
|
except KeyError:
|
|
aclfile = "gerrit/acls/%s.config" % sproject
|
|
if os.path.isfile(aclfile):
|
|
gitmoves[aclfile] = aclfile.replace('stackforge','openstack',1)
|
|
|
|
# this is mildly disgusting
|
|
sorteddata = sorted(data, key=lambda t: locale.strxfrm(t['project'].lower().replace("_", "}")))
|
|
return ProjectData(sorteddata, gitmoves)
|
|
|
|
def rename_in_projects_yaml(stacklist, data):
|
|
|
|
errors = False # TODO add error checking
|
|
|
|
newdata = build_project_data(stacklist,data).data
|
|
|
|
with open('gerrit/projects.yaml', 'w') as out: # TODO raise error if open fails
|
|
out.write(yaml.dump(newdata, default_flow_style=False,
|
|
Dumper=pcy.IndentedDumper, width=80))
|
|
|
|
return True
|
|
|
|
def load_channel_data(filename):
|
|
data = yaml.load(open(filename)) # TODO raise error if open fails
|
|
return data
|
|
|
|
def build_channel_data(stacklist, data):
|
|
|
|
for k,v in data.items():
|
|
newprojects = []
|
|
for i in v['projects']:
|
|
if i in stacklist:
|
|
newprojects.append(i.replace('stackforge','openstack',1))
|
|
else:
|
|
newprojects.append(i)
|
|
|
|
v['projects'] = sorted(newprojects)
|
|
|
|
return data
|
|
|
|
def rename_in_channels_yaml(stacklist, ydata):
|
|
|
|
errors = False # TODO add error handling
|
|
|
|
data = build_channel_data(stacklist, ydata)
|
|
|
|
with open('gerritbot/channels.yaml', 'w') as out:
|
|
out.write('# This file is sorted alphabetically by channel name.\n')
|
|
first = True
|
|
for k, v in data.items():
|
|
if not first:
|
|
out.write('\n')
|
|
first = False
|
|
out.write(yaml.dump({k: v}, default_flow_style=False,
|
|
Dumper=pcy.IndentedDumper, width=80, indent=2))
|
|
|
|
return True
|
|
|
|
def rename_with_sed(zuullayout, targetfile, stacklist, openlist):
|
|
errors = False #TODO add error handling
|
|
|
|
h, fn = tempfile.mkstemp()
|
|
with os.fdopen(h, 'w') as out:
|
|
for f,t in zip(stacklist,openlist):
|
|
if zuullayout:
|
|
out.write("s#name: %s[[:space:]]*$#name: %s#;\n" % (f,t))
|
|
else:
|
|
out.write("s#%s\\([ /]\\)#%s\\1#;\n" % (f,t))
|
|
out.write("s#%s$#%s#;\n" % (f,t))
|
|
out.flush()
|
|
subprocess.call(['sed', '-f', fn, '-i', targetfile])
|
|
os.unlink(fn)
|
|
|
|
return True
|
|
|
|
filesToChange = {
|
|
'gerrit/projects.yaml' : { 'data': False,
|
|
'func': rename_in_projects_yaml
|
|
},
|
|
'gerritbot/channels.yaml': { 'data': False,
|
|
'func': rename_in_channels_yaml
|
|
},
|
|
'zuul/layout.yaml' : { 'data': False,
|
|
'func': functools.partial(rename_with_sed, True, 'zuul/layout.yaml')
|
|
}
|
|
}
|
|
|
|
def main():
|
|
locale.setlocale(locale.LC_COLLATE, 'C')
|
|
|
|
yaml.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
|
|
pcy.construct_yaml_map)
|
|
|
|
yaml.add_representer(OrderedDict, pcy.project_representer,
|
|
Dumper=pcy.IndentedDumper)
|
|
|
|
if os.isatty(0):
|
|
sys.stderr.write('You appear to be typing in the list of projects by hand rather than\n')
|
|
sys.stderr.write('using file redirection or a pipe. If this is your intent, send an\n')
|
|
sys.stderr.write('EOF by typing Ctrl-D on a blank line after the complete list has\n')
|
|
sys.stderr.write('been entered.\n\n')
|
|
renamelist = [x.rstrip('\n') for x in sys.stdin.readlines()]
|
|
stacklist = build_list('stackforge', renamelist)
|
|
openlist = build_list('openstack', renamelist)
|
|
pdata = build_project_data(stacklist, load_yaml_data('gerrit/projects.yaml'))
|
|
|
|
filesToChange['zuul/layout.yaml']['data'] = openlist
|
|
|
|
# because Python isn't lazy
|
|
filesToChange['gerrit/projects.yaml']['data'] = pdata.data
|
|
filesToChange['gerritbot/channels.yaml']['data'] = load_yaml_data('gerritbot/channels.yaml')
|
|
|
|
for f in filesToChange:
|
|
sys.stderr.write("working on %s\n" % f)
|
|
filesToChange[f]['func'](stacklist, filesToChange[f]['data'])
|
|
subprocess.call(['git', 'add', f])
|
|
sys.stderr.write("updated %s\n" % f)
|
|
|
|
for t in os.listdir('jenkins/jobs'):
|
|
f = os.path.join('jenkins/jobs', t)
|
|
sys.stderr.write("working on %s\n" % f)
|
|
rename_with_sed(False, f, stacklist, openlist)
|
|
subprocess.call(['git', 'add', f])
|
|
sys.stderr.write("updated %s\n" % f)
|
|
|
|
for s,o in pdata.gitmoves.items():
|
|
sys.stderr.write("renaming %s to %s\n" % (s, o))
|
|
subprocess.call(['git', 'mv', s, o])
|
|
|
|
if __name__ == '__main__':
|
|
main()
|