-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #22 from cmpsc-481-s22-m1/release/0.1.0
Release/0.1.0
- Loading branch information
Showing
25 changed files
with
1,413 additions
and
114 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
--- | ||
name: New Feature | ||
about: Task for team members to complete | ||
title: '' | ||
labels: '' | ||
assignees: '' | ||
|
||
--- | ||
|
||
**What is the task** | ||
A clear and concise description of what the task is | ||
|
||
**Describe the solution you'd like** | ||
A clear and concise description of what you want to happen. | ||
|
||
**Additional context** | ||
Add any other context or screenshots about the feature request here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
[MASTER] | ||
|
||
# A comma-separated list of package or module names from where C extensions may | ||
# be loaded. Extensions are loading into the active Python interpreter and may | ||
# run arbitrary code. (This is an alternative name to extension-pkg-allow-list | ||
# for backward compatibility.) | ||
extension-pkg-whitelist=PyQt5 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,59 @@ | ||
# project-team-4 | ||
|
||
# team4-GatorConfig | ||
|
||
A simple Python project utilizing a CLI approach to automate generating | ||
configuration files for GatorGrader. The GitHub Actions workflow executes | ||
[pytest](https://pytest.org/) (with | ||
[coverage](https://pypi.org/project/pytest-cov/)) and | ||
[pylint](https://pylint.org/) using the Poetry configuration, and checks | ||
markdown with [markdownlint](https://github.com/DavidAnson/markdownlint) and | ||
spelling with [cspell](https://cspell.org/). | ||
|
||
## Requirements | ||
|
||
- [Python](https://realpython.com/installing-python/) | ||
- [Pipx](https://pypa.github.io/pipx/installation/) | ||
- [Poetry](https://python-poetry.org/docs/#installing-with-pipx) | ||
|
||
## Usage | ||
|
||
### Installing Python dependencies | ||
|
||
After cloning this project, you will likely want to instruct Poetry to create a | ||
virtual environment and install the Python packages (like pytest and pylint) | ||
listed in `pyproject.toml`. | ||
|
||
To install Python dependencies: | ||
|
||
```bash | ||
poetry install | ||
``` | ||
|
||
### Running tasks | ||
|
||
This project uses the [taskipy](https://github.com/illBeRoy/taskipy) task runner | ||
to simplify testing and linting. You can see the actual commands run when tasks | ||
are executed under the `[tool.taskipy.tasks]` header in `pyproject.toml`. | ||
|
||
- **Test** your code with `poetry run task test` | ||
- **Lint** your code with `poetry run task lint` | ||
|
||
### Running GatorConfig | ||
|
||
GatorConfig is a tool that will utilize the command line interface, which | ||
was built to accommodate the users. To run the GatorConfig program | ||
in CLI, type the command: | ||
|
||
`poetry run gatorconfig` | ||
|
||
Once you run this command, the program will output | ||
|
||
`Wrote file to: C:\Users\<YOUR PATH>\GatorConfig\gatorgrader.yml` | ||
|
||
This command will auto-generate a default configuration file for GatorGradle | ||
named `gatorgrader.yml` which will contain a default input for | ||
the variables, such as the name, break, fastfail, etc., | ||
|
||
Additionally, you can run the `poetry run gatorconfig --help` for more | ||
information about the configuration. This command will list out the variables | ||
in the file as well as the defaults it outputs. |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
"""This module generates a GitHub Actions configuration file that uses GatorGradle""" | ||
from pathlib import Path | ||
from ruamel.yaml import YAML | ||
|
||
def create_configuration_file(target_file): | ||
"""Create the workflow configuration file itself""" | ||
default = {'name': 'Grade', 'on': ['push', 'pull_request'], 'jobs': | ||
{'grade': {'runs-on': 'ubuntu-latest', 'steps': | ||
[{'name': 'Checkout repository', 'uses': 'actions/checkout@v2'}, | ||
{'name': 'Run GatorGradle', 'uses': 'GatorEducator/gatorgradle-action@v1'}]}}} | ||
yaml = YAML() | ||
yaml.default_flow_style = False | ||
out = Path(target_file) | ||
yaml.dump(default, out) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
"""Capture user input to automatically generate YAML file.""" | ||
from typing import Dict | ||
from typing import List | ||
from pathlib import Path | ||
import typer | ||
from gatorconfig import gator_yaml | ||
from gatorconfig import actions_configuration | ||
|
||
cli = typer.Typer() | ||
|
||
|
||
|
||
#pylint: disable=too-many-arguments | ||
@cli.command() | ||
def cli_input( | ||
name: str = typer.Option("Project"), | ||
brk: bool = typer.Option(False, "--break"), | ||
fastfail: bool = typer.Option(False), | ||
gen_readme: bool = typer.Option(False), | ||
file: List[str] = typer.Option([]), | ||
#language: str = typer.Option(None), | ||
output_path: Path = typer.Option(Path.cwd()), | ||
indent: int = typer.Option(4), | ||
commit_count: int = typer.Option(5) | ||
): | ||
"""Gather input from the command line. | ||
Args: | ||
name (str, optional): [description]. Defaults to typer.Option("Project"). | ||
brk (bool, optional): [description]. Defaults to typer.Option(False, "--break"). | ||
fastfail (bool, optional): [description]. Defaults to typer.Option(False). | ||
file (List[str], optional): [description]. Defaults to typer.Option([]). | ||
indent (int, optional): [description]. Defaults to typer.Option(4). | ||
commit_count (int, optional): [description]. Defaults to typer.Option(5). | ||
""" | ||
files = get_checks(file) | ||
|
||
yaml_out = gator_yaml.GatorYaml() | ||
#print(files) | ||
# Creation of the output variable | ||
output = { | ||
"name": name, | ||
"break": brk, | ||
"fastfail": fastfail, | ||
"readme": gen_readme, | ||
"indent": indent, | ||
"commits": commit_count, | ||
"files": files | ||
} | ||
file_yaml = yaml_out.dump(output, paths=output["files"]) | ||
output_file(file_yaml, output_path) | ||
actions_configuration.create_configuration_file('../.github/workflows/grade.yml') | ||
|
||
|
||
def output_file(yaml_string: str, output_path: Path): | ||
"""Create and write to file if it doesn't exist, writes to file otherwise. | ||
Args: | ||
yaml_string (str): [description] | ||
output_path (Path): [description] | ||
""" | ||
fle = Path(output_path / "gatorgrader.yml") | ||
fle.touch(exist_ok=True) | ||
with open(fle, "w", encoding="utf8") as yml: | ||
yml.write(yaml_string) | ||
print(f"Wrote file to: {fle}") | ||
|
||
def get_checks(file: List[Path]) -> Dict: | ||
"""Read in checks per file. | ||
Args: | ||
file (List[Path]): List of file paths read in from command line. | ||
Returns: | ||
Dict: Dictionary of file paths and checks to perform per file. | ||
""" | ||
files = {} | ||
for item in file: | ||
running = True | ||
print("") | ||
check_list = [] | ||
while running: | ||
check = input(f"Enter a check for {item} (Press \"Enter\" to move on): ") | ||
if check.lower() == "": | ||
running = False | ||
else: | ||
check_list.append(check) | ||
files[item] = check_list | ||
return files | ||
|
||
if __name__ == "__main__": | ||
cli() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
"""Converts dictionaries to GatorYAML""" | ||
from gatorconfig.split_file_path import split_file_path | ||
|
||
|
||
class GatorYaml: | ||
"""Main GatorYaml object""" | ||
|
||
def __init__(self, indent=4, spaces=4): | ||
"""Init GatorYAML object. Takes optional arguments to change indent of files | ||
and how many spaces is considered a tab """ | ||
self.spaces = spaces # How many spaces is a tab | ||
self.tabs = -1 # Current tab level | ||
self.output = "" # Init output | ||
self.keywords = ["(pure)", "commits"] # Any keywords to look for | ||
self.indents = indent # set indent for file path | ||
|
||
def dump(self, dic, paths=None): | ||
"""Input dictionary is parsed. returns string of valid YAML""" | ||
|
||
if paths is not None: | ||
if isinstance(paths, dict): | ||
dic["files"] = split_file_path(paths) | ||
else: | ||
raise Exception("Paths expected to be \"dict\", got " + str(type(paths)) + "!") | ||
|
||
self.enum_dict(dic) | ||
|
||
return self.output | ||
|
||
def enum_list(self, list_in): | ||
"""Enumerate through input list and output each item unless it finds another dictionary.""" | ||
for i in list_in: | ||
if isinstance(i, dict): | ||
self.tabs += 1 | ||
self.enum_dict(i) | ||
else: | ||
self.output_list_item(i) | ||
|
||
def enum_dict(self, dic): | ||
"""Enumerate through input dictionary and output each key""" | ||
self.tabs += 1 | ||
|
||
for k in dic.keys(): | ||
if k == "indent": | ||
self.indents = int(dic[k]) | ||
|
||
if k == "files": | ||
self.tabs -= 1 | ||
# if isinstance(d[k], list): | ||
# self.enum_list(d[k]) | ||
if isinstance(dic[k], dict): | ||
self.enum_file_dict(dic[k]) | ||
elif isinstance(dic[k], list): | ||
self.output_key(k) | ||
self.enum_list(dic[k]) | ||
elif isinstance(dic[k], dict): | ||
self.output_key(k) | ||
self.enum_dict(dic[k]) | ||
else: | ||
if not self.is_keyword(k, dic[k]): | ||
self.output_key_value(k, dic[k]) | ||
|
||
self.tabs -= 1 | ||
|
||
def enum_file_dict(self, files): | ||
"""Enumerate through the file list dictionary and output each key""" | ||
self.tabs += 1 | ||
|
||
for k in files: | ||
if isinstance(files[k], dict): | ||
self.output_key(k) | ||
self.enum_file_dict(files[k]) | ||
elif isinstance(files[k], list): | ||
self.output_key(k) | ||
self.enum_file_list(files[k]) | ||
|
||
self.tabs -= 1 | ||
|
||
def enum_file_list(self, list_in): | ||
"""Enumerate through each file key's parameter list items""" | ||
for item in list_in: | ||
self.output += (" " * self.spaces) * self.indents + str(item) + "\n" | ||
|
||
def output_list_item(self, item): | ||
"""Output a generic list item""" | ||
self.output += (" " * self.spaces) * self.tabs + " -" + str(item) + "\n" | ||
|
||
def output_key(self, key): | ||
"""Output a generic key""" | ||
self.output += (" " * self.spaces) * self.tabs + str(key) + ":\n" | ||
|
||
def output_key_value(self, key, value): | ||
"""Output a generic key and it's value""" | ||
self.output += ((" " * self.spaces) * self.tabs) + str(key) + ": " + str(value) + "\n" | ||
|
||
def is_keyword(self, key, value): | ||
"""Output key and value if a keyword""" | ||
if key in self.keywords: | ||
if key == "commits": | ||
self.output += (" " * self.spaces) * self.tabs \ | ||
+ "--" + str(key) + " " + str(value) + "\n" | ||
else: | ||
self.output += (" " * self.spaces) * self.tabs + str(key) \ | ||
+ " " + str(value) + "\n" | ||
return True | ||
return False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
"""Checked File widgets""" | ||
|
||
import os | ||
from PyQt5.QtWidgets import QWidget, \ | ||
QVBoxLayout, QLabel, \ | ||
QHBoxLayout, QLineEdit, QPushButton, \ | ||
QPlainTextEdit, QFrame, \ | ||
QFileDialog | ||
|
||
|
||
class CheckFile(QWidget): | ||
"""QWidget class for a checked file""" | ||
|
||
def __init__(self, parent=None): | ||
"""Init QWidget parent and the widgets that make up a checked file widget""" | ||
super().__init__(parent) | ||
self.outer_lay = QVBoxLayout() | ||
|
||
self.file = None | ||
|
||
# ----File Browser----# | ||
# Hbox Layout | ||
lay = QHBoxLayout() | ||
self.check_label = QLabel("File ") | ||
self.path_text = QLineEdit() | ||
self.path_button = QPushButton("Open", | ||
clicked=lambda: self.get_path_from_file(self.path_text)) | ||
self.file_params = QPlainTextEdit() | ||
|
||
# Add widgets to hbox layout | ||
lay.addWidget(self.check_label) | ||
lay.addWidget(self.path_text) | ||
lay.addWidget(self.path_button) | ||
|
||
self.outer_lay.addLayout(lay) | ||
self.outer_lay.addWidget(self.file_params) | ||
|
||
# Horizontal line separator | ||
self.frame = QFrame() | ||
self.frame.setFrameShape(QFrame.HLine) | ||
self.frame.setFrameShadow(QFrame.Sunken) | ||
|
||
self.outer_lay.addWidget(self.frame) | ||
|
||
self.setLayout(self.outer_lay) | ||
|
||
def get_path_from_file(self, target_text): | ||
"""Opens a file dialog to select a new file. | ||
Sets self.file to the file name and sets the tab text.""" | ||
self.file = QFileDialog.getOpenFileName(self, 'OpenFile')[0] | ||
target_text.setText(self.file) | ||
tabs = self.parentWidget().parentWidget() | ||
tabs.setTabText(tabs.currentIndex(), os.path.basename(self.file)) | ||
|
||
def get_data(self): | ||
"""Gets all the data of the checked files and returns their file paths and params.""" | ||
if self.file is None: | ||
self.file = self.path_text.text() | ||
return self.file, self.file_params.toPlainText().split() |
Oops, something went wrong.