def test_version_comparison(self): examples = ( ('debian/0.11.1+ds-1-3-ga0afcbd', '0.11.1+ds-2'), ('v0.12.0-85-g2880105', 'v0.12.0-19-g767d4f9'), ('v0.17.0rc1-1-g52ebdfd', '0.17.0rc1'), ('v0.17.0', 'v0.17.0rc1') ) for v1, v2 in examples: self.assertTrue(SaltStackVersion.parse(v1) > v2) self.assertTrue(SaltStackVersion.parse(v2) < v1)
def test_version_comparison(self): examples = ( ('debian/0.11.1+ds-1-3-ga0afcbd', '0.11.1+ds-2'), ('v0.12.0-85-g2880105', 'v0.12.0-19-g767d4f9'), ('v0.17.0rc1-1-g52ebdfd', '0.17.0rc1'), ('v0.17.0', 'v0.17.0rc1'), ('Hydrogen', '0.17.0'), ('Helium', 'Hydrogen'), ('v2014.1.4.1-n/a-abcdefgh', 'v2014.1.4.1rc3-n/a-abcdefgh'), ('v2014.1.4.1-1-abcdefgh', 'v2014.1.4.1-n/a-abcdefgh') ) for higher_version, lower_version in examples: self.assertTrue(SaltStackVersion.parse(higher_version) > lower_version) self.assertTrue(SaltStackVersion.parse(lower_version) < higher_version)
def test_version_parsing(self): strip_initial_non_numbers_regex = re.compile(r'(?:[^\d]+)?(?P<vs>.*)') expect = ( ('v0.12.0-19-g767d4f9', (0, 12, 0, 0, '', 0, 19, 'g767d4f9'), None), ('v0.12.0-85-g2880105', (0, 12, 0, 0, '', 0, 85, 'g2880105'), None), ('debian/0.11.1+ds-1-3-ga0afcbd', (0, 11, 1, 0, '', 0, 3, 'ga0afcbd'), '0.11.1-3-ga0afcbd'), ('0.12.1', (0, 12, 1, 0, '', 0, 0, None), None), ('0.12.1', (0, 12, 1, 0, '', 0, 0, None), None), ('0.17.0rc1', (0, 17, 0, 0, 'rc', 1, 0, None), None), ('v0.17.0rc1-1-g52ebdfd', (0, 17, 0, 0, 'rc', 1, 1, 'g52ebdfd'), None), ('v2014.1.4.1', (2014, 1, 4, 1, '', 0, 0, None), None), ('v2014.1.4.1rc3-n/a-abcdefgh', (2014, 1, 4, 1, 'rc', 3, -1, 'abcdefgh'), None), ('v3.4.1.1', (3, 4, 1, 1, '', 0, 0, None), None) ) for vstr, full_info, version in expect: saltstack_version = SaltStackVersion.parse(vstr) self.assertEqual( saltstack_version.full_info, full_info ) if version is None: version = strip_initial_non_numbers_regex.search(vstr).group('vs') self.assertEqual(saltstack_version.string, version)
def test_version_comparison(self): examples = (('debian/0.11.1+ds-1-3-ga0afcbd', '0.11.1+ds-2'), ('v0.12.0-85-g2880105', 'v0.12.0-19-g767d4f9'), ('v0.17.0rc1-1-g52ebdfd', '0.17.0rc1'), ('v0.17.0', 'v0.17.0rc1'), ('Hydrogen', '0.17.0'), ('Helium', 'Hydrogen'), ('v2014.1.4.1-n/a-abcdefgh', 'v2014.1.4.1rc3-n/a-abcdefgh'), ('v2014.1.4.1-1-abcdefgh', 'v2014.1.4.1-n/a-abcdefgh'), ('v2016.12.0rc1', 'v2016.12.0b1'), ('v2016.12.0beta1', 'v2016.12.0alpha1'), ('v2016.12.0alpha1', 'v2016.12.0alpha0')) for higher_version, lower_version in examples: self.assertTrue( SaltStackVersion.parse(higher_version) > lower_version) self.assertTrue( SaltStackVersion.parse(lower_version) < higher_version)
def test_version_parsing(version_string, full_info, version): saltstack_version = SaltStackVersion.parse(version_string) assert saltstack_version.full_info == full_info if version is None: version = ( STRIP_INITIAL_NON_NUMBERS_REGEX.search(version_string).group( "vs") # Strip leading non numeric chars # Now, make it Wheel metadata 1.2 compliant post release .replace("n/a", "0na").replace("-", "+", 1).replace("-", ".", 1)) assert saltstack_version.string == version
def test_salt_with_git_version(self): if getattr(self, '_call_binary_', None) is None: self.skipTest('\'_call_binary_\' not defined.') from salt.utils import which from salt.version import __version_info__, SaltStackVersion git = which('git') if not git: self.skipTest('The git binary is not available') # Let's get the output of git describe process = subprocess.Popen( [git, 'describe', '--tags', '--first-parent', '--match', 'v[0-9]*'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, cwd=CODE_DIR ) out, err = process.communicate() if process.returncode != 0: process = subprocess.Popen( [git, 'describe', '--tags', '--match', 'v[0-9]*'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, cwd=CODE_DIR ) out, err = process.communicate() if not out: self.skipTest( 'Failed to get the output of \'git describe\'. ' 'Error: \'{0}\''.format( salt.utils.to_str(err) ) ) parsed_version = SaltStackVersion.parse(out) if parsed_version.info < __version_info__: self.skipTest( 'We\'re likely about to release a new version. This test ' 'would fail. Parsed(\'{0}\') < Expected(\'{1}\')'.format( parsed_version.info, __version_info__ ) ) elif parsed_version.info != __version_info__: self.skipTest( 'In order to get the proper salt version with the ' 'git hash you need to update salt\'s local git ' 'tags. Something like: \'git fetch --tags\' or ' '\'git fetch --tags upstream\' if you followed ' 'salt\'s contribute documentation. The version ' 'string WILL NOT include the git hash.' ) out = '\n'.join(self.run_script(self._call_binary_, '--version')) self.assertIn(parsed_version.string, out)
def test_salt_with_git_version(self): if getattr(self, "_call_binary_", None) is None: self.skipTest("'_call_binary_' not defined.") from salt.version import __version_info__, SaltStackVersion git = salt.utils.path.which("git") if not git: self.skipTest("The git binary is not available") opts = { "stdout": subprocess.PIPE, "stderr": subprocess.PIPE, "cwd": CODE_DIR, } if not salt.utils.platform.is_windows(): opts["close_fds"] = True # Let's get the output of git describe process = subprocess.Popen( [git, "describe", "--tags", "--first-parent", "--match", "v[0-9]*"], **opts ) out, err = process.communicate() if process.returncode != 0: process = subprocess.Popen( [git, "describe", "--tags", "--match", "v[0-9]*"], **opts ) out, err = process.communicate() if not out: self.skipTest( "Failed to get the output of 'git describe'. Error: '{}'".format( salt.utils.stringutils.to_str(err) ) ) parsed_version = SaltStackVersion.parse(out) if parsed_version.info < __version_info__: self.skipTest( "We're likely about to release a new version. This test " "would fail. Parsed('{}') < Expected('{}')".format( parsed_version.info, __version_info__ ) ) elif parsed_version.info != __version_info__: self.skipTest( "In order to get the proper salt version with the " "git hash you need to update salt's local git " "tags. Something like: 'git fetch --tags' or " "'git fetch --tags upstream' if you followed " "salt's contribute documentation. The version " "string WILL NOT include the git hash." ) out = "\n".join(self.run_script(self._call_binary_, "--version")) self.assertIn(parsed_version.string, out)
def test_salt_with_git_version(self): if getattr(self, '_call_binary_', None) is None: self.skipTest('\'_call_binary_\' not defined.') from salt.utils import which from salt.version import __version_info__, SaltStackVersion git = which('git') if not git: self.skipTest('The git binary is not available') # Let's get the output of git describe process = subprocess.Popen( [git, 'describe', '--tags', '--match', 'v[0-9]*'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, cwd=CODE_DIR ) out, err = process.communicate() if not out: self.skipTest( 'Failed to get the output of \'git describe\'. ' 'Error: {0!r}'.format( err ) ) parsed_version = SaltStackVersion.parse(out) if parsed_version.info < __version_info__: self.skipTest( 'We\'re likely about to release a new version. This test ' 'would fail. Parsed({0!r}) < Expected({1!r})'.format( parsed_version.info, __version_info__ ) ) elif parsed_version.info != __version_info__: self.skipTest( 'In order to get the proper salt version with the ' 'git hash you need to update salt\'s local git ' 'tags. Something like: \'git fetch --tags\' or ' '\'git fetch --tags upstream\' if you followed ' 'salt\'s contribute documentation. The version ' 'string WILL NOT include the git hash.' ) out = '\n'.join(self.run_script(self._call_binary_, '--version')) self.assertIn(parsed_version.string, out)
def test_full_info_all_versions(self): """ Test full_info_all_versions property method """ expect = ( ("v2014.1.4.1rc3-n/a-abcdefff", (2014, 1, 4, 1, "rc", 3, -1, "abcdefff")), ("v3.4.1.1", (3, 4, 1, 1, "", 0, 0, None)), ("v3000", (3000, None, None, 0, "", 0, 0, None)), ("v3000.0", (3000, 0, None, 0, "", 0, 0, None)), ("v4518.1", (4518, 1, None, 0, "", 0, 0, None)), ("v3000rc1", (3000, None, None, 0, "rc", 2, 0, None)), ("v3000rc1-n/a-abcdefff", (3000, None, None, 0, "rc", 1, -1, "abcdefff")), ) for vstr, full_info in expect: saltstack_version = SaltStackVersion.parse(vstr) assert saltstack_version.full_info_all_versions, full_info assert len(saltstack_version.full_info_all_versions) == len(full_info)
def test_noc_info(self): """ Test noc_info property method """ expect = ( ("v2014.1.4.1rc3-n/a-abcdefff", (2014, 1, 4, 1, "rc", 3, -1)), ("v3.4.1.1", (3, 4, 1, 1, "", 0, 0)), ("v3000", (3000, "", 0, 0)), ("v3000.0", (3000, "", 0, 0)), ("v4518.1", (4518, 1, "", 0, 0)), ("v3000rc1", (3000, "rc", 1, 0)), ("v3000rc1-n/a-abcdefff", (3000, "rc", 1, -1)), ) for vstr, noc_info in expect: saltstack_version = SaltStackVersion.parse(vstr) assert saltstack_version.noc_info, noc_info assert len(saltstack_version.noc_info) == len(noc_info)
def test_noc_info(self): ''' Test noc_info property method ''' expect = ( ('v2014.1.4.1rc3-n/a-abcdefff', (2014, 1, 4, 1, 'rc', 3, -1)), ('v3.4.1.1', (3, 4, 1, 1, '', 0, 0)), ('v3000', (3000, '', 0, 0)), ('v3000.0', (3000, '', 0, 0)), ('v4518.1', (4518, 1, '', 0, 0)), ('v3000rc1', (3000, 'rc', 1, 0)), ('v3000rc1-n/a-abcdefff', (3000, 'rc', 1, -1)), ) for vstr, noc_info in expect: saltstack_version = SaltStackVersion.parse(vstr) assert saltstack_version.noc_info, noc_info assert len(saltstack_version.noc_info) == len(noc_info)
def run(self): if not os.path.exists( SALT_VERSION_HARDCODED) or self.distribution.with_salt_version: # Write the version file if getattr(self.distribution, 'salt_version_hardcoded_path', None) is None: print('This command is not meant to be called on it\'s own') exit(1) if not self.distribution.with_salt_version: salt_version = __saltstack_version__ # pylint: disable=undefined-variable else: from salt.version import SaltStackVersion salt_version = SaltStackVersion.parse( self.distribution.with_salt_version) # pylint: disable=E0602 open(self.distribution.salt_version_hardcoded_path, 'w').write( INSTALL_VERSION_TEMPLATE.format( date=DATE, full_version_info=salt_version.full_info))
def test_version_parsing(self): strip_initial_non_numbers_regex = re.compile(r'(?:[^\d]+)?(?P<vs>.*)') expect = ( ('v0.12.0-19-g767d4f9', (0, 12, 0, 0, 19, 'g767d4f9'), None), ('v0.12.0-85-g2880105', (0, 12, 0, 0, 85, 'g2880105'), None), ('debian/0.11.1+ds-1-3-ga0afcbd', (0, 11, 1, 0, 3, 'ga0afcbd'), '0.11.1-3-ga0afcbd'), ('0.12.1', (0, 12, 1, 0, 0, None), None), ('0.12.1', (0, 12, 1, 0, 0, None), None), ('0.17.0rc1', (0, 17, 0, 1, 0, None), None), ('v0.17.0rc1-1-g52ebdfd', (0, 17, 0, 1, 1, 'g52ebdfd'), None), ) for vs, full_info, version in expect: saltstack_version = SaltStackVersion.parse(vs) self.assertEqual(saltstack_version.full_info, full_info) if version is None: version = \ strip_initial_non_numbers_regex.search(vs).group('vs') self.assertEqual(saltstack_version.string, version)
def test_full_info_all_versions(self): ''' Test full_info_all_versions property method ''' expect = ( ('v2014.1.4.1rc3-n/a-abcdefff', (2014, 1, 4, 1, 'rc', 3, -1, 'abcdefff')), ('v3.4.1.1', (3, 4, 1, 1, '', 0, 0, None)), ('v3000', (3000, None, None, 0, '', 0, 0, None)), ('v3000.0', (3000, 0, None, 0, '', 0, 0, None)), ('v4518.1', (4518, 1, None, 0, '', 0, 0, None)), ('v3000rc1', (3000, None, None, 0, 'rc', 2, 0, None)), ('v3000rc1-n/a-abcdefff', (3000, None, None, 0, 'rc', 1, -1, 'abcdefff')), ) for vstr, full_info in expect: saltstack_version = SaltStackVersion.parse(vstr) assert saltstack_version.full_info_all_versions, full_info assert len( saltstack_version.full_info_all_versions) == len(full_info)
def test_version_parsing(self): strip_initial_non_numbers_regex = re.compile(r"(?:[^\d]+)?(?P<vs>.*)") expect = ( ("v0.12.0-19-g767d4f9", (0, 12, 0, 0, "", 0, 19, "g767d4f9"), None), ("v0.12.0-85-g2880105", (0, 12, 0, 0, "", 0, 85, "g2880105"), None), ( "debian/0.11.1+ds-1-3-ga0afcbd", (0, 11, 1, 0, "", 0, 3, "ga0afcbd"), "0.11.1-3-ga0afcbd", ), ("0.12.1", (0, 12, 1, 0, "", 0, 0, None), None), ("0.12.1", (0, 12, 1, 0, "", 0, 0, None), None), ("0.17.0rc1", (0, 17, 0, 0, "rc", 1, 0, None), None), ("v0.17.0rc1-1-g52ebdfd", (0, 17, 0, 0, "rc", 1, 1, "g52ebdfd"), None), ("v2014.1.4.1", (2014, 1, 4, 1, "", 0, 0, None), None), ( "v2014.1.4.1rc3-n/a-abcdefff", (2014, 1, 4, 1, "rc", 3, -1, "abcdefff"), None, ), ("v3.4.1.1", (3, 4, 1, 1, "", 0, 0, None), None), ("v3000", (3000, "", 0, 0, None), "3000"), ("v3000.0", (3000, "", 0, 0, None), "3000"), ("v4518.1", (4518, 1, "", 0, 0, None), "4518.1"), ("v3000rc1", (3000, "rc", 1, 0, None), "3000rc1"), ("v3000rc1-n/a-abcdefff", (3000, "rc", 1, -1, "abcdefff"), None), ("3000-n/a-1e7bc8f", (3000, "", 0, -1, "1e7bc8f"), None), ("3000.1-n/a-1e7bc8f", (3000, 1, "", 0, -1, "1e7bc8f"), None), ) for vstr, full_info, version in expect: saltstack_version = SaltStackVersion.parse(vstr) self.assertEqual(saltstack_version.full_info, full_info) if version is None: version = strip_initial_non_numbers_regex.search(vstr).group( "vs") self.assertEqual(saltstack_version.string, version)
def test_unparsable_version(self): with self.assertRaises(ValueError): SaltStackVersion.from_name('Drunk') with self.assertRaises(ValueError): SaltStackVersion.parse('Drunk')
def check_bootstrapped_minion_version(options): ''' Confirm that the bootstrapped minion version matches the desired one ''' if 'salt_minion_bootstrapped' not in options: print_bulleted(options, 'Minion not boostrapped. Not grabbing minion version information.', 'RED') sys.exit(1) print_bulleted(options, 'Grabbing bootstrapped minion version information ... ') cmd = [ 'salt', '-t', '100', '--out=json', '-l', options.log_level ] if options.no_color: cmd.append('--no-color') cmd.extend([ options.vm_name, 'test.version' ]) stdout, stderr, exitcode = run_command(cmd, options, return_output=True, stream_stdout=False, stream_stderr=False) if exitcode: print_bulleted( options, 'Failed to get the bootstrapped minion version. Exit code: {0}'.format(exitcode), 'RED' ) sys.exit(exitcode) if not stdout.strip(): print_bulleted(options, 'Failed to get the bootstrapped minion version(no output).', 'RED') sys.stdout.flush() sys.exit(1) try: version_info = json.loads(stdout.strip()) bootstrap_minion_version = os.environ.get( 'SALT_MINION_BOOTSTRAP_RELEASE', options.bootstrap_salt_commit[:7] ) if bootstrap_minion_version.startswith('v'): bootstrap_minion_version = bootstrap_minion_version[1:] if bootstrap_minion_version not in version_info[options.vm_name]: print_bulleted(options, '\n\nATTENTION!!!!\n', 'YELLOW') print_bulleted( options, 'The boostrapped minion version commit does not contain the desired commit:', 'YELLOW' ) print_bulleted( options, '{0!r} does not contain {1!r}'.format(version_info[options.vm_name], bootstrap_minion_version), 'YELLOW' ) print('\n\n') sys.stdout.flush() else: print_bulleted(options, 'Matches!', 'LIGHT_GREEN') setattr(options, 'bootstrapped_salt_minion_version', SaltStackVersion.parse(version_info[options.vm_name])) except (ValueError, TypeError): print_bulleted(options, 'Failed to load any JSON from {0!r}'.format(stdout.strip()), 'RED')
def test_unparsable_version(): with pytest.raises(ValueError): SaltStackVersion.parse("Drunk")
def test_version_comparison(higher_version, lower_version): assert SaltStackVersion.parse(higher_version) > lower_version assert SaltStackVersion.parse(lower_version) < higher_version assert SaltStackVersion.parse(lower_version) != higher_version
def __get_version(version, version_info): ''' If we can get a version provided at installation time or from Git, use that instead, otherwise we carry on. ''' try: # Try to import the version information provided at install time from saltfuse._version import __version__, __version_info__ # pylint: disable=E0611 return __version__, __version_info__ except ImportError: pass # This might be a 'python setup.py develop' installation type. Let's # discover the version information at runtime. import os import warnings import subprocess if 'SETUP_DIRNAME' in globals(): # This is from the exec() call in Salt Fuse's setup.py cwd = SETUP_DIRNAME # pylint: disable=E0602 if not os.path.exists(os.path.join(cwd, '.git')): # This is not a Salt Fuse git checkout!!! Don't even try to parse... return version, version_info else: cwd = os.path.abspath(os.path.dirname(__file__)) if not os.path.exists(os.path.join(os.path.dirname(cwd), '.git')): # This is not a Salt git checkout!!! Don't even try to parse... return version, version_info try: kwargs = dict( stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd ) if not sys.platform.startswith('win'): # Let's not import `salt.utils` for the above check kwargs['close_fds'] = True process = subprocess.Popen( ['git', 'describe', '--tags', '--match', 'v[0-9]*'], **kwargs) out, err = process.communicate() out = out.strip() err = err.strip() if not out or err: return version, version_info parsed_version = SaltStackVersion.parse(out) if parsed_version.info > version_info: warnings.warn( 'The parsed version info, `{0}`, is bigger than the one ' 'defined in the file, `{1}`. Missing version bump?'.format( parsed_version.info, version_info ), UserWarning, stacklevel=2 ) return version, version_info elif parsed_version.info < version_info: warnings.warn( 'The parsed version info, `{0}`, is lower than the one ' 'defined in the file, `{1}`.' 'In order to get the proper salt version with the git hash ' 'you need to update salt\'s local git tags. Something like: ' '\'git fetch --tags\' or \'git fetch --tags upstream\' if ' 'you followed salt\'s contribute documentation. The version ' 'string WILL NOT include the git hash.'.format( parsed_version.info, version_info ), UserWarning, stacklevel=2 ) return version, version_info return parsed_version.string, parsed_version.info except OSError as os_err: if os_err.errno != 2: # If the errno is not 2(The system cannot find the file # specified), raise the exception so it can be catch by the # developers raise return version, version_info
def test_unparsable_version(self): with self.assertRaises(ValueError): SaltStackVersion.from_name('Drunk') with self.assertRaises(ValueError): SaltStackVersion.parse('Drunk')
def check_bootstrapped_minion_version(options): ''' Confirm that the bootstrapped minion version matches the desired one ''' if 'salt_minion_bootstrapped' not in options: print_bulleted(options, 'Minion not boostrapped. Not grabbing minion version information.', 'RED') sys.exit(1) print_bulleted(options, 'Grabbing bootstrapped minion version information ... ') cmd = [ 'salt', '-t', '100', '--out=json', '-l', options.log_level ] if options.no_color: cmd.append('--no-color') cmd.extend([ options.vm_name, 'test.version' ]) stdout, stderr, exitcode = run_command(cmd, options, return_output=True, stream_stdout=False, stream_stderr=False) if exitcode: print_bulleted( options, 'Failed to get the bootstrapped minion version. Exit code: {0}'.format(exitcode), 'RED' ) sys.exit(exitcode) if not stdout.strip(): print_bulleted(options, 'Failed to get the bootstrapped minion version(no output).', 'RED') sys.stdout.flush() sys.exit(1) try: version_info = json.loads(stdout.strip()) bootstrap_minion_version = os.environ.get( 'SALT_MINION_BOOTSTRAP_RELEASE', options.bootstrap_salt_commit[:7] ) if bootstrap_minion_version.startswith('v'): bootstrap_minion_version = bootstrap_minion_version[1:] if bootstrap_minion_version not in version_info[options.vm_name]: print_bulleted(options, '\n\nATTENTION!!!!\n', 'YELLOW') print_bulleted( options, 'The boostrapped minion version commit does not contain the desired commit:', 'YELLOW' ) print_bulleted( options, '{0!r} does not contain {1!r}'.format(version_info[options.vm_name], bootstrap_minion_version), 'YELLOW' ) print('\n\n') sys.stdout.flush() else: print_bulleted(options, 'Matches!', 'LIGHT_GREEN') setattr(options, 'bootstrapped_salt_minion_version', SaltStackVersion.parse(version_info[options.vm_name])) except (ValueError, TypeError): print_bulleted(options, 'Failed to load any JSON from {0!r}'.format(stdout.strip()), 'RED')