Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

validation through entry point + reorg of the arg space #68

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions PantheonCMD/pcchecks.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class Regex:
"""Define regular expresiions for the checks."""

INCLUDE = re.compile(r'include::.*\]\n')
INCLUDED_CONTENT = re.compile(r'(?<=include::).*?(?=\[)')
MODULE_TYPE = re.compile(r':_module-type: (PROCEDURE|CONCEPT|REFERENCE)')
PREFIX_ASSEMBLIES = re.compile(r'.*\/assembly.*\.adoc')
PREFIX_MODULES = re.compile(r'.*\/con.*\.adoc|.*\/proc.*\.adoc|.*\/ref.*\.adoc')
Expand Down
126 changes: 126 additions & 0 deletions PantheonCMD/pcentrypointvalidator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#!/usr/bin/python3

import argparse
import re
import os
from pcchecks import Regex
import sys
from pcutil import get_exist, get_not_exist
from pcprvalidator import get_no_prefix_files, get_all_modules, get_all_assemblies, get_undetermined_files
from pcvalidator import validation
from pcmsg import print_message, print_report_message

parser = argparse.ArgumentParser()


def get_nonexisting_entry_points(entry_point_list):
nonexistent_files = get_not_exist(entry_point_list)

if nonexistent_files:
print_message(nonexistent_files, 'entry point', 'does not exist in your repository')
sys.exit(2)


def get_includes(entry_points):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might run into a similar problem I encountered with the coalescing function here.

Namely, some users use attributes in their includes - and nested ones at that. As such, unless you go through and resolve the entire attribute tree, attempting to convert an include into an actual path sometimes fails.

How would you feel about a pared down version of the coalescing loop to still work with attributes and iterate through levels of content?

path_to_includes = []

for entry in entry_points:
path_to_entry_point = os.path.dirname(os.path.abspath(entry))

with open(entry, 'r') as file:
original = file.read()
stripped = Regex.MULTI_LINE_COMMENT.sub('', original)
stripped = Regex.SINGLE_LINE_COMMENT.sub('', stripped)

included_files = re.findall(Regex.INCLUDED_CONTENT, stripped)

if included_files:

for include in included_files[:]:
if include.startswith('_'):
included_files.remove(include)

for i in included_files:
path_to_includes.append(os.path.join(path_to_entry_point, i))

return path_to_includes


def get_level_one_includes(files):
path_to_level_one_includes = get_includes(files)

return path_to_level_one_includes


def get_level_two_includes(files):
path_to_level_two_includes = get_includes(files)

return path_to_level_two_includes


def get_level_three_includes(files):
path_to_level_three_includes = get_includes(files)

return path_to_level_three_includes


def get_level_four_includes(files):
path_to_level_four_includes = get_includes(files)

return path_to_level_four_includes


def get_concatenated_includes(entry_point_list):
existing_entry_points = get_exist(entry_point_list)
level_one_includes = get_level_one_includes(existing_entry_points)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These functions are acting as wrappers for a single command today.

If you'd like to keep this format, perhaps this chain can be simplified to something similar to the following -

level_one_includes = get_includes(existing_entry_points)
level_two_includes = get_includes(level_one_includes)
...

level_two_includes = get_level_two_includes(level_one_includes)
level_three_includes = get_level_three_includes(level_two_includes)
level_four_includes = get_level_four_includes(level_three_includes)
no_prefix_level_four_includes = get_no_prefix_files(level_four_includes)
level_four_modules = get_all_modules(level_four_includes, no_prefix_level_four_includes)
level_four_assemblies = get_all_assemblies(level_four_includes, no_prefix_level_four_includes)

all_includes = level_one_includes + level_two_includes + level_three_includes + level_four_modules

return all_includes, level_four_assemblies


def get_level_four_assemblies(entry_point_list):
all_includes, level_four_assemblies = get_concatenated_includes(entry_point_list)

return level_four_assemblies


def get_all_includes(entry_point_list):
all_includes, level_four_assemblies = get_concatenated_includes(entry_point_list)

for entry in entry_point_list:
if not entry.endswith('master.adoc'):
all_includes = all_includes + entry_point_list

for include in all_includes:
if os.path.basename(include).startswith('_'):
all_includes.remove(include)

return all_includes


def validate_entry_point_files(entry_point_list):
# exit if entry point doesn't exist
get_nonexisting_entry_points(entry_point_list)
existing_entry_points = get_exist(entry_point_list)
includes = get_all_includes(entry_point_list)
no_prefix_files = get_no_prefix_files(includes)
modules_found = get_all_modules(includes, no_prefix_files)
assemblies_found = get_all_assemblies(includes, no_prefix_files)
undetermined_file_type = get_undetermined_files(no_prefix_files)
level_four_assemblies = get_level_four_assemblies(existing_entry_points)

if level_four_assemblies:
print_message(level_four_assemblies, 'entry point', 'contains unsupported level of nesting for the following files')

if undetermined_file_type:
print_message(undetermined_file_type, 'entry point', 'contains the following files that can not be classified as modules or assemblies')

validate = validation(includes, modules_found, assemblies_found)
print_report_message(validate, 'entry point')
78 changes: 14 additions & 64 deletions PantheonCMD/pcmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
import sys

from pcutil import PantheonRepo, get_not_exist, get_exist, is_pantheon_repo
from pcvalidator import validation
from pcvalidator import validate_build_files
from pcyamlchecks import yaml_validation
from subprocess import call
from pcprvalidator import get_changed_files, get_all_modules, get_all_assemblies, get_undetermined_files, get_no_prefix_files

from pcprvalidator import validate_merge_request_files
from pcentrypointvalidator import validate_entry_point_files
from pcmsg import print_message, print_report_message


def print_header():
Expand Down Expand Up @@ -47,6 +48,7 @@ def parse_args():
# 'Validate' command
parser_d = subparsers.add_parser('validate', help='Validate entries in your pantheon2.yml file.')
parser_d.add_argument('--mr', action='store_true', help='Validate files commited on a merge request.')
parser_d.add_argument('--e', nargs=1, help='Validate files from an entry point.')

# 'Generate' command
parser_e = subparsers.add_parser('generate', help='Generate pantheon2.yml file from a template.')
Expand Down Expand Up @@ -76,66 +78,24 @@ def parse_args():
# validate modules and assemblies
elif args.command == 'validate':

if args.mr:

changed_files = get_changed_files()
files_found = get_exist(changed_files)
no_prefix_files = get_no_prefix_files(files_found)
modules_found = get_all_modules(files_found, no_prefix_files)
assemblies_found = get_all_assemblies(files_found, no_prefix_files)
undetermined_file_type = get_undetermined_files(no_prefix_files)

if undetermined_file_type:
print("\nYour Merge Request contains the following files that can not be classified as modules or assemblies:\n")
# user provides paths to files that are relative to current pwd

for file in undetermined_file_type:
if args.e:
entry_point_list = args.e
validate_entry_point_files(entry_point_list)

print('\t' + file)
elif args.mr:

print("\nTotal: ", str(len(undetermined_file_type)))
validate_merge_request_files()

validate = validation(files_found, modules_found, assemblies_found)

if validate.count != 0:
print("\nYour Merge Request contains the following files that did not pass validation:\n")
validate.print_report()
sys.exit(2)
else:
print("All files passed validation.")
sys.exit(0)
else:

pantheon_repo = PantheonRepo(repo_location)

if os.path.exists('pantheon2.yml'):

# call yaml file validation + attribute file validation
yaml_validation('pantheon2.yml')

exists = get_not_exist(pantheon_repo.get_content())

if exists:

print("\nYour pantheon2.yml contains the following files that do not exist in your repository:\n")

for exist in exists:

print('\t' + exist)

print("\nTotal: ", str(len(exists)))

files_found = get_exist(pantheon_repo.get_content())
modules_found = pantheon_repo.get_existing_content("modules")
assemblies_found = pantheon_repo.get_existing_content("assemblies")

validate = validation(files_found, modules_found, assemblies_found)

if validate.count != 0:
print("\nYour pantheon2.yml contains the following files that did not pass validation:\n")
validate.print_report()
sys.exit(2)
else:
print("All files passed validation.")
validate_build_files()

else:

Expand All @@ -154,15 +114,11 @@ def parse_args():
# Action - preview
if args.command == 'preview':

# Validate the pantheon2.yml file
yaml_validation(pantheon_repo.yaml_file_location)

# Set the output format
if args.format == 'pdf':
output_format = 'pdf'
else:
output_format = 'html'

# Did a user specify a set of files? If so, only build those.
if args.files:
# Handle different interpretations of directories
Expand Down Expand Up @@ -215,13 +171,7 @@ def parse_args():
duplicates = pantheon_repo.get_duplicates()

if duplicates:

print("Your pantheon2.yml contains the following duplicate entries:\n")

for duplicate in duplicates:
print(duplicate)

print("\nTotal: ", str(len(duplicates)))
print_message(duplicates, 'pantheon2.yml', 'contains the following duplicate entries')

else:

Expand Down
45 changes: 45 additions & 0 deletions PantheonCMD/pcmsg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/python3

import sys


class Report():
"""Create and print report. thank u J."""

def __init__(self):
"""Create placeholder for problem description."""
self.report = {}
self.count = 0

def create_report(self, category, file_path):
"""Generate report."""
self.count += 1
if not category in self.report:
self.report[category] = []
self.report[category].append(file_path)

def print_report(self):

"""Print report."""
separator = "\n\t"

for category, files in self.report.items():
print("\nERROR: {} found in the following files:".format(category))
print('\t' + separator.join(files))


def print_message(variable, specification, msg):
print(f'\nYour {specification} {msg}:\n')
for var in variable:
print('\t', var)
print("\nTotal: ", str(len(variable)))


def print_report_message(variable, specification):
if variable.count != 0:
print(f"\nYour {specification} contains the following files that did not pass validation:\n")
variable.print_report()
sys.exit(2)
else:
print("All files passed validation.")
sys.exit(0)
30 changes: 29 additions & 1 deletion PantheonCMD/pcprvalidator.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
from pygit2 import Repository
import os
import sys
import subprocess
import re
from pcchecks import Regex
from pcvalidator import validation
from pcmsg import print_message, print_report_message
from pcutil import get_exist


if subprocess.call(["git", "branch"], stderr=subprocess.STDOUT, stdout=open(os.devnull, 'w')) != 0:
Expand All @@ -16,6 +18,15 @@
current_branch = Repository('.').head.shorthand


def get_mr():
if current_branch == 'master':
print('On master. Exiting...')
sys.exit(1)
elif current_branch == 'main':
print('On main. Exiting...')
sys.exit(1)


def get_changed_files():
"""Return a list of the files that werre change on the PR."""

Expand Down Expand Up @@ -121,3 +132,20 @@ def get_undetermined_files(no_prefix_files):
no_prefix_module_type, no_prefix_assembly_type, undetermined_file_type = get_no_prefefix_file_type(no_prefix_files)

return(sorted(undetermined_file_type, key=str.lower))


def validate_merge_request_files():
get_mr()
changed_files = get_changed_files()
files_found = get_exist(changed_files)
no_prefix_files = get_no_prefix_files(files_found)
modules_found = get_all_modules(files_found, no_prefix_files)
assemblies_found = get_all_assemblies(files_found, no_prefix_files)
undetermined_file_type = get_undetermined_files(no_prefix_files)

if undetermined_file_type:
print_message(undetermined_file_type, 'Merge Request', 'contains the following files that can not be classified as modules or assemblies')

validate = validation(files_found, modules_found, assemblies_found)

print_report_message(validate, 'Merge Request')
Loading