diff --git a/src/screwdrivercd/version/arguments.py b/src/screwdrivercd/version/arguments.py index 456d85a..395234f 100644 --- a/src/screwdrivercd/version/arguments.py +++ b/src/screwdrivercd/version/arguments.py @@ -36,6 +36,14 @@ def get_config_default(key, default=None, setup_cfg_filename='setup.cfg'): return default +def get_bool_equivalent(key) -> bool: + """ Get the equivalent bool value for a string key in the config file. """ + + if isinstance(key, str) and key.lower() in ['false', '0', 'off']: + return False + return True + + def parse_arguments(): """ Parse the command line arguments @@ -47,10 +55,10 @@ def parse_arguments(): """ version_type = get_config_default('version_type', default='default') update_meta = get_config_default('update_screwdriver_meta', default='false') - if isinstance(update_meta, str) and update_meta.lower() in ['false', '0', 'off']: - update_meta = False - else: - update_meta = True + update_meta = get_bool_equivalent(update_meta) + link_to_project = get_config_default('link_to_project', default='false') + link_to_project = get_bool_equivalent(link_to_project) + version_choices = list(versioners.keys()) if version_type not in version_choices: raise VersionError(f'The version_type in the [screwdrivercd.version] section of setup.cfg has an invalid version type of {version_type!r}') @@ -60,5 +68,6 @@ def parse_arguments(): parser.add_argument('--version_type', default=version_type, choices=version_choices, help='Type of version number to generate') parser.add_argument('--ignore_meta', default=False, action='store_true', help='Ignore the screwdriver v4 metadata') parser.add_argument('--update_meta', default=update_meta, action='store_true', help='Update the screwdriver v4 metadata with the new version') + parser.add_argument('--link_to_project', default=link_to_project, action='store_true', help='Add/update link to source project tree for current package version') result = parser.parse_args() return result diff --git a/src/screwdrivercd/version/cli.py b/src/screwdrivercd/version/cli.py index cc87b5a..79a9ca5 100644 --- a/src/screwdrivercd/version/cli.py +++ b/src/screwdrivercd/version/cli.py @@ -24,7 +24,7 @@ def main(): if args.force_update or setupcfg_has_metadata(): versioner = versioners[args.version_type] print(f'Updating version using the {versioner.name} version plugin', flush=True) - version = versioner(ignore_meta_version=args.ignore_meta, update_sdv4_meta=args.update_meta) + version = versioner(ignore_meta_version=args.ignore_meta, update_sdv4_meta=args.update_meta, link_to_project=args.link_to_project) version.update_setup_cfg_metadata() if args.update_meta: diff --git a/src/screwdrivercd/version/version_types.py b/src/screwdrivercd/version/version_types.py index 3be1012..46181ee0 100644 --- a/src/screwdrivercd/version/version_types.py +++ b/src/screwdrivercd/version/version_types.py @@ -13,7 +13,7 @@ LOG = logging.getLogger(__name__) -class Version(): +class Version: """ Base Screwdriver Versioning class """ @@ -22,12 +22,13 @@ class Version(): setup_cfg_filename: str = 'setup.cfg' _meta_version: str = '' - def __init__(self, setup_cfg_filename=None, ignore_meta_version: bool=False, update_sdv4_meta: bool=True, meta_command: str='meta'): + def __init__(self, setup_cfg_filename=None, ignore_meta_version: bool = False, update_sdv4_meta: bool = True, link_to_project: bool = False, meta_command: str = 'meta'): if setup_cfg_filename: # pragma: no cover self.setup_cfg_filename = setup_cfg_filename self.meta_command = meta_command self.ignore_meta_version = ignore_meta_version self.update_sdv4_meta = update_sdv4_meta + self.link_to_project = link_to_project def __repr__(self): return repr(self.version) @@ -67,18 +68,29 @@ def generate(self): """ return self.read_setup_version() + def get_link_to_project_using_hash(self): + """ + Generate and return link to build-triggering commit using its SHA hash + """ + if self.link_to_project and os.environ.get('SCM_URL') and os.environ.get('SD_BUILD_SHA'): + return os.environ.get('SCM_URL') + '/tree/' + os.environ.get('SD_BUILD_SHA') + return '' + def update_setup_cfg_metadata(self): """ Update the version value in the setup.cfg file """ if not self.version: # pragma: no cover return + link_to_project = self.get_link_to_project_using_hash() config = configparser.ConfigParser() config.read(self.setup_cfg_filename) if 'metadata' not in config.sections(): config['metadata'] = {} config['metadata']['version'] = self.version + if link_to_project: + config['metadata']['link_to_project'] = link_to_project with open(self.setup_cfg_filename, 'w') as config_file_handle: config.write(config_file_handle) @@ -175,7 +187,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def revision_value(self): # pragma: no cover - "Method to return a newly generatated revision value" + """Method to return a newly generated revision value""" return self.default_revision_value def generate(self): # pragma: no cover @@ -233,6 +245,7 @@ class VersionSDV4Build(VersionUpdateRevision): Each new screwdriver job run will increment the revision number. """ name = 'sdv4_SD_BUILD' + def revision_value(self): revision = os.environ.get('SD_BUILD', None) if not revision: @@ -292,6 +305,6 @@ def generate(self): } # Make sure the versioners are listed all lowercase to make identifying them easier -for key, value in list(versioners.items()): +for key, value in list(versioners.items()): if key.lower() not in versioners.keys(): versioners[key.lower()] = value diff --git a/tests/test_versioners.py b/tests/test_versioners.py index fad511a..ac361fe 100644 --- a/tests/test_versioners.py +++ b/tests/test_versioners.py @@ -13,13 +13,28 @@ class TestVersioners(ScrewdriverTestCase): environ_keys = { 'BASE_PYTHON', 'PACKAGE_DIR', 'PACKAGE_DIRECTORY', 'SD_ARTIFACTS_DIR', 'SD_BUILD', 'SD_BUILD_ID', - 'SD_PULL_REQUEST', + 'SD_PULL_REQUEST', 'SCM_URL', 'SD_BUILD_SHA', } def test__version__read_setup_version__no_version(self): version = Version(ignore_meta_version=True).read_setup_version() self.assertEqual(version, Version.default_version) + def test__version__get_link_to_project_using_hash__unset_env_variables(self): + link = Version(ignore_meta_version=True, link_to_project=True).get_link_to_project_using_hash() + self.assertEqual(link, '') + + def test__version__get_link_to_project_using_hash__set_and_unset_env_variables(self): + os.environ['SD_BUILD_SHA'] = 'a5c3785ed8d6a35868bc169f07e40e889087fd2e' + link = Version(ignore_meta_version=True, link_to_project=True).get_link_to_project_using_hash() + self.assertEqual(link, '') + + def test__version__get_link_to_project_using_hash__set_env_variables(self): + os.environ['SCM_URL'] = 'https://github.com/org/project' + os.environ['SD_BUILD_SHA'] = 'a5c3785ed8d6a35868bc169f07e40e889087fd2e' + link = Version(ignore_meta_version=True, link_to_project=True).get_link_to_project_using_hash() + self.assertEqual(link, 'https://github.com/org/project/tree/a5c3785ed8d6a35868bc169f07e40e889087fd2e') + def test__git_revision_count__no_git(self): with self.assertRaises(VersionError): version = str(VersionGitRevisionCount(ignore_meta_version=True, log_errors=False))