From 6726b6ddc71eec9da5abb7dd3b1ca770f5a0e057 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 19 Mar 2014 23:01:23 +0000 Subject: [PATCH] Automate more of the release registration steps. Copied from Perforce Change: 184892 ServerID: perforce.ravenbrook.com --- mps/procedure/release-build.rst | 8 +-- mps/tool/branch.py | 32 ++++++------ mps/tool/release.py | 92 +++++++++++++++++++++++++++------ 3 files changed, 95 insertions(+), 37 deletions(-) diff --git a/mps/procedure/release-build.rst b/mps/procedure/release-build.rst index ac52b0c371a..063be4c4773 100644 --- a/mps/procedure/release-build.rst +++ b/mps/procedure/release-build.rst @@ -183,10 +183,6 @@ On a Unix (including OS X) machine: p4 -c $CLIENT client -d $CLIENT rm -rf /tmp/$CLIENT - -7. Registering the release --------------------------- - #. Edit the index of releases (``release/index.html``) and add the release to the table, in a manner consistent with previous releases. @@ -201,6 +197,10 @@ On a Unix (including OS X) machine: p4 submit -d "MPS: registered release $RELEASE." + +7. Registering the release +-------------------------- + #. Visit the `project updater `__, select “mps” from the dropdown, and hit “Find releases”. diff --git a/mps/tool/branch.py b/mps/tool/branch.py index 10612cd3221..96472db3535 100755 --- a/mps/tool/branch.py +++ b/mps/tool/branch.py @@ -63,7 +63,7 @@ VERSION_BRANCH_ENTRY = ''' {description} - base
+ base
changelists @@ -80,9 +80,8 @@ def main(argv): help='Changelevel at which to make the branch.') parser.add_argument('-d', '--description', help='Description of the branch (for the branch spec).') - parser.add_argument('-y', '--commit', action='store_true', - help='Carry out the operation (by default, just ' - 'show a preview).') + parser.add_argument('-y', '--yes', action='store_true', + help='Yes, really make the branch.') group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-c', '--child', help='Name of the child branch.') @@ -92,6 +91,7 @@ def main(argv): help='Name of the task branch.') args = parser.parse_args(argv[1:]) args.depot = DEPOT + args.today = datetime.date.today().strftime('%Y-%m-%d') fmt = lambda s: s.format_map(vars(args)) if not args.project: @@ -133,8 +133,7 @@ def main(argv): if args.task: if not re.match(TASK_RE, args.task): raise Error(fmt("Invalid task: {task}")) - args.child = fmt(datetime.date.today() - .strftime('branch/%Y-%m-%d/{task}')) + args.child = fmt('branch/{today}/{task}') print(fmt("child={child}")) elif args.version: # Deduce version number from code/version.c. @@ -172,12 +171,12 @@ def main(argv): if any(p4.run('branches', '-E', args.branch)): print(fmt("Branch spec {branch} already exists: skipping.")) have_branch = True - elif args.commit: + elif args.yes: print(fmt("Creating branch spec {branch}.")) p4.run('branch', '-i').send(branch_spec).done() have_branch = True else: - print("-y/--commit not specified: skipping branch creation.") + print("--yes omitted: skipping branch creation.") # Populate the branch if any(p4.run('dirs', fmt('{depot}/project/{project}/{child}'))): @@ -188,15 +187,15 @@ def main(argv): '-b', args.branch, '-d', fmt("Branching {parent} to {child}."), '-s', srcs] - if args.commit: + if args.yes: print(fmt("Populating branch {branch}...")) populate_args.remove('-n') p4.do(*populate_args) elif have_branch: - print("-y/--commit not specified: dry-run (-n) only.") + print("--yes omitted: populate -n ...") p4.do(*populate_args) else: - print("-y/--commit not specified: skipping populate.") + print("--yes omitted: skipping populate.") # Determine the first change on the branch cmd = p4.run('changes', fmt('{depot}/project/{project}/{child}/...')) @@ -204,7 +203,7 @@ def main(argv): args.base = int(deque(cmd, maxlen=1).pop()['change']) print(fmt("base={base}")) except IndexError: - args.commit = False + args.yes = False args.base = args.changelevel print(fmt("Branch {child} not populated: using base={base}")) @@ -225,11 +224,10 @@ def main(argv): for result in conn.run('diff'): if 'data' in result: print(result['data']) - if args.commit: + if args.yes: conn.do('submit', '-d', fmt("Registering {child}."), filename) else: - print(fmt("-y/--commit not specified: skipping submit of\n" - " {filespec}.")) + print(fmt("--yes omitted: skipping submit of {filespec}")) # Task branches if not args.version: @@ -247,7 +245,7 @@ def main(argv): if any(p4.run('clients', '-E', args.git_client)): print(fmt("client {git_client} already exists: skipping.")) have_git_branch = True - elif args.commit: + elif args.yes: client_spec = dict( Client=args.git_client, Description=fmt("Git-fusion client for syncing {project} " @@ -260,7 +258,7 @@ def main(argv): p4.run('client', '-i').send(client_spec).done() have_git_branch = True else: - print("-y/--commit not specified: skipping git branch creation.") + print(fmt("--yes omitted: skipping {git_client}")) # Update table of pushes register('{depot}/infosys/robots/git-fusion/etc/pushes', diff --git a/mps/tool/release.py b/mps/tool/release.py index dec3ab78723..ec452281b35 100755 --- a/mps/tool/release.py +++ b/mps/tool/release.py @@ -20,6 +20,7 @@ from __future__ import unicode_literals import argparse from contextlib import contextmanager +import datetime import os import re import subprocess @@ -39,15 +40,34 @@ def pushdir(dir): yield os.chdir(cwd) -ROOT = '//info.ravenbrook.com/project' +DEPOT = '//info.ravenbrook.com' PROJECT_RE = r'[a-z][a-z0-9.-]*' -PROJECT_FILESPEC_RE = r'{}/({})/'.format(re.escape(ROOT), PROJECT_RE) +PROJECT_FILESPEC_RE = r'{}/project/({})/'.format(re.escape(DEPOT), PROJECT_RE) VERSION_RE = r'\d+\.\d+' CUSTOMER_RE = r'[a-z][a-z0-9.-]*' BRANCH_RE = (r'master|(?:custom/({})/)?(?:main|version/({}))' .format(CUSTOMER_RE, VERSION_RE)) BRANCH_FILESPEC_RE = r'{}({})(?:/|$)'.format(PROJECT_FILESPEC_RE, BRANCH_RE) +RELEASE_ENTRY = ''' + + + {release} + {today}
+ {branch}/...@{changelevel} + + {description} + + + Known
+ Fixed + + +''' + +VERSION_ENTRY = ''' {release} +''' + def main(argv): parser = argparse.ArgumentParser() parser.add_argument('-P', '--project', @@ -56,11 +76,13 @@ def main(argv): help='Name of the branch to make the release from.') parser.add_argument('-C', '--changelevel', type=int, help='Changelevel at which to make the release.') - parser.add_argument('-y', '--commit', action='store_true', - help='Carry out the operation (by default, just ' - 'show a preview).') + parser.add_argument('-d', '--description', + help='Description of the release.') + parser.add_argument('-y', '--yes', action='store_true', + help='Yes, really make the release.') args = parser.parse_args(argv[1:]) - args.root = ROOT + args.depot = DEPOT + args.today = datetime.date.today().strftime('%Y-%m-%d') fmt = lambda s: s.format_map(vars(args)) if not args.project: @@ -72,7 +94,7 @@ def main(argv): args.project = m.group(1) print(fmt("project={project}")) - if not any(p4.run('dirs', fmt('{root}/{project}'))): + if not any(p4.run('dirs', fmt('{depot}/project/{project}'))): raise Error(fmt("No such project: {project}")) if not args.branch: @@ -97,16 +119,17 @@ def main(argv): if args.version: print(fmt("version={version}")) - if not any(p4.run('dirs', fmt('{root}/{project}/{branch}'))): + args.origin = fmt('{depot}/project/{project}/{branch}') + if not any(p4.run('dirs', args.origin)): raise Error(fmt("No such branch: {branch}")) if not args.changelevel: - cmd = p4.run('changes', '-m', '1', fmt('{root}/{project}/{branch}/...')) + cmd = p4.run('changes', '-m', '1', fmt('{origin}/...')) args.changelevel = int(next(cmd)['change']) print(fmt("changelevel={changelevel}")) # Deduce release from code/version.c. - f = fmt('{root}/{project}/{branch}/code/version.c@{changelevel}') + f = fmt('{origin}/code/version.c@{changelevel}') m = re.search(r'^#define MPS_RELEASE "release/((\d+\.\d+)\.\d+)"$', p4.contents(f), re.M) if not m: @@ -116,15 +139,19 @@ def main(argv): if args.version and args.version != m.group(2): raise Error(fmt("Version {version} does not match release {release}")) if args.customer: - args.reldir = fmt('{root}/{project}/custom/{customer}/release/{release}') + args.reldir = fmt('{depot}/project/{project}/custom/{customer}/release/{release}') else: - args.reldir = fmt('{root}/{project}/release/{release}') + args.reldir = fmt('{depot}/project/{project}/release/{release}') + + if not args.description: + args.description = fmt("Release {release}.") + print(fmt("description={description}")) args.kit = fmt('mps-kit-{release}') client_spec = dict( - View0=fmt('{root}/{project}/{branch}/... //__CLIENT__/{kit}/...'), + View0=fmt('{origin}/... //__CLIENT__/{kit}/...'), View1=fmt('{reldir}/... //__CLIENT__/release/{release}/...')) - srcs = fmt('{root}/{project}/{branch}/...@{changelevel}') + srcs = fmt('{origin}/...@{changelevel}') for line_end, args.ext, cmd in (('local', 'tar.gz', ['tar', 'czf']), ('win', 'zip', ['zip', '-r'])): client_spec['LineEnd'] = line_end @@ -139,8 +166,8 @@ def main(argv): os.makedirs(fmt('release/{release}')) subprocess.check_call(cmd + [archive, args.kit], stdout=subprocess.DEVNULL) - if not args.commit: - print("-y/--commit not specified: skipping.") + if not args.yes: + print(fmt("--yes omitted: skipping submit of {kit}.{ext}")) else: conn.do('add', os.path.join(client_root, archive)) desc = fmt("Adding the MPS Kit {ext} archive for " @@ -149,6 +176,39 @@ def main(argv): else: print("{} already exists: skipping.".format(archive)) + def register(filespec, search, replace): + args.filespec = fmt(filespec) + if p4.contents(args.filespec).find(args.release) != -1: + print(fmt("{filespec} already updated: skipping.")) + return + client_spec = dict(View0=fmt('{filespec} //__CLIENT__/target')) + with p4.temp_client(client_spec) as (conn, client_root): + filename = os.path.join(client_root, 'target') + conn.do('sync', filename) + conn.do('edit', filename) + with open(filename, encoding='utf8') as f: + text = re.sub(search, fmt(replace), f.read(), 1) + with open(filename, 'w', encoding='utf8') as f: + f.write(text) + for result in conn.run('diff'): + if 'data' in result: + print(result['data']) + if args.yes: + conn.do('submit', '-d', fmt("Registering release {release}."), + filename) + else: + print(fmt("--yes omitted: skipping submit of {filespec}")) + + if not args.customer: + register('{depot}/project/{project}/release/index.html', + '(?<=\n)', RELEASE_ENTRY) + register('{depot}/project/{project}/version/index.html', + (r'(?<={0}\n \n)' + .format(re.escape(args.version), re.escape(args.project))), + VERSION_ENTRY) + register('{depot}/project/{project}/index.rst', + r'release/\d+\.\d+\.\d+', 'release/{release}') + if __name__ == '__main__': main(sys.argv)