Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

increase and verify version functions #6980

Merged
merged 3 commits into from
Dec 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 132 additions & 7 deletions eng/versioning/set_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@
#
# python utilities/set_versions.py --ut [library|external_dependency|all] --bt [client|data|management] --bq <BuildQualifierString> --ar <artifactId>
#
# Use case: increment the version of a given artifact in the approprate version_[client|data|management].txt file
#
# python eng/versioning/set_versions.py --bt [client|data|management] --increment-version --artifact-id <artifactId>
# For example: To update increment the version of azure-core
# python eng/versioning/update_versions.py --bt client --iv -ar azure-core
#
# Use case: verify the version of a given artifact in the approprate version_[client|data|management].txt file
#
# python eng/versioning/set_versions.py --bt [client|data|management] --verify-version --artifact-id <artifactId>
# For example: To update increment the version of azure-core
# python eng/versioning/update_versions.py --bt client --vv -ar azure-core
#
# The script must be run at the root of azure-sdk-for-java.

import argparse
Expand All @@ -27,12 +39,14 @@
from utils import BuildType
from utils import CodeModule
from utils import UpdateType
from utils import version_regex_str_with_anchor
from utils import version_regex_str_with_names_anchored
from utils import prerelease_version_regex_with_name

# The regex string we want should be the anchored one since the entire string is what's being matched
version_regex = re.compile(version_regex_str_with_anchor)
version_regex_named = re.compile(version_regex_str_with_names_anchored)
prerelease_regex_named = re.compile(prerelease_version_regex_with_name)

def update_versions_file(update_type, build_type, build_qualifier, artifact_id):
def update_versions_file_for_nightly_devops(update_type, build_type, build_qualifier, artifact_id):

version_file = os.path.normpath('eng/versioning/version_' + build_type.name + '.txt')
print('version_file=' + version_file)
Expand All @@ -51,15 +65,15 @@ def update_versions_file(update_type, build_type, build_qualifier, artifact_id):
module.current += "." + build_qualifier
else:
module.current += '-' + build_qualifier
match = version_regex.match(module.current)
match = version_regex_named.match(module.current)
if not match:
raise ValueError('{}\'s current version + build qualifier {} is not a valid semver version'.format(module.name, module.current + build_qualifier))
if update_type == UpdateType.external_dependency or update_type == UpdateType.all:
if '-' in module.dependency:
module.dependency += "." + build_qualifier
else:
module.dependency += '-' + build_qualifier
match = version_regex.match(module.dependency)
match = version_regex_named.match(module.dependency)
if not match:
raise ValueError('{}\'s dependency version + build qualifier {} is not a valid semver version'.format(module.name, module.dependency + build_qualifier))
newlines.append(module.string_for_version_file())
Expand Down Expand Up @@ -93,23 +107,134 @@ def prep_version_file_for_source_testing(build_type):
f.write(line)

return file_changed


# given a build type and artifact id
def increment_version_for_artifact(build_type, artifact_id):

if not build_type:
raise ValueError('build_type cannot be empty.')

if not artifact_id:
raise ValueError('artifact_id cannot be empty.')

version_file = os.path.normpath('eng/versioning/version_' + build_type.name + '.txt')
print('version_file=' + version_file)

artifact_found = False
newlines = []
with open(version_file, encoding='utf-8') as f:
for raw_line in f:
stripped_line = raw_line.strip()
if not stripped_line or stripped_line.startswith('#'):
newlines.append(raw_line)
else:
module = CodeModule(stripped_line)
# Tick up the version here. If the version is already a pre-release
# version then just increment the revision. Otherwise increment the
# minor version, zero the patch and add "-beta.1" to the end
# https://github.com/Azure/azure-sdk/blob/master/docs/policies/releases.md#java
if module.artifact_id == artifact_id:
artifact_found = True
vmatch = version_regex_named.match(module.current)
if (vmatch.group('prerelease') is not None):
prever = prerelease_regex_named.match(vmatch.group('prerelease'))
rev = int(prever.group('revision'))
rev += 1
new_version = '{}.{}.{}-beta.{}'.format(vmatch.group('major'), vmatch.group('minor'), vmatch.group('patch'), str(rev))
else:
minor = int(vmatch.group('minor'))
minor += 1
new_version = '{}.{}.{}-beta.1'.format(vmatch.group('major'), minor, 0)
print('artifact_id {}, previous version={}, new current version={}'.format(artifact_id, module.current, new_version))
module.current = new_version
newlines.append(module.string_for_version_file())

if not artifact_found:
raise ValueError('artifact_id ({}) was not found in version file {}'.format(artifact_id, version_file))

with open(version_file, 'w', encoding='utf-8') as f:
for line in newlines:
f.write(line)

# Verify that the current version of an artifact matches our versioning scheme. This is meant to be called
# as part of the release pipeline for a given artifact to verify that we don't accidentally release a version
# that doesn't match our versioning scheme
def verify_current_version_of_artifact(build_type, artifact_id):
if not build_type:
raise ValueError('build_type cannot be empty.')

if not artifact_id:
raise ValueError('artifact_id cannot be empty.')

version_file = os.path.normpath('eng/versioning/version_' + build_type.name + '.txt')
print('version_file=' + version_file)

artifact_found = False
with open(version_file, encoding='utf-8') as f:
for raw_line in f:
stripped_line = raw_line.strip()
if not stripped_line or stripped_line.startswith('#'):
continue
else:
module = CodeModule(stripped_line)
# verify the current version of the artifact matches our version schema which is one
# of the following:
# <major>.<minor>.<patch/hotfix>
# <major>.<minor>.<patch/hotfix>-beta.<prerelease>
if module.artifact_id == artifact_id:
artifact_found = True
vmatch = version_regex_named.match(module.current)
temp_ver = '{}.{}.{}'.format(vmatch.group('major'), vmatch.group('minor'), vmatch.group('patch'))
# we should never have buildmetadata in our versioning scheme
if vmatch.group('buildmetadata') is not None:
raise ValueError('artifact ({}) version ({}) in version file ({}) is not a correct version to release. buildmetadata is set and should never be {}'.format(artifact_id, module.current, version_file, vmatch.group('buildmetadata')))

# reconstruct the version from the semver pieces and it should match exactly the current
# version in the module
# If there's a pre-release version it should be beta.X
if vmatch.group('prerelease') is not None:
prerel = vmatch.group('prerelease')

if prerelease_regex_named.match(prerel) is None:
raise ValueError('artifact ({}) version ({}) in version file ({}) is not a correct version to release. The accepted prerelease tag is (beta.X) and the current prerelease tag is ({})'.format(artifact_id, module.current, version_file, prerel))

prever = prerelease_regex_named.match(prerel)
rev = int(prever.group('revision'))
temp_ver = '{}-beta.{}'.format(temp_ver, str(rev))

# last but not least, for sanity verify that the version constructed from the
# semver pieces matches module's current version
if module.current != temp_ver:
raise ValueError('artifact ({}) version ({}) in version file ({}) does not match the version constructed from the semver pieces ({})'.format(artifact_id, module.current, version_file, temp_ver))

print('The version {} for artifact_id {} looks good!'.format(module.name, module.current))


if not artifact_found:
raise ValueError('artifact_id ({}) was not found in version file {}'.format(artifact_id, version_file))

def main():
parser = argparse.ArgumentParser(description='set version numbers in the appropriate version text file')
parser.add_argument('--update-type', '--ut', type=UpdateType, choices=list(UpdateType))
parser.add_argument('--build-type', '--bt', type=BuildType, choices=list(BuildType))
parser.add_argument('--build-qualifier', '--bq', help='build qualifier to append onto the version string.')
parser.add_argument('--artifact-id', '--ar', help='artifactId to target.')
parser.add_argument('--prep-source-testing', '--pst', action='store_true', help='prep the version file for source testing')
parser.add_argument('--increment-version', '--iv', action='store_true', help='increment the version for a given artifact')
parser.add_argument('--verify-version', '--vv', action='store_true', help='verify the version for a given artifact')
args = parser.parse_args()
if (args.build_type == BuildType.management):
raise ValueError('{} is not currently supported.'.format(BuildType.management.name))
start_time = time.time()
file_changed = False
if (args.prep_source_testing):
file_changed = prep_version_file_for_source_testing(args.build_type)
elif (args.increment_version):
increment_version_for_artifact(args.build_type, args.artifact_id)
elif (args.verify_version):
verify_current_version_of_artifact(args.build_type, args.artifact_id)
else:
update_versions_file(args.update_type, args.build_type, args.build_qualifier, args.artifact_id)
update_versions_file_for_nightly_devops(args.update_type, args.build_type, args.build_qualifier, args.artifact_id)
elapsed_time = time.time() - start_time
print('elapsed_time={}'.format(elapsed_time))
print('Total time for replacement: {}'.format(str(timedelta(seconds=elapsed_time))))
Expand Down
5 changes: 4 additions & 1 deletion eng/versioning/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
# This is the regex that would be used to ensure the entire string matches
# semver format
# https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
version_regex_str_with_anchor = r'^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'
version_regex_str_with_names_anchored = r'^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably worth just having the one regex with the named anchored instead of both.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the non-named one. Will be updated with next commit.


# This is specific to our revision which, if there is one, needs to have the format of beta.X
prerelease_version_regex_with_name = r'^beta\.(?P<revision>0|[1-9]\d*)$'

class UpdateType(Enum):
external_dependency = 'external_dependency'
Expand Down
3 changes: 2 additions & 1 deletion eng/versioning/version_client.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ com.azure:azure-storage-file-datalake;12.0.0-beta.7;12.0.0-beta.8
com.azure:azure-storage-queue;12.1.0;12.2.0-beta.1
com.azure:azure-e2e;1.0.0-beta.1;1.0.0-beta.1

# This is a temporary fix for libaries that need the unreleased dependency version of core
# This is a temporary fix for libaries that need the unreleased dependency version of core. It's worth
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should consider putting an invalid version in there something like "Unused" or "Unreleased" just so it is clear and there is no confusion later if we increment the one but not the other.

# noting that the 'current' version isn't used, these entries are for the dependency versions
unreleased_com.azure:azure-core;1.2.0-beta.1;1.2.0-beta.1

# This is a temporary fix for libaries that need the unreleased dependency version of azure-core-test
Expand Down