build/buildrelease-repo.py
Rama master · réplica de lectura del repositorio original.
#!/usr/bin/python3 -u
import getopt
import re
import os
from os import path
import shutil
import subprocess
import sys
import tempfile
# clone URL for MantisBT repository
clone_url = 'https://github.com/mantisbt/mantisbt.git'
build_script_name = 'buildrelease.py'
# List of refs to ignore (regular expressions)
# - HEAD (generally the same as master)
# - dependabot branches
# - 1.x refs
ignorelist = [
r'^origin\/HEAD$',
r'-1\.[\d]+\.[\w\d]+',
r'^origin\/dependabot\/',
]
# Script options
options = "hfr:bacds:"
long_options = ["help", "fresh", "ref=", "branches", "auto-suffix", "clean",
"docbook", "suffix="]
def usage():
print(f'''Builds one or more releases (zip/tarball) for the specified
references or for all branches.
Usage: {path.basename(__file__)} [options] /path/for/tarballs [/path/to/repo]
Options:
-h | --help Show this usage message
-f | --fresh Create a fresh clone in repository path,
or temporary path
-r | --ref <ref>[,<ref>...] Build a release for named refs <ref>
-b | --branches Build a release for all branches
-a | --auto-suffix Automatically append the HEAD commit's sha1
to the version suffix
The following options are passed on to '{build_script_name}':
-c | --clean Remove build directories when completed
-d | --docbook Build the docbook manuals
-s | --suffix <suffix> Include version suffix in config files
''')
# end usage()
def get_head_commit_sha():
result = subprocess.run(['git', 'log', '--pretty=format:%h', '-n1'],
check=True, text=True, capture_output=True)
return result.stdout
def ignore(ref):
"""
Decide which refs to ignore based on regexen listed in 'ignorelist'.
"""
for regex in [re.compile(r) for r in ignorelist]:
if len(regex.findall(ref)) > 0:
return True
return False
# end ignore()
def main():
try:
opts, args = getopt.gnu_getopt(sys.argv[1:], options, long_options)
except getopt.GetoptError as err:
print(err)
usage()
sys.exit(2)
pass_opts = []
refs = []
all_branches = False
version_suffix = ""
auto_suffix = False
fresh_clone = False
delete_clone = False
# noinspection PyUnboundLocalVariable
for opt, val in opts:
if opt in ("-h", "--help"):
usage()
sys.exit(0)
elif opt in ("-f", "--fresh"):
fresh_clone = True
elif opt in ("-r", "--ref"):
refs.extend(val.split(","))
elif opt in ("-b", "--branches"):
all_branches = True
elif opt in ("-c", "--clean"):
pass_opts.append("-c")
elif opt in ("-d", "--docbook"):
pass_opts.append("-d")
elif opt in ("-a", "--auto-suffix"):
auto_suffix = True
elif opt in ("-s", "--suffix"):
version_suffix = val
# noinspection PyUnboundLocalVariable
if len(args) < 1:
usage()
sys.exit(1)
release_path = path.abspath(args[0])
repo_path = "."
if len(args) > 1:
repo_path = path.abspath(args[1])
# Create a new repo clone
if fresh_clone:
print("Origin MantisBT repository:", clone_url)
if repo_path == ".":
if not path.isdir(release_path):
print("Creating release path...")
os.mkdir(release_path)
repo_path = tempfile.mkdtemp(dir=release_path, prefix="mantisbt-", suffix=".git")
delete_clone = True
try:
subprocess.run(['git', 'clone', clone_url, repo_path], check=True)
except subprocess.CalledProcessError:
print("ERROR: clone failed")
sys.exit(1)
# Change to the repo path
script_dir = path.dirname(path.abspath(__file__))
os.chdir(repo_path)
# Update the repository
if not fresh_clone:
print(f"Updating repository at '{repo_path}'")
subprocess.run(['git', 'fetch'], check=True)
# Consolidate refs/branches
if all_branches:
subprocess.run(['git', 'remote', 'prune', 'origin'], check=True)
result = subprocess.run(['git', 'for-each-ref', '--format=%(refname:short)', 'refs/remotes'],
check=True, text=True, capture_output=True)
refs.extend(result.stdout.split())
if not refs:
refs.append(get_head_commit_sha())
refs = [ref for ref in refs if not ignore(ref)]
# Info
print("\nWill build the following releases:")
for ref in refs:
print(" " + ref)
# Regex to strip 'origin/' from ref names
refnameregex = re.compile('(?:[a-zA-Z0-9-.]+/)?(.*)')
for ref in refs:
print(f"\nChecking out '{ref}'")
subprocess.run(['git', 'checkout', '-f', '-q', ref], check=True)
subprocess.run(['git', 'log', '-n1', '--pretty="HEAD is now at %h... %s"'],
check=True)
print()
# Composer
if path.isfile('composer.json'):
print("Installing Composer packages")
composer = ['composer', 'install', '--no-plugins', '--no-scripts', '--no-dev', '--no-progress']
try:
subprocess.run(composer, check=True)
except subprocess.CalledProcessError as e:
print("ERROR:", e)
sys.exit(1)
print()
# Update and reset submodules
print("Updating submodules")
subprocess.run(['git', 'submodule', 'update', '--init'], check=True)
subprocess.run(['git', 'submodule', 'foreach', 'git', 'checkout', '--', '.'], check=True)
# Handle suffix/auto-suffix generation
commit_hash = get_head_commit_sha()
if commit_hash != ref:
ref = refnameregex.search(ref).group(1)
commit_hash = f"{ref}-{commit_hash}"
if auto_suffix and version_suffix:
suffix = [f"--suffix={version_suffix}-{commit_hash}"]
elif auto_suffix:
suffix = ["--suffix=" + commit_hash]
elif version_suffix:
suffix = ["--suffix=" + version_suffix]
else:
suffix = []
# Absolute path to buildrelease.py in the target repository, with a
# fallback to the directory of the currently executing script
buildscript = path.join(repo_path, 'build', build_script_name)
if not path.exists(buildscript):
buildscript = path.join(script_dir, build_script_name)
print(f"Build script ({build_script_name}) not found in {ref}")
print(f"Using '{buildscript}' instead.")
# Start building
try:
cmd = [buildscript] + pass_opts + suffix + [release_path, repo_path]
print("Running:", " ".join(cmd))
subprocess.run(cmd, check=True)
except subprocess.CalledProcessError as e:
print(e)
sys.exit(1)
# Cleanup temporary repo if needed
if delete_clone:
print("\nRemoving temporary clone.")
shutil.rmtree(repo_path)
# Done
print("\nAll builds completed.")
# end main()
if __name__ == "__main__":
main()