Modified: subversion/branches/multi-wc-format/tools/dist/release.py URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/dist/release.py?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/dist/release.py (original) +++ subversion/branches/multi-wc-format/tools/dist/release.py Fri Jan 14 14:01:45 2022 @@ -41,7 +41,10 @@ import sys import glob import fnmatch import shutil -import urllib2 +try: + from urllib.request import urlopen # Python 3 +except: + from urllib2 import urlopen # Python 2 import hashlib import tarfile import logging @@ -52,6 +55,7 @@ import itertools import subprocess import argparse # standard in Python 2.7 import io +import yaml import backport.status @@ -67,62 +71,33 @@ except ImportError: sys.path.remove(ezt_path) +def get_dist_metadata_file_path(): + return os.path.join(os.path.abspath(sys.path[0]), 'release-lines.yaml') + +# Read the dist metadata (about release lines) +with open(get_dist_metadata_file_path(), 'r') as stream: + dist_metadata = yaml.safe_load(stream) + # Our required / recommended release tool versions by release branch -tool_versions = { - 'trunk' : { - 'autoconf' : ['2.69', - '954bd69b391edc12d6a4a51a2dd1476543da5c6bbf05a95b59dc0dd6fd4c2969'], - 'libtool' : ['2.4.6', - 'e3bd4d5d3d025a36c21dd6af7ea818a2afcd4dfc1ea5a17b39d7854bcd0c06e3'], - 'swig' : ['3.0.12', - '7cf9f447ae7ed1c51722efc45e7f14418d15d7a1e143ac9f09a668999f4fc94d'], - }, - '1.11' : { - 'autoconf' : ['2.69', - '954bd69b391edc12d6a4a51a2dd1476543da5c6bbf05a95b59dc0dd6fd4c2969'], - 'libtool' : ['2.4.6', - 'e3bd4d5d3d025a36c21dd6af7ea818a2afcd4dfc1ea5a17b39d7854bcd0c06e3'], - 'swig' : ['3.0.12', - '7cf9f447ae7ed1c51722efc45e7f14418d15d7a1e143ac9f09a668999f4fc94d'], - }, - '1.10' : { - 'autoconf' : ['2.69', - '954bd69b391edc12d6a4a51a2dd1476543da5c6bbf05a95b59dc0dd6fd4c2969'], - 'libtool' : ['2.4.6', - 'e3bd4d5d3d025a36c21dd6af7ea818a2afcd4dfc1ea5a17b39d7854bcd0c06e3'], - 'swig' : ['3.0.12', - '7cf9f447ae7ed1c51722efc45e7f14418d15d7a1e143ac9f09a668999f4fc94d'], - }, - '1.9' : { - 'autoconf' : ['2.69', - '954bd69b391edc12d6a4a51a2dd1476543da5c6bbf05a95b59dc0dd6fd4c2969'], - 'libtool' : ['2.4.6', - 'e3bd4d5d3d025a36c21dd6af7ea818a2afcd4dfc1ea5a17b39d7854bcd0c06e3'], - 'swig' : ['2.0.12', - '65e13f22a60cecd7279c59882ff8ebe1ffe34078e85c602821a541817a4317f7'], - }, - '1.8' : { - 'autoconf' : ['2.69', - '954bd69b391edc12d6a4a51a2dd1476543da5c6bbf05a95b59dc0dd6fd4c2969'], - 'libtool' : ['2.4.3', - '36b4881c1843d7585de9c66c4c3d9a067ed3a3f792bc670beba21f5a4960acdf'], - 'swig' : ['2.0.9', - '586954000d297fafd7e91d1ad31089cc7e249f658889d11a44605d3662569539'], - }, -} +tool_versions = dist_metadata['tool_versions'] # The version that is our current recommended release -# ### TODO: derive this from svn_version.h; see ../../build/getversion.py -recommended_release = '1.11' +recommended_release = dist_metadata['recommended_release'] # For clean-dist, a whitelist of artifacts to keep, by version. -supported_release_lines = frozenset({"1.9", "1.10", "1.11", "1.12"}) +supported_release_lines = frozenset(dist_metadata['supported_release_lines']) +# Long-Term Support (LTS) versions +lts_release_lines = frozenset(dist_metadata['lts_release_lines']) # Some constants -repos = 'https://svn.apache.org/repos/asf/subversion' -secure_repos = 'https://svn.apache.org/repos/asf/subversion' -dist_repos = 'https://dist.apache.org/repos/dist' +svn_repos = os.getenv('SVN_RELEASE_SVN_REPOS', + 'https://svn.apache.org/repos/asf/subversion') +dist_repos = os.getenv('SVN_RELEASE_DIST_REPOS', + 'https://dist.apache.org/repos/dist') dist_dev_url = dist_repos + '/dev/subversion' dist_release_url = dist_repos + '/release/subversion' +dist_archive_url = 'https://archive.apache.org/dist/subversion' +buildbot_repos = os.getenv('SVN_RELEASE_BUILDBOT_REPOS', + 'https://svn.apache.org/repos/infra/infrastructure/buildbot/aegis/buildmaster') KEYS = 'https://people.apache.org/keys/group/subversion.asc' extns = ['zip', 'tar.gz', 'tar.bz2'] @@ -167,18 +142,6 @@ class Version(object): def is_prerelease(self): return self.pre != None - def is_recommended(self): - return self.branch == recommended_release - - def get_download_anchor(self): - if self.is_prerelease(): - return 'pre-releases' - else: - if self.is_recommended(): - return 'recommended-release' - else: - return 'supported-releases' - def get_ver_tags(self, revnum): # These get substituted into svn_version.h ver_tag = '' @@ -196,7 +159,7 @@ class Version(object): ver_tag = '" (Nightly Build r%d)"' % revnum ver_numtag = '"-nightly-r%d"' % revnum else: - ver_tag = '" (r%d)"' % revnum + ver_tag = '" (r%d)"' % revnum ver_numtag = '""' return (ver_tag, ver_numtag) @@ -266,15 +229,21 @@ def get_exportdir(base_dir, version, rev return os.path.join(get_tempdir(base_dir), 'subversion-%s-r%d' % (version, revnum)) -def get_deploydir(base_dir): - return os.path.join(base_dir, 'deploy') - def get_target(args): "Return the location of the artifacts" if args.target: return args.target else: - return get_deploydir(args.base_dir) + return os.path.join(args.base_dir, 'deploy') + +def get_branch_path(args): + if not args.branch: + try: + args.branch = 'branches/%d.%d.x' % (args.version.major, args.version.minor) + except AttributeError: + raise RuntimeError("Please specify the branch using the release version label argument (for certain subcommands) or the '--branch' global option") + + return args.branch.rstrip('/') # canonicalize for later comparisons def get_tmpldir(): return os.path.join(os.path.abspath(sys.path[0]), 'templates') @@ -284,12 +253,14 @@ def get_tmplfile(filename): return open(os.path.join(get_tmpldir(), filename)) except IOError: # Hmm, we had a problem with the local version, let's try the repo - return urllib2.urlopen(repos + '/trunk/tools/dist/templates/' + filename) + return urlopen(svn_repos + '/trunk/tools/dist/templates/' + filename) def get_nullfile(): return open(os.path.devnull, 'w') -def run_script(verbose, script, hide_stderr=False): +def run_command(cmd, verbose=True, hide_stderr=False, dry_run=False): + if verbose: + print("+ " + ' '.join(cmd)) stderr = None if verbose: stdout = None @@ -298,23 +269,62 @@ def run_script(verbose, script, hide_std if hide_stderr: stderr = get_nullfile() + if not dry_run: + subprocess.check_call(cmd, stdout=stdout, stderr=stderr) + else: + print(' ## dry-run; not executed') + +def run_script(verbose, script, hide_stderr=False): for l in script.split('\n'): - subprocess.check_call(l.split(), stdout=stdout, stderr=stderr) + run_command(l.split(), verbose, hide_stderr) def download_file(url, target, checksum): - response = urllib2.urlopen(url) - target_file = open(target, 'w+') + """Download the file at URL to the local path TARGET. + If CHECKSUM is a string, verify the checksum of the downloaded + file and raise RuntimeError if it does not match. If CHECKSUM + is None, do not verify the downloaded file. + """ + assert checksum is None or isinstance(checksum, str) + + response = urlopen(url) + target_file = open(target, 'w+b') target_file.write(response.read()) target_file.seek(0) m = hashlib.sha256() m.update(target_file.read()) target_file.close() checksum2 = m.hexdigest() - if checksum != checksum2: + if checksum is not None and checksum != checksum2: raise RuntimeError("Checksum mismatch for '%s': "\ "downloaded: '%s'; expected: '%s'" % \ (target, checksum, checksum2)) +def run_svn(cmd, verbose=True, dry_run=False, username=None): + if (username): + cmd[:0] = ['--username', username] + run_command(['svn'] + cmd, verbose=verbose, dry_run=dry_run) + +def run_svnmucc(cmd, verbose=True, dry_run=False, username=None): + if (username): + cmd[:0] = ['--username', username] + run_command(['svnmucc'] + cmd, verbose=verbose, dry_run=dry_run) + +#---------------------------------------------------------------------- +def is_lts(version): + return version.branch in lts_release_lines + +def is_recommended(version): + return version.branch == recommended_release + +def get_download_anchor(version): + if version.is_prerelease(): + return 'pre-releases' + else: + if is_recommended(version): + return 'recommended-release' + else: + return 'supported-releases' + #---------------------------------------------------------------------- # ezt helpers @@ -338,7 +348,7 @@ def cleanup(args): shutil.rmtree(get_prefix(args.base_dir), True) shutil.rmtree(get_tempdir(args.base_dir), True) - shutil.rmtree(get_deploydir(args.base_dir), True) + shutil.rmtree(get_target(args), True) #---------------------------------------------------------------------- @@ -353,7 +363,8 @@ class RollDep(object): def _test_version(self, cmd): proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) + stderr=subprocess.STDOUT, + universal_newlines=True) (stdout, stderr) = proc.communicate() rc = proc.wait() if rc: return '' @@ -495,13 +506,236 @@ def build_env(args): #---------------------------------------------------------------------- +# Create a new minor release branch + +def get_trunk_wc_path(base_dir, path=None): + trunk_wc_path = os.path.join(get_tempdir(base_dir), 'svn-trunk') + if path is None: return trunk_wc_path + return os.path.join(trunk_wc_path, path) + +def get_buildbot_wc_path(base_dir, path=None): + buildbot_wc_path = os.path.join(get_tempdir(base_dir), 'svn-buildmaster') + if path is None: return buildbot_wc_path + return os.path.join(buildbot_wc_path, path) + +def get_trunk_url(revnum=None): + return svn_repos + '/trunk' + '@' + (str(revnum) if revnum else '') + +def get_branch_url(ver): + return svn_repos + '/branches/' + ver.branch + '.x' + +def get_tag_url(ver): + return svn_repos + '/tags/' + ver.base + +def edit_file(path, pattern, replacement): + print("Editing '%s'" % (path,)) + print(" pattern='%s'" % (pattern,)) + print(" replace='%s'" % (replacement,)) + old_text = open(path, 'r').read() + new_text = re.sub(pattern, replacement, old_text) + assert new_text != old_text + open(path, 'w').write(new_text) + +def edit_changes_file(path, newtext): + """Insert NEWTEXT in the 'CHANGES' file found at PATH, + just before the first line that starts with 'Version '. + """ + print("Prepending to '%s'" % (path,)) + print(" text='%s'" % (newtext,)) + lines = open(path, 'r').readlines() + for i, line in enumerate(lines): + if line.startswith('Version '): + with open(path, 'w') as newfile: + newfile.writelines(lines[:i]) + newfile.write(newtext) + newfile.writelines(lines[i:]) + break + +#---------------------------------------------------------------------- +def make_release_branch(args): + ver = args.version + run_svn(['copy', + get_trunk_url(args.revnum), + get_branch_url(ver), + '-m', 'Create the ' + ver.branch + '.x release branch.'], + dry_run=args.dry_run) + +#---------------------------------------------------------------------- +def update_minor_ver_in_trunk(args): + """Change the minor version in trunk to the next (future) minor version. + """ + ver = args.version + trunk_wc = get_trunk_wc_path(args.base_dir) + run_svn(['checkout', + get_trunk_url(args.revnum), + trunk_wc]) + + prev_ver = Version('1.%d.0' % (ver.minor - 1,)) + next_ver = Version('1.%d.0' % (ver.minor + 1,)) + relpaths = [] + + relpath = 'subversion/include/svn_version.h' + relpaths.append(relpath) + edit_file(get_trunk_wc_path(args.base_dir, relpath), + r'(#define SVN_VER_MINOR *)%s' % (ver.minor,), + r'\g<1>%s' % (next_ver.minor,)) + + relpath = 'subversion/tests/cmdline/svntest/main.py' + relpaths.append(relpath) + edit_file(get_trunk_wc_path(args.base_dir, relpath), + r'(SVN_VER_MINOR = )%s' % (ver.minor,), + r'\g<1>%s' % (next_ver.minor,)) + + relpath = 'subversion/bindings/javahl/src/org/apache/subversion/javahl/NativeResources.java' + relpaths.append(relpath) + try: + # since r1817921 (just after branching 1.10) + edit_file(get_trunk_wc_path(args.base_dir, relpath), + r'SVN_VER_MINOR = %s;' % (ver.minor,), + r'SVN_VER_MINOR = %s;' % (next_ver.minor,)) + except: + # before r1817921: two separate places + edit_file(get_trunk_wc_path(args.base_dir, relpath), + r'version.isAtLeast\(1, %s, 0\)' % (ver.minor,), + r'version.isAtLeast\(1, %s, 0\)' % (next_ver.minor,)) + edit_file(get_trunk_wc_path(args.base_dir, relpath), + r'1.%s.0, but' % (ver.minor,), + r'1.%s.0, but' % (next_ver.minor,)) + + relpath = 'CHANGES' + relpaths.append(relpath) + # insert at beginning of CHANGES file + edit_changes_file(get_trunk_wc_path(args.base_dir, relpath), + 'Version ' + next_ver.base + '\n' + + '(?? ??? 20XX, from /branches/' + next_ver.branch + '.x)\n' + + get_tag_url(next_ver) + '\n' + + '\n') + + log_msg = '''\ +Increment the trunk version number to %s, and introduce a new CHANGES +section, following the creation of the %s.x release branch. + +* subversion/include/svn_version.h, + subversion/bindings/javahl/src/org/apache/subversion/javahl/NativeResources.java, + subversion/tests/cmdline/svntest/main.py + (SVN_VER_MINOR): Increment to %s. + +* CHANGES: New section for %s.0. +''' % (next_ver.branch, ver.branch, next_ver.minor, next_ver.branch) + commit_paths = [get_trunk_wc_path(args.base_dir, p) for p in relpaths] + run_svn(['commit'] + commit_paths + ['-m', log_msg], + dry_run=args.dry_run) + +#---------------------------------------------------------------------- +def create_status_file_on_branch(args): + ver = args.version + branch_wc = get_workdir(args.base_dir) + branch_url = get_branch_url(ver) + run_svn(['checkout', branch_url, branch_wc, '--depth=immediates']) + + status_local_path = os.path.join(branch_wc, 'STATUS') + template_filename = 'STATUS.ezt' + data = { 'major-minor' : ver.branch, + 'major-minor-patch' : ver.base, + } + + template = ezt.Template(compress_whitespace=False) + template.parse(get_tmplfile(template_filename).read()) + + with open(status_local_path, 'wx') as g: + template.generate(g, data) + run_svn(['add', status_local_path]) + run_svn(['commit', status_local_path, + '-m', '* branches/' + ver.branch + '.x/STATUS: New file.'], + dry_run=args.dry_run) + +#---------------------------------------------------------------------- +def update_backport_bot(args): + ver = args.version + print("""\ + +*** MANUAL STEP REQUIRED *** + + Ask someone with appropriate access to add the %s.x branch + to the backport merge bot. See + http://subversion.apache.org/docs/community-guide/releasing.html#backport-merge-bot + +*** + +""" % (ver.branch,)) + +#---------------------------------------------------------------------- +def update_buildbot_config(args): + """Add the new branch to the list of branches monitored by the buildbot + master. + """ + ver = args.version + buildbot_wc = get_buildbot_wc_path(args.base_dir) + run_svn(['checkout', buildbot_repos, buildbot_wc]) + + prev_ver = Version('1.%d.0' % (ver.minor - 1,)) + next_ver = Version('1.%d.0' % (ver.minor + 1,)) + + relpath = 'master1/projects/subversion.conf' + edit_file(get_buildbot_wc_path(args.base_dir, relpath), + r'(MINOR_LINES=\[.*%s)(\])' % (prev_ver.minor,), + r'\1, %s\2' % (ver.minor,)) + + log_msg = '''\ +Subversion: start monitoring the %s branch. +''' % (ver.branch) + commit_paths = [get_buildbot_wc_path(args.base_dir, relpath)] + run_svn(['commit'] + commit_paths + ['-m', log_msg], + dry_run=args.dry_run) + +#---------------------------------------------------------------------- +def create_release_branch(args): + make_release_branch(args) + update_minor_ver_in_trunk(args) + create_status_file_on_branch(args) + update_backport_bot(args) + update_buildbot_config(args) + + +#---------------------------------------------------------------------- +def write_release_notes(args): + + # Create a skeleton release notes file from template + + template_filename = \ + 'release-notes-lts.ezt' if is_lts(args.version) else 'release-notes.ezt' + + prev_ver = Version('%d.%d.0' % (args.version.major, args.version.minor - 1)) + data = { 'major-minor' : args.version.branch, + 'previous-major-minor' : prev_ver.branch, + } + + template = ezt.Template(compress_whitespace=False) + template.parse(get_tmplfile(template_filename).read()) + + if args.edit_html_file: + with open(args.edit_html_file, 'w') as g: + template.generate(g, data) + else: + template.generate(sys.stdout, data) + + # Add an "in progress" entry in the release notes index + # + index_file = os.path.normpath(args.edit_html_file + '/../index.html') + marker = '<ul id="release-notes-list">\n' + new_item = '<li><a href="%s.html">Subversion %s</a> â <i>in progress</i></li>\n' % (args.version.branch, args.version.branch) + edit_file(index_file, + re.escape(marker), + (marker + new_item).replace('\\', r'\\')) + +#---------------------------------------------------------------------- # Create release artifacts def compare_changes(repos, branch, revision): mergeinfo_cmd = ['svn', 'mergeinfo', '--show-revs=eligible', repos + '/trunk/CHANGES', repos + '/' + branch + '/' + 'CHANGES'] - stdout = subprocess.check_output(mergeinfo_cmd) + stdout = subprocess.check_output(mergeinfo_cmd, universal_newlines=True) if stdout: # Treat this as a warning since we are now putting entries for future # minor releases in CHANGES on trunk. @@ -519,7 +753,7 @@ def check_copyright_year(repos, branch, file_url = (repos + '/' + branch + '/' + branch_relpath + '@' + str(revision)) cat_cmd = ['svn', 'cat', file_url] - stdout = subprocess.check_output(cat_cmd) + stdout = subprocess.check_output(cat_cmd, universal_newlines=True) m = _copyright_re.search(stdout) if m: year = m.group('year') @@ -544,16 +778,12 @@ def replace_lines(path, actions): def roll_tarballs(args): 'Create the release artifacts.' - if not args.branch: - args.branch = 'branches/%d.%d.x' % (args.version.major, args.version.minor) - - branch = args.branch # shorthand - branch = branch.rstrip('/') # canonicalize for later comparisons + branch = get_branch_path(args) logging.info('Rolling release %s from branch %s@%d' % (args.version, branch, args.revnum)) - check_copyright_year(repos, args.branch, args.revnum) + check_copyright_year(svn_repos, branch, args.revnum) # Ensure we've got the appropriate rolling dependencies available autoconf = AutoconfDep(args.base_dir, False, args.verbose, @@ -572,20 +802,21 @@ def roll_tarballs(args): if branch != 'trunk': # Make sure CHANGES is sync'd. - compare_changes(repos, branch, args.revnum) + compare_changes(svn_repos, branch, args.revnum) # Ensure the output directory doesn't already exist - if os.path.exists(get_deploydir(args.base_dir)): + if os.path.exists(get_target(args)): raise RuntimeError('output directory \'%s\' already exists' - % get_deploydir(args.base_dir)) + % get_target(args)) - os.mkdir(get_deploydir(args.base_dir)) + os.mkdir(get_target(args)) logging.info('Preparing working copy source') shutil.rmtree(get_workdir(args.base_dir), True) - run_script(args.verbose, 'svn checkout %s %s' - % (repos + '/' + branch + '@' + str(args.revnum), - get_workdir(args.base_dir))) + run_svn(['checkout', + svn_repos + '/' + branch + '@' + str(args.revnum), + get_workdir(args.base_dir)], + verbose=args.verbose) # Exclude stuff we don't want in the tarball, it will not be present # in the exported tree. @@ -596,8 +827,8 @@ def roll_tarballs(args): exclude += ['packages', 'www'] cwd = os.getcwd() os.chdir(get_workdir(args.base_dir)) - run_script(args.verbose, - 'svn update --set-depth exclude %s' % " ".join(exclude)) + run_svn(['update', '--set-depth=exclude'] + exclude, + verbose=args.verbose) os.chdir(cwd) if args.patches: @@ -607,10 +838,10 @@ def roll_tarballs(args): for name in os.listdir(args.patches): if name.find(majmin) != -1 and name.endswith('patch'): logging.info('Applying patch %s' % name) - run_script(args.verbose, - '''svn patch %s %s''' - % (os.path.join(args.patches, name), - get_workdir(args.base_dir))) + run_svn(['patch', + os.path.join(args.patches, name), + get_workdir(args.base_dir)], + verbose=args.verbose) # Massage the new version number into svn_version.h. ver_tag, ver_numtag = args.version.get_ver_tags(args.revnum) @@ -645,11 +876,12 @@ def roll_tarballs(args): def export(windows): shutil.rmtree(exportdir, True) if windows: - eol_style = "--native-eol CRLF" + eol_style = "--native-eol=CRLF" else: - eol_style = "--native-eol LF" - run_script(args.verbose, "svn export %s %s %s" - % (eol_style, get_workdir(args.base_dir), exportdir)) + eol_style = "--native-eol=LF" + run_svn(['export', + eol_style, get_workdir(args.base_dir), exportdir], + verbose=args.verbose) def transform_sql(): for root, dirs, files in os.walk(exportdir): @@ -700,7 +932,7 @@ def roll_tarballs(args): # Use the gzip -n flag - this prevents it from storing the # original name of the .tar file, and far more importantly, the # mtime of the .tar file, in the produced .tar.gz file. This is - # important, because it makes the gzip encoding reproducable by + # important, because it makes the gzip encoding reproducible by # anyone else who has an similar version of gzip, and also uses # "gzip -9n". This means that committers who want to GPG-sign both # the .tar.gz and the .tar.bz2 can download the .tar.bz2 (which is @@ -723,25 +955,33 @@ def roll_tarballs(args): for e in extns: filename = basename + '.' + e filepath = os.path.join(get_tempdir(args.base_dir), filename) - shutil.move(filepath, get_deploydir(args.base_dir)) - filepath = os.path.join(get_deploydir(args.base_dir), filename) + shutil.move(filepath, get_target(args)) + filepath = os.path.join(get_target(args), filename) if args.version < Version("1.11.0-alpha1"): # 1.10 and earlier generate *.sha1 files for compatibility reasons. # They are deprecated, however, so we don't publicly link them in # the announcements any more. m = hashlib.sha1() - m.update(open(filepath, 'r').read()) + m.update(open(filepath, 'rb').read()) open(filepath + '.sha1', 'w').write(m.hexdigest()) m = hashlib.sha512() - m.update(open(filepath, 'r').read()) + m.update(open(filepath, 'rb').read()) open(filepath + '.sha512', 'w').write(m.hexdigest()) # Nightlies do not get tagged so do not need the header if args.version.pre != 'nightly': shutil.copy(os.path.join(get_workdir(args.base_dir), 'subversion', 'include', 'svn_version.h'), - os.path.join(get_deploydir(args.base_dir), - 'svn_version.h.dist-%s' % str(args.version))) + os.path.join(get_target(args), + 'svn_version.h.dist-%s' + % (str(args.version),))) + + # Download and "tag" the KEYS file (in case a signing key is removed + # from a committer's LDAP profile down the road) + basename = 'subversion-%s.KEYS' % (str(args.version),) + filepath = os.path.join(get_tempdir(args.base_dir), basename) + download_file(KEYS, filepath, None) + shutil.move(filepath, get_target(args)) # And we're done! @@ -767,7 +1007,7 @@ def sign_candidates(args): for e in extns: filename = os.path.join(target, 'subversion-%s.%s' % (args.version, e)) sign_file(filename) - if args.version.major >= 1 and args.version.minor <= 6: + if args.version.major == 1 and args.version.minor <= 6: filename = os.path.join(target, 'subversion-deps-%s.%s' % (args.version, e)) sign_file(filename) @@ -783,14 +1023,12 @@ def post_candidates(args): logging.info('Importing tarballs to %s' % dist_dev_url) ver = str(args.version) - svn_cmd = ['svn', 'import', '-m', + svn_cmd = ['import', '-m', 'Add Subversion %s candidate release artifacts' % ver, '--auto-props', '--config-option', 'config:auto-props:*.asc=svn:eol-style=native;svn:mime-type=text/plain', target, dist_dev_url] - if (args.username): - svn_cmd += ['--username', args.username] - subprocess.check_call(svn_cmd) + run_svn(svn_cmd, verbose=args.verbose, username=args.username) #---------------------------------------------------------------------- # Create tag @@ -803,25 +1041,19 @@ def create_tag_only(args): logging.info('Creating tag for %s' % str(args.version)) - if not args.branch: - args.branch = 'branches/%d.%d.x' % (args.version.major, args.version.minor) + branch_url = svn_repos + '/' + get_branch_path(args) - branch = secure_repos + '/' + args.branch.rstrip('/') + tag = svn_repos + '/tags/' + str(args.version) - tag = secure_repos + '/tags/' + str(args.version) - - svnmucc_cmd = ['svnmucc', '-m', - 'Tagging release ' + str(args.version)] - if (args.username): - svnmucc_cmd += ['--username', args.username] - svnmucc_cmd += ['cp', str(args.revnum), branch, tag] + svnmucc_cmd = ['-m', 'Tagging release ' + str(args.version)] + svnmucc_cmd += ['cp', str(args.revnum), branch_url, tag] svnmucc_cmd += ['put', os.path.join(target, 'svn_version.h.dist' + '-' + str(args.version)), tag + '/subversion/include/svn_version.h'] # don't redirect stdout/stderr since svnmucc might ask for a password try: - subprocess.check_call(svnmucc_cmd) + run_svnmucc(svnmucc_cmd, verbose=args.verbose, username=args.username) except subprocess.CalledProcessError: if args.version.is_prerelease(): logging.error("Do you need to pass --branch=trunk?") @@ -832,10 +1064,7 @@ def bump_versions_on_branch(args): logging.info('Bumping version numbers on the branch') - if not args.branch: - args.branch = 'branches/%d.%d.x' % (args.version.major, args.version.minor) - - branch = secure_repos + '/' + args.branch.rstrip('/') + branch_url = svn_repos + '/' + get_branch_path(args) def replace_in_place(fd, startofline, flat, spare): """In file object FD, replace FLAT with SPARE in the first line @@ -863,11 +1092,12 @@ def bump_versions_on_branch(args): args.version.patch + 1)) HEAD = subprocess.check_output(['svn', 'info', '--show-item=revision', - '--', branch]).strip() + '--', branch_url], + universal_newlines=True).strip() HEAD = int(HEAD) def file_object_for(relpath): - fd = tempfile.NamedTemporaryFile() - url = branch + '/' + relpath + fd = tempfile.NamedTemporaryFile(mode='w+', encoding='UTF-8') + url = branch_url + '/' + relpath fd.url = url subprocess.check_call(['svn', 'cat', '%s@%d' % (url, HEAD)], stdout=fd) @@ -883,13 +1113,14 @@ def bump_versions_on_branch(args): svn_version_h.seek(0, os.SEEK_SET) STATUS.seek(0, os.SEEK_SET) - subprocess.check_call(['svnmucc', '-r', str(HEAD), - '-m', 'Post-release housekeeping: ' - 'bump the %s branch to %s.' - % (branch.split('/')[-1], str(new_version)), - 'put', svn_version_h.name, svn_version_h.url, - 'put', STATUS.name, STATUS.url, - ]) + run_svnmucc(['-r', str(HEAD), + '-m', 'Post-release housekeeping: ' + 'bump the %s branch to %s.' + % (branch_url.split('/')[-1], str(new_version)), + 'put', svn_version_h.name, svn_version_h.url, + 'put', STATUS.name, STATUS.url, + ], + verbose=args.verbose, username=args.username) del svn_version_h del STATUS @@ -909,7 +1140,8 @@ def clean_dist(args): '''Clean the distribution directory of release artifacts of no-longer-supported minor lines.''' - stdout = subprocess.check_output(['svn', 'list', dist_release_url]) + stdout = subprocess.check_output(['svn', 'list', dist_release_url], + universal_newlines=True) def minor(version): """Return the minor release line of the parameter, which must be @@ -917,7 +1149,7 @@ def clean_dist(args): return (version.major, version.minor) filenames = stdout.split('\n') - filenames = filter(lambda x: x.startswith('subversion-'), filenames) + filenames = [x for x in filenames if x.startswith('subversion-')] versions = set(map(Version, filenames)) to_keep = set() # TODO: When we release 1.A.0 GA we'll have to manually remove 1.(A-2).* artifacts. @@ -931,11 +1163,8 @@ def clean_dist(args): for i in sorted(to_keep): logging.info("Saving release '%s'", i) - svnmucc_cmd = ['svnmucc', '-m', 'Remove old Subversion releases.\n' + - 'They are still available at ' + - 'https://archive.apache.org/dist/subversion/'] - if (args.username): - svnmucc_cmd += ['--username', args.username] + svnmucc_cmd = ['-m', 'Remove old Subversion releases.\n' + + 'They are still available at ' + dist_archive_url] for filename in filenames: if Version(filename) not in to_keep: logging.info("Removing %r", filename) @@ -943,7 +1172,7 @@ def clean_dist(args): # don't redirect stdout/stderr since svnmucc might ask for a password if 'rm' in svnmucc_cmd: - subprocess.check_call(svnmucc_cmd) + run_svnmucc(svnmucc_cmd, verbose=args.verbose, username=args.username) else: logging.info("Nothing to remove") @@ -953,16 +1182,15 @@ def clean_dist(args): def move_to_dist(args): 'Move candidate artifacts to the distribution directory.' - stdout = subprocess.check_output(['svn', 'list', dist_dev_url]) + stdout = subprocess.check_output(['svn', 'list', dist_dev_url], + universal_newlines=True) filenames = [] for entry in stdout.split('\n'): if fnmatch.fnmatch(entry, 'subversion-%s.*' % str(args.version)): filenames.append(entry) - svnmucc_cmd = ['svnmucc', '-m', + svnmucc_cmd = ['-m', 'Publish Subversion-%s.' % str(args.version)] - if (args.username): - svnmucc_cmd += ['--username', args.username] svnmucc_cmd += ['rm', dist_dev_url + '/' + 'svn_version.h.dist' + '-' + str(args.version)] for filename in filenames: @@ -971,20 +1199,24 @@ def move_to_dist(args): # don't redirect stdout/stderr since svnmucc might ask for a password logging.info('Moving release artifacts to %s' % dist_release_url) - subprocess.check_call(svnmucc_cmd) + run_svnmucc(svnmucc_cmd, verbose=args.verbose, username=args.username) #---------------------------------------------------------------------- # Write announcements def write_news(args): 'Write text for the Subversion website.' - data = { 'date' : datetime.date.today().strftime('%Y%m%d'), - 'date_pres' : datetime.date.today().strftime('%Y-%m-%d'), + if args.news_release_date: + release_date = datetime.datetime.strptime(args.news_release_date, '%Y-%m-%d') + else: + release_date = datetime.date.today() + data = { 'date' : release_date.strftime('%Y%m%d'), + 'date_pres' : release_date.strftime('%Y-%m-%d'), 'major-minor' : args.version.branch, 'version' : str(args.version), 'version_base' : args.version.base, - 'anchor': args.version.get_download_anchor(), - 'is_recommended': ezt_bool(args.version.is_recommended()), + 'anchor': get_download_anchor(args.version), + 'is_recommended': ezt_bool(is_recommended(args.version)), 'announcement_url': args.announcement_url, } @@ -1018,7 +1250,7 @@ def get_fileinfo(args): target = get_target(args) - files = glob.glob(os.path.join(target, 'subversion*-%s*.asc' % args.version)) + files = glob.glob(os.path.join(target, 'subversion*-%s.*.asc' % args.version)) files.sort() class info(object): @@ -1044,7 +1276,7 @@ def write_announcement(args): 'siginfo' : "\n".join(siginfo) + "\n", 'major-minor' : args.version.branch, 'major-minor-patch' : args.version.base, - 'anchor' : args.version.get_download_anchor(), + 'anchor' : get_download_anchor(args.version), } if args.version.is_prerelease(): @@ -1109,14 +1341,12 @@ def get_siginfo(args, quiet=False): import security._gnupg as gnupg gpg = gnupg.GPG() - target = get_target(args) - good_sigs = {} fingerprints = {} output = [] - glob_pattern = os.path.join(target, 'subversion*-%s*.asc' % args.version) - for filename in glob.glob(glob_pattern): + for fileinfo in get_fileinfo(args): + filename = os.path.join(get_target(args), fileinfo.filename + '.asc') text = open(filename).read() keys = text.split(key_start) @@ -1141,9 +1371,9 @@ def get_siginfo(args, quiet=False): % (n, filename, key_end)) sys.exit(1) - fd, fn = tempfile.mkstemp() - os.write(fd, key_start + key) - os.close(fd) + fd, fn = tempfile.mkstemp(text=True) + with os.fdopen(fd, 'w') as key_file: + key_file.write(key_start + key) verified = gpg.verify_file(open(fn, 'rb'), filename[:-4]) os.unlink(fn) @@ -1165,6 +1395,7 @@ def get_siginfo(args, quiet=False): gpg_output = subprocess.check_output( ['gpg', '--fixed-list-mode', '--with-colons', '--fingerprint', id], stderr=subprocess.STDOUT, + universal_newlines=True, ) gpg_output = gpg_output.splitlines() @@ -1232,7 +1463,7 @@ def get_keys(args): 'Import the LDAP-based KEYS file to gpg' # We use a tempfile because urlopen() objects don't have a .fileno() with tempfile.SpooledTemporaryFile() as fd: - fd.write(urllib2.urlopen(KEYS).read()) + fd.write(urlopen(KEYS).read()) fd.flush() fd.seek(0) subprocess.check_call(['gpg', '--import'], stdin=fd) @@ -1244,18 +1475,18 @@ def add_to_changes_dict(changes_dict, au if section: section = section.lower() change = change.strip() - + if not audience in changes_dict: changes_dict[audience] = dict() if not section in changes_dict[audience]: changes_dict[audience][section] = dict() - + changes = changes_dict[audience][section] if change in changes: changes[change].add(revision) else: changes[change] = set([revision]) - + def print_section(changes_dict, audience, section, title, mandatory=False): if audience in changes_dict: audience_changes = changes_dict[audience] @@ -1292,7 +1523,7 @@ def write_changelog(args): # Putting [skip], [ignore], [c:skip] or [c:ignore] somewhere in the # log message means this commit must be ignored for Changelog processing # (ignored even with the --include-unlabeled-summaries option). - # + # # If there is no changes label anywhere in the commit message, and the # --include-unlabeled-summaries option is used, we'll consider the summary # line of the commit message (= first line except if it starts with a *) @@ -1307,13 +1538,14 @@ def write_changelog(args): # New svn_ra_list() API function [D:api] # [D:bindings] JavaHL: Allow access to constructors of a couple JavaHL classes - branch = secure_repos + '/' + args.branch - previous = secure_repos + '/' + args.previous + branch_url = svn_repos + '/' + get_branch_path(args) + previous = svn_repos + '/' + args.previous include_unlabeled = args.include_unlabeled separator_line = ('-' * 72) + '\n' - + mergeinfo = subprocess.check_output(['svn', 'mergeinfo', '--show-revs', - 'eligible', '--log', branch, previous]) + 'eligible', '--log', branch_url, previous], + universal_newlines=True) log_messages_dict = { # This is a dictionary mapping revision numbers to their respective # log messages. The expression in the "key:" part of the dict @@ -1324,7 +1556,7 @@ def write_changelog(args): for log_message in mergeinfo.split(separator_line)[1:-1] } mergeinfo = mergeinfo.splitlines() - + separator_pattern = re.compile('^-{72}$') revline_pattern = re.compile('^r(\d+) \| [^\|]+ \| [^\|]+ \| \d+ lines?$') changes_prefix_pattern = re.compile(r'^\[(U|D)?:?([^\]]+)?\](.+)$') @@ -1341,7 +1573,7 @@ def write_changelog(args): audience = None section = None message = None - + for line in mergeinfo: if separator_pattern.match(line): # New revision section. Reset variables. @@ -1358,7 +1590,7 @@ def write_changelog(args): # logic, in order to extract CHANGES_PREFIX_PATTERN # and CHANGES_SUFFIX_PATTERN lines from the trunk log # message. - + # 2. Parse the STATUS entry this_log_message = log_messages_dict[revision] status_paragraph = this_log_message.split('\n\n')[2] @@ -1399,7 +1631,7 @@ def write_changelog(args): if re.search(r'\[(c:)?(skip|ignore)\]', line, re.IGNORECASE): changes_ignore = True - + prefix_match = changes_prefix_pattern.match(line) if prefix_match: audience = prefix_match.group(1) @@ -1417,7 +1649,7 @@ def write_changelog(args): # Output the sorted changelog entries # 1) Uncategorized changes print_section(changes_dict, None, None, None) - print + print() # 2) User-visible changes print(' User-visible changes:') print_section(changes_dict, 'U', None, None) @@ -1429,7 +1661,7 @@ def write_changelog(args): print_section(changes_dict, 'U', 'clientserver', 'Client-side and server-side bugfixes') print_section(changes_dict, 'U', 'other', 'Other tool improvements and bugfixes') print_section(changes_dict, 'U', 'bindings', 'Bindings bugfixes', mandatory=True) - print + print() # 3) Developer-visible changes print(' Developer-visible changes:') print_section(changes_dict, 'D', None, None) @@ -1447,13 +1679,25 @@ def main(): parser = argparse.ArgumentParser( description='Create an Apache Subversion release.') parser.add_argument('--clean', action='store_true', default=False, - help='Remove any directories previously created by %(prog)s') + help='''Remove any directories previously created by %(prog)s, + including the 'prefix' dir, the 'temp' dir, and the + default or specified target dir.''') parser.add_argument('--verbose', action='store_true', default=False, help='Increase output verbosity') parser.add_argument('--base-dir', default=os.getcwd(), help='''The directory in which to create needed files and folders. The default is the current working directory.''') + parser.add_argument('--target', + help='''The full path to the directory containing + release artifacts. Default: <BASE_DIR>/deploy''') + parser.add_argument('--branch', + help='''The branch to base the release on, + as a path relative to ^/subversion/. + Default: 'branches/MAJOR.MINOR.x'.''') + parser.add_argument('--username', + help='Username for committing to ' + svn_repos + + ' or ' + dist_repos + '.') subparsers = parser.add_subparsers(title='subcommands') # Setup the parser for the build-env subcommand @@ -1471,6 +1715,40 @@ def main(): help='''Attempt to use existing build dependencies before downloading and building a private set.''') + # Setup the parser for the create-release-branch subcommand + subparser = subparsers.add_parser('create-release-branch', + help='''Create a minor release branch: branch from trunk, + update version numbers on trunk, create status + file on branch, update backport bot, + update buildbot config.''') + subparser.set_defaults(func=create_release_branch) + subparser.add_argument('version', type=Version, + help='''A version number to indicate the branch, such as + '1.7.0' (the '.0' is required).''') + subparser.add_argument('revnum', type=lambda arg: int(arg.lstrip('r')), + nargs='?', default=None, + help='''The trunk revision number to base the branch on. + Default is HEAD.''') + subparser.add_argument('--dry-run', action='store_true', default=False, + help='Avoid committing any changes to repositories.') + + # Setup the parser for the create-release-branch subcommand + subparser = subparsers.add_parser('write-release-notes', + help='''Write a template release-notes file.''') + subparser.set_defaults(func=write_release_notes) + subparser.add_argument('version', type=Version, + help='''A version number to indicate the branch, such as + '1.7.0' (the '.0' is required).''') + subparser.add_argument('revnum', type=lambda arg: int(arg.lstrip('r')), + nargs='?', default=None, + help='''The trunk revision number to base the branch on. + Default is HEAD.''') + subparser.add_argument('--edit-html-file', + help='''Write the template release-notes to this file, + and update 'index.html' in the same directory.''') + subparser.add_argument('--dry-run', action='store_true', default=False, + help='Avoid committing any changes to repositories.') + # Setup the parser for the roll subcommand subparser = subparsers.add_parser('roll', help='''Create the release artifacts.''') @@ -1479,9 +1757,6 @@ def main(): help='''The release label, such as '1.7.0-alpha1'.''') subparser.add_argument('revnum', type=lambda arg: int(arg.lstrip('r')), help='''The revision number to base the release on.''') - subparser.add_argument('--branch', - help='''The branch to base the release on, - relative to ^/subversion/.''') subparser.add_argument('--patches', help='''The path to the directory containing patches.''') @@ -1491,9 +1766,6 @@ def main(): subparser.set_defaults(func=sign_candidates) subparser.add_argument('version', type=Version, help='''The release label, such as '1.7.0-alpha1'.''') - subparser.add_argument('--target', - help='''The full path to the directory containing - release artifacts.''') subparser.add_argument('--userid', help='''The (optional) USER-ID specifying the key to be used for signing, such as '110B1C95' (Key-ID). If @@ -1506,11 +1778,6 @@ def main(): subparser.set_defaults(func=post_candidates) subparser.add_argument('version', type=Version, help='''The release label, such as '1.7.0-alpha1'.''') - subparser.add_argument('--username', - help='''Username for ''' + dist_repos + '''.''') - subparser.add_argument('--target', - help='''The full path to the directory containing - release artifacts.''') # Setup the parser for the create-tag subcommand subparser = subparsers.add_parser('create-tag', @@ -1521,14 +1788,6 @@ def main(): help='''The release label, such as '1.7.0-alpha1'.''') subparser.add_argument('revnum', type=lambda arg: int(arg.lstrip('r')), help='''The revision number to base the release on.''') - subparser.add_argument('--branch', - help='''The branch to base the release on, - relative to ^/subversion/.''') - subparser.add_argument('--username', - help='''Username for ''' + secure_repos + '''.''') - subparser.add_argument('--target', - help='''The full path to the directory containing - release artifacts.''') # Setup the parser for the bump-versions-on-branch subcommand subparser = subparsers.add_parser('bump-versions-on-branch', @@ -1538,14 +1797,6 @@ def main(): help='''The release label, such as '1.7.0-alpha1'.''') subparser.add_argument('revnum', type=lambda arg: int(arg.lstrip('r')), help='''The revision number to base the release on.''') - subparser.add_argument('--branch', - help='''The branch to base the release on, - relative to ^/subversion/.''') - subparser.add_argument('--username', - help='''Username for ''' + secure_repos + '''.''') - subparser.add_argument('--target', - help='''The full path to the directory containing - release artifacts.''') # The clean-dist subcommand subparser = subparsers.add_parser('clean-dist', @@ -1553,19 +1804,15 @@ def main(): subparser.set_defaults(func=clean_dist) subparser.add_argument('--dist-dir', help='''The directory to clean.''') - subparser.add_argument('--username', - help='''Username for ''' + dist_repos + '''.''') # The move-to-dist subcommand subparser = subparsers.add_parser('move-to-dist', - help='''Move candiates and signatures from the temporary + help='''Move candidates and signatures from the temporary release dev location to the permanent distribution directory.''') subparser.set_defaults(func=move_to_dist) subparser.add_argument('version', type=Version, help='''The release label, such as '1.7.0-alpha1'.''') - subparser.add_argument('--username', - help='''Username for ''' + dist_repos + '''.''') # The write-news subcommand subparser = subparsers.add_parser('write-news', @@ -1574,6 +1821,9 @@ def main(): subparser.set_defaults(func=write_news) subparser.add_argument('--announcement-url', help='''The URL to the archived announcement email.''') + subparser.add_argument('--news-release-date', + help='''The release date for the news, as YYYY-MM-DD. + Default: today.''') subparser.add_argument('--edit-html-file', help='''Insert the text into this file news.html, index.html).''') @@ -1588,9 +1838,6 @@ def main(): subparser.add_argument('--security', action='store_true', default=False, help='''The release being announced includes security fixes.''') - subparser.add_argument('--target', - help='''The full path to the directory containing - release artifacts.''') subparser.add_argument('version', type=Version, help='''The release label, such as '1.7.0-alpha1'.''') @@ -1599,9 +1846,6 @@ def main(): help='''Output to stdout template text for the download table for subversion.apache.org''') subparser.set_defaults(func=write_downloads) - subparser.add_argument('--target', - help='''The full path to the directory containing - release artifacts.''') subparser.add_argument('version', type=Version, help='''The release label, such as '1.7.0-alpha1'.''') @@ -1612,9 +1856,6 @@ def main(): subparser.set_defaults(func=check_sigs) subparser.add_argument('version', type=Version, help='''The release label, such as '1.7.0-alpha1'.''') - subparser.add_argument('--target', - help='''The full path to the directory containing - release artifacts.''') # get-keys subparser = subparsers.add_parser('get-keys', @@ -1633,12 +1874,8 @@ def main(): commit messages, optionally labeled with a category like [U:client], [D:api], [U], ...''') subparser.set_defaults(func=write_changelog) - subparser.add_argument('branch', - help='''The branch (or tag or trunk), relative to - ^/subversion/, of which to generate the - changelog, when compared to "previous".''') subparser.add_argument('previous', - help='''The "previous" branch or tag, relative to + help='''The "previous" branch or tag, relative to ^/subversion/, to compare "branch" against.''') subparser.add_argument('--include-unlabeled-summaries', dest='include_unlabeled', @@ -1649,7 +1886,7 @@ def main(): summary line contains 'STATUS', 'CHANGES', 'Post-release housekeeping', 'Follow-up' or starts with '*').''') - + # Parse the arguments args = parser.parse_args()
Modified: subversion/branches/multi-wc-format/tools/dist/security/_gnupg.py URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/dist/security/_gnupg.py?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/dist/security/_gnupg.py (original) +++ subversion/branches/multi-wc-format/tools/dist/security/_gnupg.py Fri Jan 14 14:01:45 2022 @@ -1,9 +1,9 @@ # Copyright (c) 2008-2014 by Vinay Sajip. # All rights reserved. -# +# # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: -# +# # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, Modified: subversion/branches/multi-wc-format/tools/dist/templates/download.ezt URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/dist/templates/download.ezt?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/dist/templates/download.ezt (original) +++ subversion/branches/multi-wc-format/tools/dist/templates/download.ezt Fri Jan 14 14:01:45 2022 @@ -4,12 +4,12 @@ <th>File</th> <th>Checksum (SHA512)</th> <th>Signatures</th> + <th>PGP Public Keys</th> </tr> [for fileinfo]<tr> <td><a href="[[]preferred]subversion/[fileinfo.filename]">[fileinfo.filename]</a></td> - <!-- The sha512 line does not have a class="checksum" since the link needn't - be rendered in monospace. --> <td>[<a href="https://www.apache.org/dist/subversion/[fileinfo.filename].sha512">SHA-512</a>]</td> - <td>[<a href="https://www.apache.org/dist/subversion/[fileinfo.filename].asc">PGP</a>]</td> + <td>[<a href="https://www.apache.org/dist/subversion/[fileinfo.filename].asc">PGP signatures</a>]</td> + <td>[<a href="https://www.apache.org/dist/subversion/subversion-[version].KEYS">PGP keyring</a>]</td> </tr>[end] </table> Modified: subversion/branches/multi-wc-format/tools/dist/templates/rc-news.ezt URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/dist/templates/rc-news.ezt?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/dist/templates/rc-news.ezt (original) +++ subversion/branches/multi-wc-format/tools/dist/templates/rc-news.ezt Fri Jan 14 14:01:45 2022 @@ -7,12 +7,16 @@ <p>We are pleased to announce the release of Apache Subversion [version]. This release is not intended for production use, but is provided as a milestone to encourage wider testing and feedback from intrepid users and maintainers. - Please see the + Please see the[if-any announcement_url][else] +<!-- Initially the release announcement link is commented out +until the release announcement has landed in the archives. +Add the URL below and remove this comment start section...|[end] <a href="[announcement_url]">release - announcement</a> for more information about this release, and the + announcement</a> for more information about this release, and the[if-any announcement_url][else] +|... and this end comment--->[end] <a href="/docs/release-notes/[major-minor].html">release notes</a> and - <a href="https://svn.apache.org/repos/asf/subversion/tags/[version]/CHANGES"> - change log</a> for information about what will eventually be + <a href="https://svn.apache.org/repos/asf/subversion/tags/[version]/CHANGES" + >change log</a> for information about what will eventually be in the [version_base] release.</p> <p>To get this release from the nearest mirror, please visit our Modified: subversion/branches/multi-wc-format/tools/dist/templates/rc-release-ann.ezt URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/dist/templates/rc-release-ann.ezt?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/dist/templates/rc-release-ann.ezt (original) +++ subversion/branches/multi-wc-format/tools/dist/templates/rc-release-ann.ezt Fri Jan 14 14:01:45 2022 @@ -1,5 +1,6 @@ From: [email protected] -To: [email protected], [email protected], [email protected], [email protected] +To: [email protected], [email protected], [email protected] +Reply-To: [email protected] Subject: [[]ANNOUNCE] Apache Subversion [version] released I'm happy to announce the release of Apache Subversion [version]. @@ -22,6 +23,10 @@ PGP Signatures are available at: For this release, the following people have provided PGP signatures: [siginfo] +These public keys are available at: + + https://www.apache.org/dist/subversion/subversion-[version].KEYS + This is a pre-release for what will eventually become version [major-minor-patch] of the Apache Subversion open source version control system. It may contain known issues, a complete list of [major-minor-patch]-blocking issues can be found Modified: subversion/branches/multi-wc-format/tools/dist/templates/stable-news.ezt URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/dist/templates/stable-news.ezt?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/dist/templates/stable-news.ezt (original) +++ subversion/branches/multi-wc-format/tools/dist/templates/stable-news.ezt Fri Jan 14 14:01:45 2022 @@ -9,9 +9,13 @@ users of Subversion to upgrade as soon as reasonable. [else] This is the most complete release of the [major-minor].x line to date, and we encourage all users to upgrade as soon as reasonable. -[end] Please see the +[end] Please see the[if-any announcement_url][else] +<!-- Initially the release announcement link is commented out +until the release announcement has landed in the archives. +Add the URL below and remove this comment start section...|[end] <a href="[announcement_url]" - >release announcement</a> and the + >release announcement</a> and the[if-any announcement_url][else] +|... and this end comment -->[end] <a href="/docs/release-notes/[major-minor]" >release notes</a> for more information about this release.</p> Modified: subversion/branches/multi-wc-format/tools/dist/templates/stable-release-ann.ezt URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/dist/templates/stable-release-ann.ezt?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/dist/templates/stable-release-ann.ezt (original) +++ subversion/branches/multi-wc-format/tools/dist/templates/stable-release-ann.ezt Fri Jan 14 14:01:45 2022 @@ -1,5 +1,6 @@ From: [email protected] -To: [email protected], [email protected], [email protected], [email protected] +To: [email protected], [email protected], [email protected] +Reply-To: [email protected] [if-any security]Cc: [email protected], [email protected], [email protected] [end][if-any security]Subject: [[]SECURITY][[]ANNOUNCE] Apache Subversion [version] released [else]Subject: [[]ANNOUNCE] Apache Subversion [version] released @@ -33,6 +34,10 @@ PGP Signatures are available at: For this release, the following people have provided PGP signatures: [siginfo] +These public keys are available at: + + https://www.apache.org/dist/subversion/subversion-[version].KEYS + Release notes for the [major-minor].x release series may be found at: https://subversion.apache.org/docs/release-notes/[major-minor].html Modified: subversion/branches/multi-wc-format/tools/examples/get-location-segments.py URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/examples/get-location-segments.py?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/examples/get-location-segments.py (original) +++ subversion/branches/multi-wc-format/tools/examples/get-location-segments.py Fri Jan 14 14:01:45 2022 @@ -73,7 +73,7 @@ def parse_args(args): def prompt_func_ssl_unknown_cert(realm, failures, cert_info, may_save, pool): - print( "The certficate details are as follows:") + print( "The certificate details are as follows:") print("--------------------------------------") print("Issuer : " + str(cert_info.issuer_dname)) print("Hostname : " + str(cert_info.hostname)) Modified: subversion/branches/multi-wc-format/tools/examples/walk-config-auth.py URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/examples/walk-config-auth.py?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/examples/walk-config-auth.py (original) +++ subversion/branches/multi-wc-format/tools/examples/walk-config-auth.py Fri Jan 14 14:01:45 2022 @@ -18,7 +18,7 @@ credentials found. """ % (sys.argv[0])) sys.exit(0) -config_dir = svn.core.svn_config_get_user_config_path(None, '') +config_dir = svn.core.svn_config_get_user_config_path(None, None) if len(sys.argv) > 1: config_dir = sys.argv[1] Modified: subversion/branches/multi-wc-format/tools/hook-scripts/mailer/mailer.conf.example URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/tools/hook-scripts/mailer/mailer.conf.example?rev=1897034&r1=1897033&r2=1897034&view=diff ============================================================================== --- subversion/branches/multi-wc-format/tools/hook-scripts/mailer/mailer.conf.example (original) +++ subversion/branches/multi-wc-format/tools/hook-scripts/mailer/mailer.conf.example Fri Jan 14 14:01:45 2022 @@ -23,6 +23,11 @@ # This option specifies the hostname for delivery via SMTP. #smtp_hostname = localhost +# This option specifies the TCP port number to connect for SMTP. +# If it is not specified, 25 is used for SMTP and 465 is used for +# SMTP-Over-SSL by default. +#smtp_port = 25 + # Username and password for SMTP servers requiring authorisation. #smtp_username = example #smtp_password = example
