def assert_project_properties_contain(self, expected: dict): property_reader = PropertyIO.get_instance_by_filename( self.project_property_file) try: actual = property_reader.from_file(self.project_property_file) except FileNotFoundError: actual = dict() self.assert_same_pairs(expected, actual)
def cmd_convert_config(context): result = Result() with open(context.args['<input-file>'], mode='r', encoding='utf-8') as in_file: if in_file is None: result.fail(os.EX_USAGE, _("Failed to open input file"), None) return result input = PropertyIO.get_instance_by_filename(in_file.name) with open(context.args['<output-file>'], mode='w', encoding='utf-8') as out_file: if out_file is None: result.fail(os.EX_USAGE, _("Failed to open output file"), None) return result output = PropertyIO.get_instance_by_filename(out_file.name) config = input.from_stream(in_file) output.to_stream(out_file, config) 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 __test_load_store(self, file_name: str): property_file: PropertyIO = PropertyIO.get_instance_by_filename( file_name) properties = dict() properties['bla'] = 'blub' property_file.to_file(file_name, properties) print('===================================') print(file_name) print('---------- FILE CONTENTS ----------') with open(file_name, 'r') as file: print(file.read()) print('-----------------------------------') stored_properties = property_file.from_file(file_name) assert properties == stored_properties
def __test_load_store_bytes(self, file_name: str): property_file: PropertyIO = PropertyIO.get_instance_by_filename( file_name) properties = property_file.from_bytes(bytes(), 'UTF-8') assert len(properties) == 0 properties['bla'] = 'blub' written_bytes = property_file.to_bytes(properties, 'UTF-8') print('===================================') print(file_name) print('---------- FILE CONTENTS ----------') print(str(written_bytes, 'UTF-8')) print('-----------------------------------') stored_properties = property_file.from_bytes(written_bytes, 'UTF-8') assert properties == stored_properties
def __test_load_store_string(self, file_name: str): property_file: PropertyIO = PropertyIO.get_instance_by_filename( file_name) properties = property_file.from_str("") assert len(properties) == 0 properties['bla'] = 'blub' written_string = property_file.to_str(properties) print('===================================') print(file_name) print('---------- FILE CONTENTS ----------') print(written_string) print('-----------------------------------') stored_properties = property_file.from_str(written_string) assert properties == stored_properties
def read_properties_in_commit(context: Context, repo: RepoContext, config: dict, commit: str): if config is not None: property_file = config.get(const.CONFIG_PROJECT_PROPERTY_FILE) if property_file is None: return None properties_bytes = repotools.get_file_contents(repo, commit, property_file) if properties_bytes is None: return property_reader = PropertyIO.get_instance_by_filename(property_file) properties = property_reader.from_bytes( properties_bytes, const.DEFAULT_PROPERTY_ENCODING) if properties is None: context.fail(os.EX_DATAERR, _("Failed to parse properties."), None) return properties
def read_config_in_commit( repo: RepoContext, commit: str, config_file_path: str = const.DEFAULT_CONFIG_FILE) -> dict: if config_file_path is None: config_str = None for config_filename in const.DEFAULT_CONFIGURATION_FILE_NAMES: config_str = repotools.get_file_contents(repo, commit, config_filename) if config_filename is not None: break else: config_str = repotools.get_file_contents(repo, commit, config_file_path) if config_str is not None: config = PropertyIO.get_instance_by_filename( config_file_path).from_bytes(config_str, const.DEFAULT_PROPERTY_ENCODING) else: config = None return config
def create(args: dict, result_out: Result) -> 'Context': context = Context() context.config: Config = Config() if args is not None: context.args = args context.batch = context.args['--batch'] context.assume_yes = context.args.get('--assume-yes') context.dry_run = context.args.get('--dry-run') # TODO remove this workaround context.verbose = (context.args['--verbose'] + 1) // 2 context.pretty = context.args['--pretty'] else: context.args = dict() # configure CLI cli.set_allow_color(not context.batch) # initialize repo context and attempt to load the config file if '--root' in context.args and context.args['--root'] is not None: context.root = context.args['--root'] context.repo = RepoContext() context.repo.dir = context.root context.repo.verbose = context.verbose context.git_version = repotools.git_version(context.repo) # context.repo.use_root_dir_arg = semver.compare(context.git_version, "2.9.0") >= 0 context.repo.use_root_dir_arg = False repo_root = repotools.git_rev_parse(context.repo, '--show-toplevel') # None when invalid or bare if repo_root is not None: context.repo.dir = repo_root if context.verbose >= const.TRACE_VERBOSITY: cli.print("--------------------------------------------------------------------------------") cli.print("refs in {repo}:".format(repo=context.repo.dir)) cli.print("--------------------------------------------------------------------------------") for ref in repotools.git_list_refs(context.repo): cli.print(repr(ref)) cli.print("--------------------------------------------------------------------------------") config_dir = context.repo.dir else: context.repo = None config_dir = context.root gitflow_config_file: Optional[str] = None if context.args['--config'] is not None: gitflow_config_file = os.path.join(config_dir, context.args['--config']) if gitflow_config_file is None: result_out.fail(os.EX_DATAERR, _("the specified config file does not exist or is not a regular file: {path}.") .format(path=repr(gitflow_config_file)), None ) else: for config_filename in const.DEFAULT_CONFIGURATION_FILE_NAMES: path = os.path.join(config_dir, config_filename) if os.path.exists(path): gitflow_config_file = path break if gitflow_config_file is None: result_out.fail(os.EX_DATAERR, _("config file not found.") .format(path=repr(gitflow_config_file)), _("Default config files are\n:{list}") .format(list=const.DEFAULT_CONFIGURATION_FILE_NAMES) ) if context.verbose >= const.TRACE_VERBOSITY: cli.print("gitflow_config_file: " + gitflow_config_file) with open(gitflow_config_file) as json_file: config = PropertyIO.get_instance_by_filename(gitflow_config_file).from_stream(json_file) else: config = object() build_config_json = config.get(const.CONFIG_BUILD) context.config.version_change_actions = config.get(const.CONFIG_ON_VERSION_CHANGE, []) context.config.build_stages = list() if build_config_json is not None: stages_json = build_config_json.get('stages') if stages_json is not None: for stage_key, stage_json in stages_json.items(): stage = BuildStage() if isinstance(stage_json, dict): stage.type = stage_json.get('type') or stage_key if stage.type not in const.BUILD_STAGE_TYPES: result_out.fail( os.EX_DATAERR, _("Configuration failed."), _("Invalid build stage type {key}." .format(key=repr(stage.type))) ) stage.name = stage_json.get('name') or stage_key stage_labels = stage_json.get('labels') if isinstance(stage_labels, list): stage.labels.extend(stage_labels) else: stage.labels.append(stage_labels) stage_steps_json = stage_json.get('steps') if stage_steps_json is not None: for step_key, step_json in stage_steps_json.items(): step = BuildStep() if isinstance(step_json, dict): step.name = step_json.get('name') or step_key step.commands = step_json.get('commands') stage_labels = stage_json.get('labels') if isinstance(stage_labels, list): stage.labels.extend(stage_labels) else: stage.labels.append(stage_labels) elif isinstance(step_json, list): step.name = step_key step.type = step_key step.commands = step_json else: result_out.fail( os.EX_DATAERR, _("Configuration failed."), _("Invalid build step definition {type} {key}." .format(type=repr(type(step_json)), key=repr(step_key))) ) stage.steps.append(step) elif isinstance(stage_json, list): stage.type = stage_key stage.name = stage_key if len(stage_json): step = BuildStep() step.name = '#' step.commands = stage_json stage.steps.append(step) else: result_out.fail( os.EX_DATAERR, _("Configuration failed."), _("Invalid build stage definition {key}." .format(key=repr(stage_key))) ) context.config.build_stages.append(stage) context.config.build_stages.sort(key=utils.cmp_to_key(lambda stage_a, stage_b: const.BUILD_STAGE_TYPES.index(stage_a.type) - const.BUILD_STAGE_TYPES.index(stage_b.type) ), reverse=False ) # project properties config context.config.property_file = config.get(const.CONFIG_PROJECT_PROPERTY_FILE) if context.config.property_file is not None: context.config.property_file = os.path.join(context.root, context.config.property_file) context.config.version_property = config.get(const.CONFIG_VERSION_PROPERTY) context.config.sequence_number_property = config.get( const.CONFIG_SEQUENCE_NUMBER_PROPERTY) context.config.version_property = config.get( const.CONFIG_VERSION_PROPERTY) property_names = [property for property in [context.config.sequence_number_property, context.config.version_property] if property is not None] duplicate_property_names = [item for item, count in collections.Counter(property_names).items() if count > 1] if len(duplicate_property_names): result_out.fail(os.EX_DATAERR, _("Configuration failed."), _("Duplicate property names: {duplicate_property_names}").format( duplicate_property_names=', '.join(duplicate_property_names)) ) # version config context.config.version_config = VersionConfig() versioning_scheme = config.get(const.CONFIG_VERSIONING_SCHEME, const.DEFAULT_VERSIONING_SCHEME) if versioning_scheme not in const.VERSIONING_SCHEMES: result_out.fail(os.EX_DATAERR, _("Configuration failed."), _("The versioning scheme {versioning_scheme} is invalid.").format( versioning_scheme=utils.quote(versioning_scheme, '\''))) context.config.version_config.versioning_scheme = const.VERSIONING_SCHEMES[versioning_scheme] if context.config.version_config.versioning_scheme == VersioningScheme.SEMVER: qualifiers = config.get(const.CONFIG_VERSION_TYPES, const.DEFAULT_PRE_RELEASE_QUALIFIERS) if isinstance(qualifiers, str): qualifiers = [qualifier.strip() for qualifier in qualifiers.split(",")] if qualifiers != sorted(qualifiers): result_out.fail( os.EX_DATAERR, _("Configuration failed."), _("Pre-release qualifiers are not specified in ascending order.") ) context.config.version_config.qualifiers = qualifiers context.config.version_config.initial_version = const.DEFAULT_INITIAL_VERSION elif context.config.version_config.versioning_scheme == VersioningScheme.SEMVER_WITH_SEQ: context.config.version_config.qualifiers = None context.config.version_config.initial_version = const.DEFAULT_INITIAL_SEQ_VERSION else: context.fail(os.EX_CONFIG, "configuration error", "invalid versioning scheme") # branch config context.config.remote_name = "origin" context.config.release_branch_base = config.get(const.CONFIG_RELEASE_BRANCH_BASE, const.DEFAULT_RELEASE_BRANCH_BASE) remote_prefix = repotools.create_ref_name(const.REMOTES_PREFIX, context.config.remote_name) context.release_base_branch_matcher = VersionMatcher( [const.LOCAL_BRANCH_PREFIX, remote_prefix], None, re.escape(context.config.release_branch_base), ) context.release_branch_matcher = VersionMatcher( [const.LOCAL_BRANCH_PREFIX, remote_prefix], config.get( const.CONFIG_RELEASE_BRANCH_PREFIX, const.DEFAULT_RELEASE_BRANCH_PREFIX), config.get( const.CONFIG_RELEASE_BRANCH_PATTERN, const.DEFAULT_RELEASE_BRANCH_PATTERN), ) context.work_branch_matcher = VersionMatcher( [const.LOCAL_BRANCH_PREFIX, remote_prefix], [const.BRANCH_PREFIX_DEV, const.BRANCH_PREFIX_PROD], config.get( const.CONFIG_WORK_BRANCH_PATTERN, const.DEFAULT_WORK_BRANCH_PATTERN), ) context.version_tag_matcher = VersionMatcher( [const.LOCAL_TAG_PREFIX], config.get( const.CONFIG_VERSION_TAG_PREFIX, const.DEFAULT_VERSION_TAG_PREFIX), config.get( const.CONFIG_VERSION_TAG_PATTERN, const.DEFAULT_SEMVER_VERSION_TAG_PATTERN if context.config.version_config.versioning_scheme == VersioningScheme.SEMVER else const.DEFAULT_SEMVER_WITH_SEQ_VERSION_TAG_PATTERN) ) context.version_tag_matcher.group_unique_code = None \ if context.config.version_config.versioning_scheme == VersioningScheme.SEMVER \ else 'prerelease_type' context.discontinuation_tag_matcher = VersionMatcher( [const.LOCAL_TAG_PREFIX], config.get( const.CONFIG_DISCONTINUATION_TAG_PREFIX, const.DEFAULT_DISCONTINUATION_TAG_PREFIX), config.get( const.CONFIG_DISCONTINUATION_TAG_PATTERN, const.DEFAULT_DISCONTINUATION_TAG_PATTERN), None ) return context