def prompt_for_confirmation(context: Context, fail_title: str, message: str, prompt: str): result = Result() if context.batch: result.value = context.assume_yes if not result.value: sys.stdout.write(prompt + ' -' + os.linesep) result.fail(const.EX_ABORTED, fail_title, _("Operation aborted in batch mode.")) else: if message is not None: cli.warn(message) sys.stderr.flush() sys.stdout.flush() if context.assume_yes: sys.stdout.write(prompt + ' y' + os.linesep) result.value = True else: result.value = cli.query_yes_no(sys.stdout, prompt, "no") if result.value is not True: result.error(const.EX_ABORTED_BY_USER, fail_title, _("Operation aborted."), False) return result
def version_bump_prerelease(version_config: VersionConfig, version: Optional[str], global_seq: Optional[int]): result = Result() version_info = semver.parse_version_info( version) if version is not None else semver.parse_version_info("0.0.0") if version_info.prerelease: prerelease_version_elements = version_info.prerelease.split(".") if len(prerelease_version_elements ) > 0 and prerelease_version_elements[0].upper() == "SNAPSHOT": if len(prerelease_version_elements) == 1: result.error( os.EX_DATAERR, _("The pre-release increment has been skipped."), _("In order to retain Maven compatibility, " "the pre-release component of snapshot versions must not be versioned." )) else: result.error( os.EX_DATAERR, _("Failed to increment the pre-release component of version {version}." ).format(version=repr(version)), _("Snapshot versions must not have a pre-release version.") ) result.value = version elif len(prerelease_version_elements) == 1: if version_config.versioning_scheme != VersioningScheme.SEMVER_WITH_SEQ: result.error( os.EX_DATAERR, _("Failed to increment the pre-release component of version {version}." ).format(version=repr(version)), _("The qualifier {qualifier} must already be versioned."). format(qualifier=repr(prerelease_version_elements[0]))) result.value = semver.bump_prerelease(version) else: result.error( os.EX_DATAERR, _("Failed to increment the pre-release component of version {version}." ).format(version=repr(version)), _("Pre-release increments cannot be performed on release versions." )) if result.has_errors(): result.value = None elif result.value is not None and not semver.compare( result.value, version) > 0: result.value = None if not result.value: result.error( os.EX_SOFTWARE, _("Failed to increment the pre-release of version {version} for unknown reasons." ).format(version=repr(version)), None) return result
def update_project_property_file(context: Context, prev_properties: dict, new_version: str, new_sequential_version: int, commit_out: CommitInfo): result = Result() result.value = False if context.config.property_file is not None: property_reader = PropertyIO.get_instance_by_filename( context.config.property_file) if property_reader is None: result.fail( os.EX_DATAERR, _("Property file not supported: {path}\n" "Currently supported:\n" "{listing}").format(path=repr(context.config.property_file), listing='\n'.join( ' - ' + type for type in ['*.properties'])), None) properties = update_project_properties(context, prev_properties, new_version, new_sequential_version) property_reader.write_file(context.config.property_file, properties) commit_out.add_file(context.config.property_file) result.value = True else: properties = None var_separator = ' : ' if properties is not None: def log_property(properties: dict, key: str): if key is not None: commit_out.add_message( '#properties[' + utils.quote(key, '"') + ']' + var_separator + cli.if_none(properties.get(key), "null")) for property_key in [ context.config.version_property, context.config.sequence_number_property ]: log_property(properties, property_key) if context.verbose and result.value != 0: print("properties have changed") print("commit message:") print(commit_out.message) return result
def validate_version(config: VersionConfig, version_string): result = Result() try: version_info = semver.parse_version_info(version_string) if version_info.prerelease is not None: if version_info.prerelease is not None and not re.match(r'[a-zA-Z][a-zA-Z0-9]*\.\d', version_info.prerelease): result.error(os.EX_DATAERR, "Invalid version format.", "The pre-release component must contain a type name with a version number.\n" "The required version format is:\n" + const.TEXT_VERSION_STRING_FORMAT) prerelease_version_elements = version_info.prerelease.split(".") prerelease_type = prerelease_version_elements[0] prerelease_version = prerelease_version_elements[1] if config.qualifiers is not None and prerelease_type not in config.qualifiers: result.error(os.EX_DATAERR, "Invalid version.", "The pre-release type \"" + prerelease_type + "\" is invalid, must be one of: " + ','.join(config.qualifiers) + ".\n" + "Configuration property: " + const.CONFIG_VERSION_TYPES) result.value = version_string except ValueError: result.error(os.EX_DATAERR, "Failed to parse the version.", "The required version format is:\n" + const.TEXT_VERSION_STRING_FORMAT) return result
def __call__(self, version_config: VersionConfig, old_version: Optional[str], global_seq: Optional[int]): result = Result() result.add_subresult( version.validate_version(version_config, self.__new_version)) result.value = self.__new_version return result
def version_bump_to_release(version_config: VersionConfig, version: Optional[str], global_seq: Optional[int]): result = Result() version_info = semver.parse_version_info( version) if version is not None else semver.parse_version_info("0.0.0") if version_config.versioning_scheme == VersioningScheme.SEMVER_WITH_SEQ: result.error( os.EX_USAGE, _("Failed to increment version to release: {version}.").format( version=repr(version)), _("Sequential versions cannot be release versions.")) return result if not version_info.prerelease: result.error( os.EX_DATAERR, _("Failed to increment version to release: {version}.").format( version=repr(version)), _("Only pre-release versions can be incremented to a release version." )) if not result.has_errors(): result.value = semver.format_version(version_info.major, version_info.minor, version_info.patch, None, None) return result
def version_bump_qualifier(version_config: VersionConfig, version: Optional[str], global_seq: Optional[int]): result = Result() version_info = semver.parse_version_info( version) if version is not None else semver.parse_version_info("0.0.0") new_qualifier = None if not version_config.qualifiers: result.error( os.EX_USAGE, _("Failed to increment the pre-release qualifier of version {version}." ).format(version=repr(version)), _("The version scheme does not contain qualifiers")) return result if version_info.prerelease: prerelease_version_elements = version_info.prerelease.split(".") qualifier = prerelease_version_elements[0] qualifier_index = version_config.qualifiers.index( qualifier) if qualifier in version_config.qualifiers else -1 if qualifier_index < 0: result.error( os.EX_DATAERR, _("Failed to increment the pre-release qualifier of version {version}." ).format(version=repr(version)), _("The current qualifier is invalid: {qualifier}").format( qualifier=repr(qualifier))) else: qualifier_index += 1 if qualifier_index < len(version_config.qualifiers): new_qualifier = version_config.qualifiers[qualifier_index] else: result.error( os.EX_DATAERR, _("Failed to increment the pre-release qualifier {qualifier} of version {version}." ).format(qualifier=qualifier, version=repr(version)), _("There are no further qualifiers with higher precedence, configured qualifiers are:\n" "{listing}\n" "The sub command 'bump-to-release' may be used for a final bump." ).format(listing='\n'.join( ' - ' + repr(qualifier) for qualifier in version_config.qualifiers))) else: result.error( os.EX_DATAERR, _("Failed to increment the pre-release qualifier of version {version}." ).format(version=version), _("Pre-release increments cannot be performed on release versions." )) if not result.has_errors() and new_qualifier is not None: result.value = semver.format_version(version_info.major, version_info.minor, version_info.patch, new_qualifier + ".1", None) return result
def download_file(source_uri: str, dest_file: str, hash_hex: str): from urllib import request import hashlib result = Result() hash = bytes.fromhex(hash_hex) download = False if not os.path.exists(dest_file): cli.print("file does not exist: " + dest_file) download = True elif hash_file(hashlib.sha256(), dest_file) != hash: cli.print("file hash does not match: " + dest_file) download = True else: cli.print("keeping file: " + dest_file + ", sha256 matched: " + hash_hex) if download: cli.print("downloading: " + source_uri + " to " + dest_file) request.urlretrieve(url=str(source_uri), filename=dest_file + "~") filesystem.replace_file(dest_file + "~", dest_file) if hash is not None: actual_hash = hash_file(hashlib.sha256(), dest_file) if actual_hash != hash: result.error( os.EX_IOERR, _("File verification failed."), _("The file {file} is expected to hash to {expected_hash},\n" "The actual hash is: {actual_hash}").format( file=repr(dest_file), expected_hash=repr(hash_hex), actual_hash=repr(actual_hash.hex()), )) if not result.has_errors(): result.value = dest_file return result
def version_bump_patch(version_config: VersionConfig, version: Optional[str], global_seq: Optional[int]): result = Result() try: global_seq = filter_sequence_number(version_config, version, global_seq) except ValueError as e: result.error(os.EX_DATAERR, "version increment failed", str(e)) if not result.has_errors(): version_info = semver.parse_version_info( semver.bump_patch(version) ) if version is not None else semver.parse_version_info("0.0.0") pre_release = True result.value = semver.format_version( version_info.major, version_info.minor, version_info.patch, (version_config.qualifiers[0] + ".1" if pre_release else None) if version_config.versioning_scheme != VersioningScheme.SEMVER_WITH_SEQ else global_seq + 1, None) return result
def clone_repository(context: Context, branch: str) -> Result: """ :rtype: Result """ result = Result() remote = repotools.git_get_remote(context.repo, context.config.remote_name) if remote is None: result.fail( os.EX_DATAERR, _("Failed to clone repo."), _("The remote {remote} does not exist.").format( remote=repr(context.config.remote_name))) tempdir_path = tempfile.mkdtemp(prefix=os.path.basename(context.repo.dir) + ".gitflow-clone.") try: if os.path.exists(tempdir_path): os.chmod(path=tempdir_path, mode=0o700) if os.path.isdir(tempdir_path): if os.listdir(tempdir_path): result.fail( os.EX_DATAERR, _("Failed to clone repo."), _("Directory is not empty: {path}").format( path=tempdir_path)) else: result.fail( os.EX_DATAERR, _("Failed to clone repo."), _("File is not a directory: {path}").format( path=tempdir_path)) else: result.fail( os.EX_DATAERR, _("Failed to clone repo."), _("File does not exist: {path}").format(path=tempdir_path)) if context.config.push_to_local: returncode, out, err = repotools.git_raw(git=context.repo.git, args=[ 'clone', '--branch', branch, '--shared', context.repo.dir, tempdir_path ], verbose=context.verbose) else: returncode, out, err = repotools.git_raw(git=context.repo.git, args=[ 'clone', '--branch', branch, '--reference', context.repo.dir, remote.url, tempdir_path ], verbose=context.verbose) if returncode != os.EX_OK: result.error(os.EX_DATAERR, _("Failed to clone the repository."), _("An unexpected error occurred.")) except: result.error(os.EX_DATAERR, _("Failed to clone the repository."), _("An unexpected error occurred.")) finally: context.add_subresult(result) if not result.has_errors(): repo = RepoContext() repo.git = context.repo.git repo.dir = tempdir_path repo.verbose = context.repo.verbose result.value = repo else: shutil.rmtree(path=tempdir_path) return result