Re-enable module comparisons in validate-modules (#21582)

* Re-enable module comparisons, specifically for new module detection and for finding new options/arguments
* Only do new module checks in shippable, local will display warning
pull/4420/head
Matt Martz 2017-02-17 17:13:18 -06:00 committed by Matt Clay
parent b3b76826e5
commit 9b1bd2eb7e
2 changed files with 56 additions and 14 deletions

View File

@ -796,6 +796,13 @@ def command_sanity_validate_modules(args, targets):
if skip_paths: if skip_paths:
cmd += ['--exclude', '^(%s)' % '|'.join(skip_paths)] cmd += ['--exclude', '^(%s)' % '|'.join(skip_paths)]
if is_shippable():
cmd.extend([
'--base-branch', os.environ['BASE_BRANCH']
])
else:
display.warning("Cannot perform module comparison against the base branch when running locally")
run_command(args, cmd, env=env) run_command(args, cmd, env=env)

View File

@ -24,7 +24,9 @@ import argparse
import ast import ast
import os import os
import re import re
import subprocess
import sys import sys
import tempfile
from distutils.version import StrictVersion from distutils.version import StrictVersion
from fnmatch import fnmatch from fnmatch import fnmatch
@ -134,7 +136,7 @@ class ModuleValidator(Validator):
'setup.ps1' 'setup.ps1'
)) ))
def __init__(self, path, analyze_arg_spec=False): def __init__(self, path, analyze_arg_spec=False, base_branch=None):
super(ModuleValidator, self).__init__() super(ModuleValidator, self).__init__()
self.path = path self.path = path
@ -143,6 +145,8 @@ class ModuleValidator(Validator):
self.analyze_arg_spec = analyze_arg_spec self.analyze_arg_spec = analyze_arg_spec
self.base_branch = base_branch
self._python_module_override = False self._python_module_override = False
with open(path) as f: with open(path) as f:
@ -153,6 +157,23 @@ class ModuleValidator(Validator):
except: except:
self.ast = None self.ast = None
if base_branch:
self.base_module = self._get_base_file()
else:
self.base_module = None
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
if not self.base_module:
return
try:
os.remove(self.base_module)
except:
pass
@property @property
def object_name(self): def object_name(self):
return self.basename return self.basename
@ -180,12 +201,22 @@ class ModuleValidator(Validator):
except AttributeError: except AttributeError:
return False return False
def _get_base_file(self):
command = ['git', 'show', '%s:%s' % (self.base_branch, self.path)]
p = subprocess.Popen(command, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if int(p.returncode) != 0:
return None
t = tempfile.NamedTemporaryFile(delete=False)
t.write(stdout)
t.close()
return t.name
def _is_new_module(self): def _is_new_module(self):
if self.name.startswith("_") and not os.path.islink(self.name): return self.base_branch and not bool(self.base_module)
# This is a deprecated module, so look up the *old* name
return not module_loader.has_plugin(self.name[1:])
else:
return not module_loader.has_plugin(self.name)
def _check_interpreter(self, powershell=False): def _check_interpreter(self, powershell=False):
if powershell: if powershell:
@ -549,8 +580,7 @@ class ModuleValidator(Validator):
with CaptureStd(): with CaptureStd():
try: try:
existing = module_loader.find_plugin(self.name, mod_type='.py') existing_doc, _, _, _ = get_docstring(self.base_module, verbose=True)
existing_doc, _, _, _ = get_docstring(existing, verbose=True)
existing_options = existing_doc.get('options', {}) existing_options = existing_doc.get('options', {})
except AssertionError: except AssertionError:
fragment = doc['extends_documentation_fragment'] fragment = doc['extends_documentation_fragment']
@ -712,6 +742,9 @@ def main():
type=re_compile) type=re_compile)
parser.add_argument('--arg-spec', help='Analyze module argument spec', parser.add_argument('--arg-spec', help='Analyze module argument spec',
action='store_true', default=False) action='store_true', default=False)
parser.add_argument('--base-branch', default=None,
help='Used in determining if new options were added')
args = parser.parse_args() args = parser.parse_args()
args.modules[:] = [m.rstrip('/') for m in args.modules] args.modules[:] = [m.rstrip('/') for m in args.modules]
@ -723,9 +756,10 @@ def main():
path = module path = module
if args.exclude and args.exclude.search(path): if args.exclude and args.exclude.search(path):
sys.exit(0) sys.exit(0)
mv = ModuleValidator(path, analyze_arg_spec=args.arg_spec) with ModuleValidator(path, analyze_arg_spec=args.arg_spec,
mv.validate() base_branch=args.base_branch) as mv:
exit.append(mv.report(args.warnings)) mv.validate()
exit.append(mv.report(args.warnings))
for root, dirs, files in os.walk(module): for root, dirs, files in os.walk(module):
basedir = root[len(module)+1:].split('/', 1)[0] basedir = root[len(module)+1:].split('/', 1)[0]
@ -745,9 +779,10 @@ def main():
path = os.path.join(root, filename) path = os.path.join(root, filename)
if args.exclude and args.exclude.search(path): if args.exclude and args.exclude.search(path):
continue continue
mv = ModuleValidator(path, analyze_arg_spec=args.arg_spec) with ModuleValidator(path, analyze_arg_spec=args.arg_spec,
mv.validate() base_branch=args.base_branch) as mv:
exit.append(mv.report(args.warnings)) mv.validate()
exit.append(mv.report(args.warnings))
sys.exit(sum(exit)) sys.exit(sum(exit))