packages/python-packages/doc-warden/warden/WardenConfiguration.py (197 lines of code) (raw):

# Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. from __future__ import print_function import argparse import yaml import os class WardenConfiguration(): REPOSITORY_SETS = { # 0 = groupId 'java': { 'TestUrl': 'https://oss.sonatype.org/content/repositories/releases/[0]/{package_id}/{package_version}/{package_id}-{package_version}.pom', 'TestUrlTransformationFunction': lambda input_string: input_string.replace('.','/'), 'URL': 'https://search.maven.org/artifact/[0]/{package_id}', 'UrlTransformationFunction': lambda input_string: input_string, 'Text': 'Maven', }, 'python': { 'URL': 'https://pypi.org/project/{package_id}', 'Text': 'PyPI' }, 'js': { 'URL': 'https://www.npmjs.com/package/{package_id}', 'Text': 'NPM' }, 'net': { 'URL': 'https://www.nuget.org/packages/{package_id}/', 'Text': '![{package_id}](https://img.shields.io/nuget/vpre/{package_id}.svg)' } } def __init__(self): parser = argparse.ArgumentParser(description ='''\ Scan an azure-sdk repo and ensure that readmes are present and have appropriate content. This check is done by convention, which is why there is the --scan-language option exists. For normal/CI usage, a .docsettings file should be present in the repository root, to allow for visible configuration of all the options. ''') parser.add_argument( '-d', '--scan-directory', dest = 'scan_directory', help = 'The directory on a repo that this tool should be scanning.', required = True) parser.add_argument( '-u', '--repo-root', dest = 'repo_root', help = 'The root of the repo', required = False) parser.add_argument( '-c', '--config-location', dest = 'config_location', required = False, help = ''' If provided, will replace the repo native .docsettings file with a .docsettings file found at the location provided by this input. ''') parser.add_argument( '-p', '--package-output', dest = 'package_output_location', required = False, help = ''' If provided, will replace the root packages.md file output location with the location provided by this input. ''') parser.add_argument( '-l', '--scan-language', dest = 'scan_language', required = False, help = 'The language contained within the target directory. Overrides .docsettings contents.') parser.add_argument( '-r', '--root-check-enabled', dest = 'root_check_enabled', required = False, help = 'Enable or disable checking for a readme at the root of the repository. Defaults true. Overrides .docsettings contents.') parser.add_argument( '-s', '--pipeline-stage', choices=['release', 'pr', 'ci'], dest = 'pipeline_stage', required = False, help = 'Specify the stage of the pipeline. Used to provide conditional functionality depending on the stage of the pipeline') parser.add_argument( '-t', '--target', choices=['all','readme','changelog'], dest = 'target', required = False, help = 'The file name to scan for; "`readme` or `changelog`" or specify `all` to scan for both. Will default to `readme`') parser.add_argument( '-o', '--verbose-output', action="store_true", dest = 'verbose_output', required = False, help = 'Enable or disable verbose output. Defaults false. Overrides .docsettings contents.') parser.add_argument( 'command', help = ('The warden command to run.')) args = parser.parse_args() self.command = args.command self.target_directory = args.scan_directory self.repo_root = args.repo_root or self.target_directory self.yml_location = args.config_location or os.path.join(self.repo_root, '.docsettings.yml') self.package_index_output_location = args.package_output_location or os.path.join(self.repo_root, 'packages.md') self.target = args.target or 'default' self.target_files = [] with open(self.yml_location, 'r') as f: try: doc = yaml.safe_load(f) except err: print('Unable to parse .docsettings. Check the location of the file.') try: self.omitted_paths = doc['omitted_paths'] or [] except: self.omitted_paths = [] try: self.package_indexing_exclusion_list = doc['package_indexing_exclusion_list'] or [] except: self.package_indexing_exclusion_list = [] try: self.package_indexing_traversal_stops = doc['package_indexing_traversal_stops'] or [] except: self.package_indexing_traversal_stops = [] try: self.required_readme_sections = doc['required_readme_sections'] or [] except: self.required_readme_sections = [] self.pipeline_stage = args.pipeline_stage or '' try: self.known_content_issues = doc['known_content_issues'] or [] except: self.known_content_issues = [] try: self.known_presence_issues = doc['known_presence_issues'] or [] except: self.known_presence_issues = [] try: self.scan_language = args.scan_language or doc['language'] except: print('.docsettings has no selected language, neither has the --scan-language parameter been populated. Exiting.') exit(1) if self.target == 'changelog': self.target_files = ['history.rst', 'history.md'] if self.scan_language == 'python' else ['changelog.md'] elif self.target == 'readme': self.target_files = ['readme.rst', 'readme.md'] if self.scan_language == 'python' else ['readme.md'] try: settings_file_root_check = doc['root_check_enabled'] except: settings_file_root_check = False self.root_check_enabled = args.root_check_enabled or settings_file_root_check or True try: settings_file_verbose_output = doc['verbose_output'] except: settings_file_verbose_output = False self.verbose_output = args.verbose_output or settings_file_verbose_output or False # strips the directory up till the repo root. Allows us to easily think about # relative paths instead of absolute on disk def get_output_path(self, input_path): return input_path.replace(os.path.normpath(self.repo_root), '') def get_known_presence_issues(self): known_issue_paths = [] for exception_tuple in self.known_presence_issues: if any(exception_tuple[0].lower().endswith(target_file) for target_file in self.target_files): known_issue_paths.append(os.path.normpath(os.path.join(self.repo_root, os.path.dirname(exception_tuple[0])))) elif any(target_file.startswith('readme') for target_file in self.target_files): known_issue_paths.append(os.path.normpath(os.path.join(self.repo_root, exception_tuple[0]))) return known_issue_paths def get_known_content_issues(self): known_issue_paths = [] for exception_tuple in self.known_content_issues: if any(exception_tuple[0].lower().endswith(target_file) for target_file in self.target_files): known_issue_paths.append(os.path.normpath(os.path.join(self.repo_root, exception_tuple[0]))) return known_issue_paths def get_package_indexing_traversal_stops(self): return [os.path.normpath(os.path.join(self.repo_root, traversal_stop)) for traversal_stop in self.package_indexing_traversal_stops] def get_repository_details(self): return WardenConfiguration.REPOSITORY_SETS[self.scan_language] def dump(self): current_config = { 'command': self.command, 'target_directory': self.target_directory, 'repo_root': self.repo_root, 'yml_location': self.yml_location, 'omitted_paths': self.omitted_paths, 'package_indexing_exclusion_list': self.package_indexing_exclusion_list, 'package_indexing_traversal_stops': self.package_indexing_traversal_stops, 'scan_language': self.scan_language, 'root_check_enabled': self.root_check_enabled, 'verbose_output': self.verbose_output, 'target_files' : self.target_files, 'required_readme_sections': self.required_readme_sections, 'known_content_issues': self.known_content_issues, 'known_presence_issues': self.known_presence_issues } print("Warden configuration this run:") for key in current_config: print('{0}: {1}'.format(key, current_config[key])) return current_config