def test_new_item_mismatches_global_list_with_extra(self): # If the global list has multiple entries for an item with # different "extra" specifiers, the values must all be in the # requirements file. r_content = textwrap.dedent(""" name>=1.5;python_version=='3.6' name>=1.2,!=1.4;python_version=='2.6' """) reqs = [r for r, line in requirement.parse(r_content)['name']] branch_reqs = check.RequirementsList( 'testproj', {'requirements': { 'requirements.txt': '' }}, ) branch_reqs.process(False) global_reqs = check.get_global_reqs( textwrap.dedent(""" name>=1.5;python_version=='3.5' name>=1.2,!=1.4;python_version=='2.6' """)) self.assertTrue( check._validate_one( 'name', reqs=reqs, branch_reqs=branch_reqs, blacklist=requirement.parse(''), global_reqs=global_reqs, ))
def test_constraints_with_markers(self): constraints_content = textwrap.dedent(""" name==1.1;python_version=='2.7' name==2.0;python_version=='3.5' name==2.0;python_version=='3.6' """) project_data = { 'requirements': { 'requirements.txt': textwrap.dedent(""" name>=1.1,!=1.2;python_version=='2.7' name>=2.0;python_version=='3.5' name>=2.0;python_version=='3.6' """), }, 'lower-constraints.txt': constraints_content, } head_reqs = check.RequirementsList('testproj', project_data) head_reqs.process(False) self.assertFalse( check.validate_lower_constraints( req_list=head_reqs, constraints=project_data['lower-constraints.txt'], blacklist=requirement.parse(''), ))
def test_no_constraints_file(self): constraints_content = None project_data = { 'requirements': { 'requirements.txt': 'name>=1.2,!=1.4' }, 'lower-constraints.txt': constraints_content, } head_reqs = check.RequirementsList('testproj', project_data) head_reqs.process(False) self.assertFalse( check.validate_lower_constraints( req_list=head_reqs, constraints=project_data['lower-constraints.txt'], blacklist=requirement.parse(''), ))
def test_constrained_version_excluded(self): constraints_content = textwrap.dedent(""" name==1.2 """) project_data = { 'requirements': { 'requirements.txt': 'name>=1.1,!=1.2' }, 'lower-constraints.txt': constraints_content, } head_reqs = check.RequirementsList('testproj', project_data) head_reqs.process(False) self.assertTrue( check.validate_lower_constraints( req_list=head_reqs, constraints=project_data['lower-constraints.txt'], blacklist=requirement.parse(''), ))
def test_new_item_matches_global_list(self): # If the new item matches the global list exactly that is OK. reqs = [r for r, line in requirement.parse('name>=1.2,!=1.4')['name']] branch_reqs = check.RequirementsList( 'testproj', {'requirements': { 'requirements.txt': '' }}, ) branch_reqs.process(False) global_reqs = check.get_global_reqs('name>=1.2,!=1.4') self.assertFalse( check._validate_one( 'name', reqs=reqs, branch_reqs=branch_reqs, blacklist=requirement.parse(''), global_reqs=global_reqs, ))
def test_not_in_global_list(self): # If the package is not in the global list, that is an error. reqs = [r for r, line in requirement.parse('name>=1.2,!=1.4')['name']] branch_reqs = check.RequirementsList( 'testproj', {'requirements': { 'requirements.txt': 'name>=1.2,!=1.4' }}, ) branch_reqs.process(False) global_reqs = check.get_global_reqs('') self.assertTrue( check._validate_one( 'name', reqs=reqs, branch_reqs=branch_reqs, blacklist=requirement.parse(''), global_reqs=global_reqs, ))
def test_blacklisted(self): # If the package is blacklisted, everything is OK. reqs = [r for r, line in requirement.parse('name>=1.2,!=1.4')['name']] branch_reqs = check.RequirementsList( 'testproj', {'requirements': { 'requirements.txt': 'name>=1.2,!=1.4' }}, ) branch_reqs.process(False) global_reqs = check.get_global_reqs('name>=1.2,!=1.4') self.assertFalse( check._validate_one( 'name', reqs=reqs, branch_reqs=branch_reqs, blacklist=requirement.parse('name'), global_reqs=global_reqs, ))
def test_new_item_missing_exclusion(self): # If the new item does not include an exclusion that is # present in the global list that is OK. reqs = [r for r, line in requirement.parse('name>=1.2')['name']] branch_reqs = check.RequirementsList( 'testproj', {'requirements': { 'requirements.txt': '' }}, ) branch_reqs.process(False) global_reqs = check.get_global_reqs('name>=1.2,!=1.4') self.assertFalse( check._validate_one( 'name', reqs=reqs, branch_reqs=branch_reqs, blacklist=requirement.parse(''), global_reqs=global_reqs, ))
def test_new_item_lower_min(self): # If the new item has a lower minimum value than the global # list, that is OK. reqs = [r for r, line in requirement.parse('name>=1.1,!=1.4')['name']] branch_reqs = check.RequirementsList( 'testproj', {'requirements': { 'requirements.txt': '' }}, ) branch_reqs.process(False) global_reqs = check.get_global_reqs('name>=1.2,!=1.4') self.assertFalse( check._validate_one( 'name', reqs=reqs, branch_reqs=branch_reqs, blacklist=requirement.parse(''), global_reqs=global_reqs, ))
def test_blacklisted_mismatch(self): # If the package is blacklisted, it doesn't matter if the # version matches. reqs = [r for r, line in requirement.parse('name>=1.5')['name']] branch_reqs = check.RequirementsList( 'testproj', {'requirements': { 'requirements.txt': 'name>=1.2,!=1.4' }}, ) branch_reqs.process(False) global_reqs = check.get_global_reqs('name>=1.2,!=1.4') self.assertFalse( check._validate_one( 'name', reqs=reqs, branch_reqs=branch_reqs, blacklist=requirement.parse('name'), global_reqs=global_reqs, ))
def test_complex_marker_evaluation(self): constraints_content = textwrap.dedent(""" name===0.8.0;python_version=='2.7' name===1.0.0;python_version>='3.0' """) project_data = { 'requirements': { 'requirements.txt': textwrap.dedent(""" name>=0.8.0;python_version<'3.0' # BSD name>=1.0.0;python_version>='3.0' # BSD """), }, 'lower-constraints.txt': constraints_content, } head_reqs = check.RequirementsList('testproj', project_data) head_reqs.process(False) self.assertFalse( check.validate_lower_constraints( req_list=head_reqs, constraints=project_data['lower-constraints.txt'], blacklist=requirement.parse(''), ))
def main(): args = grab_args() branch = args.branch os.chdir(args.src_dir) reqdir = args.reqs print(sys.version_info) if reqdir is None: if args.local: print('selecting default requirements directory for local mode') reqdir = os.path.dirname( os.path.dirname(os.path.dirname(sys.argv[0]))) else: print('selecting default requirements directory for normal mode') reqdir = _DEFAULT_REQS_DIR print('Branch: {}'.format(branch)) print('Source: {}'.format(args.src_dir)) print('Requirements: {}'.format(reqdir)) sha, _ = run_command('git log -n 1 --format=%H') print('Patch under test: {}'.format(sha)) # build a list of requirements from the global list in the # openstack/requirements project so we can match them to the changes with tempdir() as reqroot: install_and_load_requirements(reqroot, reqdir) with open(reqdir + '/global-requirements.txt', 'rt') as f: global_reqs = check.get_global_reqs(f.read()) blacklist = requirement.parse( open(reqdir + '/blacklist.txt', 'rt').read()) cwd = os.getcwd() # build a list of requirements in the proposed change, # and check them for style violations while doing so head_proj = project.read(cwd) head_reqs = check.RequirementsList(sha, head_proj) # Don't apply strict parsing rules to stable branches. # Reasoning is: # - devstack etc protect us from functional issues # - we're backporting to stable, so guarding against # aesthetics and DRY concerns is not our business anymore # - if in future we have other not-functional linty style # things to add, we don't want them to affect stable # either. head_strict = not branch.startswith('stable/') head_reqs.process(strict=head_strict) failed = check.validate(head_reqs, blacklist, global_reqs) failed = (check.validate_lower_constraints( head_reqs, head_proj['lower-constraints.txt'], blacklist, ) or failed) # report the results if failed or head_reqs.failed: print("*** Incompatible requirement found!") print("*** See http://docs.openstack.org/developer/requirements") sys.exit(1) print("Updated requirements match openstack/requirements.")
def main(): args = grab_args() branch = args.branch os.chdir(args.src_dir) reqdir = args.reqs if reqdir is None: if args.local: reqdir = os.path.dirname( os.path.dirname( os.path.dirname(sys.argv[0]))) else: reqdir = _DEFAULT_REQS_DIR # build a list of requirements from the global list in the # openstack/requirements project so we can match them to the changes with tempdir() as reqroot: install_and_load_requirements(reqroot, reqdir) with open(reqdir + '/global-requirements.txt', 'rt') as f: global_reqs = check.get_global_reqs(f.read()) blacklist = requirement.parse( open(reqdir + '/blacklist.txt', 'rt').read()) cwd = os.getcwd() # build a list of requirements in the proposed change, # and check them for style violations while doing so head_proj = project.read(cwd) head_reqs = check.RequirementsList('HEAD', head_proj) # Don't apply strict parsing rules to stable branches. # Reasoning is: # - devstack etc protect us from functional issues # - we're backporting to stable, so guarding against # aesthetics and DRY concerns is not our business anymore # - if in future we have other not-functional linty style # things to add, we don't want them to affect stable # either. head_strict = not branch.startswith('stable/') head_reqs.process(strict=head_strict) if not args.local: # build a list of requirements already in the target branch, # so that we can create a diff and identify what's being changed run_command("git checkout HEAD^1") branch_proj = project.read(cwd) # switch back to the proposed change now run_command("git checkout %s" % branch) else: branch_proj = {'root': cwd} branch_reqs = check.RequirementsList(branch, branch_proj) # Don't error on the target branch being broken. branch_reqs.process(strict=False) failed = check.validate(head_reqs, branch_reqs, blacklist, global_reqs) failed = ( check.validate_lower_constraints( head_reqs, head_proj['lower-constraints.txt'], blacklist, ) or failed ) # report the results if failed or head_reqs.failed or branch_reqs.failed: print("*** Incompatible requirement found!") print("*** See http://docs.openstack.org/developer/requirements") sys.exit(1) print("Updated requirements match openstack/requirements.")