1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
#!/usr/bin/env python
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
# Below are common methods for the devops build steps. This is the common location that will be updated with
# package targeting during release.
import sys
import os
from os import path
import re
import logging
from packaging.version import parse
from setup_parser import parse_setup
root_dir = path.abspath(path.join(path.abspath(__file__), "..", "..", ".."))
common_task_path = path.abspath(path.join(root_dir, "scripts", "devops_tasks"))
sys.path.append(common_task_path)
from common_tasks import process_glob_string, run_check_call
VERSION_PY = "_version.py"
# Auto generated code has version maintained in version.py.
# We need to handle this old file name until generated code creates _version.py for all packages
OLD_VERSION_PY = "version.py"
VERSION_REGEX = r'^VERSION\s*=\s*[\'"]([^\'"]*)[\'"]'
VERSION_STRING = 'VERSION = "%s"'
DEV_STATUS_REGEX = r'(classifiers=\[(\s)*)(["\']Development Status :: .*["\'])'
logging.getLogger().setLevel(logging.INFO)
def path_excluded(path):
return "-nspkg" in path or "tests" in path or "mgmt" in path or is_metapackage(path)
# Metapackages do not have an 'azure' folder within them
def is_metapackage(package_path):
dir_path = package_path if path.isdir(package_path) else path.split(package_path)[0]
azure_path = path.join(dir_path, 'azure')
return not path.exists(azure_path)
def get_setup_py_paths(glob_string, base_path):
setup_paths = process_glob_string(glob_string, base_path)
filtered_paths = [path.join(p, 'setup.py') for p in setup_paths if not path_excluded(p)]
return filtered_paths
def get_packages(args, package_name = ""):
# This function returns list of path to setup.py and setup info like install requires, version for all packages discovered using glob
# Followiong are the list of arguements expected and parsed by this method
# service, glob_string
if args.service:
target_dir = path.join(root_dir, "sdk", args.service)
else:
target_dir = root_dir
paths = get_setup_py_paths(args.glob_string, target_dir)
# Check if package is excluded if a package name param is passed
if package_name and not any(filter(lambda x: package_name == os.path.basename(os.path.dirname(x)), paths)):
logging.info("Package {} is excluded from version update tool".format(package_name))
exit(0)
packages = []
for setup_path in paths:
try:
setup_info = parse_setup(setup_path)
setup_entry = (setup_path, setup_info)
packages.append(setup_entry)
except:
print('Error parsing {}'.format(setup_path))
raise
return packages
def get_version_py(setup_py_location):
file_path, _ = path.split(setup_py_location)
# Find path to _version.py recursively in azure folder of package
azure_root_path = path.join(file_path, 'azure')
for root, _, files in os.walk(azure_root_path):
if(VERSION_PY in files):
return path.join(root, VERSION_PY)
elif (OLD_VERSION_PY in files):
return path.join(root, OLD_VERSION_PY)
def set_version_py(setup_py_location, new_version):
version_py_location = get_version_py(setup_py_location)
version_contents = ''
with open(version_py_location, 'r') as version_py_file:
version_contents = version_py_file.read()
with open(version_py_location, 'w') as version_py_file:
replaced_version_contents = re.sub(
VERSION_REGEX,
VERSION_STRING % new_version,
version_contents,
flags=re.MULTILINE)
version_py_file.write(replaced_version_contents)
# Get classification for PyPI (https://pypi.org/classifiers/)
def get_classification(version):
parsed_version = parse(version)
if not parsed_version.is_prerelease:
return 'Development Status :: 5 - Production/Stable'
else:
return 'Development Status :: 4 - Beta'
def set_dev_classifier(setup_py_location, version):
classification = get_classification(version)
setup_contents = ''
with open(setup_py_location, 'r+') as setup_py_file:
setup_contents = setup_py_file.read()
# Reset position and truncate the file for new contents
setup_py_file.seek(0)
setup_py_file.truncate()
replaced_setup_contents = re.sub(
DEV_STATUS_REGEX,
'\g<1>"{}"'.format(classification),
setup_contents
)
setup_py_file.write(replaced_setup_contents)
def update_change_log(setup_py_location, version, is_unreleased, replace_version):
script = os.path.join(root_dir, "eng", "common", "Update-Change-Log.ps1")
pkg_root = os.path.abspath(os.path.join(setup_py_location, ".."))
commands = [
"pwsh",
script,
"--Version",
version,
"--ChangeLogPath",
pkg_root,
"--Unreleased",
str(is_unreleased),
"--ReplaceVersion",
str(replace_version)
]
# Run script to update change log
run_check_call(commands, pkg_root)
|