diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 0000000..08e1985 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,18 @@ +# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json +language: "en-US" +early_access: false +reviews: + profile: "chill" + request_changes_workflow: true + high_level_summary: true + poem: true + review_status: true + collapse_walkthrough: false + auto_review: + enabled: true + drafts: false + base_branches: + - develop + - main +chat: + auto_reply: true diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..a6046cd --- /dev/null +++ b/.flake8 @@ -0,0 +1,3 @@ +[flake8] +ignore = E402,E722,E203,F401,W503 +max-line-length = 80 diff --git a/.github/workflows/auto-label.json5 b/.github/workflows/auto-label.json5 new file mode 100644 index 0000000..f404d49 --- /dev/null +++ b/.github/workflows/auto-label.json5 @@ -0,0 +1,7 @@ +{ + "labelsSynonyms": { + "dependencies": ["dependabot", "dependency", "dependencies"], + "security": ["security"], + }, + "defaultLabels": ["unapproved"], +} \ No newline at end of file diff --git a/.github/workflows/issue.yml b/.github/workflows/issue.yml new file mode 100644 index 0000000..05c7031 --- /dev/null +++ b/.github/workflows/issue.yml @@ -0,0 +1,66 @@ +############################################################################## +############################################################################## +# +# NOTE! +# +# Please read the README.md file in this directory that defines what should +# be placed in this file +# +############################################################################## +############################################################################## + +name: Issue Workflow +on: + issues: + types: ['opened'] +jobs: + Opened-issue-label: + name: Adding Issue Label + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: | + .github/workflows/auto-label.json5 + sparse-checkout-cone-mode: false + - uses: Renato66/auto-label@v3 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/github-script@v7 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + script: | + const { owner, repo } = context.repo; + const issue_number = context.issue.number; + const apiParams = { + owner, + repo, + issue_number + }; + const labels = await github.rest.issues.listLabelsOnIssue(apiParams); + if(labels.data.reduce((a, c)=>a||["dependencies"].includes(c.name), false)) + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ["good first issue", "security"] + }); + else if(labels.data.reduce((a, c)=>a||["security", "ui/ux"].includes(c.name), false)) + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ["good first issue"] + }); + + + Issue-Greeting: + name: Greeting Message to User + runs-on: ubuntu-latest + steps: + - uses: actions/first-interaction@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + issue-message: "Congratulations on making your first Issue! :confetti_ball: If you haven't already, check out our [Contributing Guidelines](https://github.com/PalisadoesFoundation/talawa-admin/blob/develop/CONTRIBUTING.md) and [Issue Reporting Guidelines](https://github.com/PalisadoesFoundation/talawa-admin/blob/develop/ISSUE_GUIDELINES.md) to ensure that you are following our guidelines for contributing and making issues." + diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 31c34c9..cfd1e2e 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -38,8 +38,31 @@ jobs: echo "Source Branch ${{ github.event.pull_request.head.ref }}" echo "Target Branch ${{ github.event.pull_request.base.ref }}" echo "Error: Source and Target Branches are the same. Please ensure they are different." + echo "Error: Close this PR and try again." exit 1 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: 3.9 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 black pydocstyle flake8-docstrings + + - name: Run Black Formatter Check + run: | + black --check . + + - name: Run Flake8 Linter + run: | + flake8 --docstring-convention google switchmap bin setup tests .github --ignore E402,E722,E203,F401,W503 + + - name: Run pydocstyle + run: | + pydocstyle switchmap setup bin tests --convention=google --add-ignore=D415,D205 + Check-Sensitive-Files: if: ${{ github.actor != 'dependabot[bot]' && !contains(github.event.pull_request.labels.*.name, 'ignore-sensitive-files-pr') }} name: Checks if sensitive files have been changed without authorization @@ -57,12 +80,12 @@ jobs: .github/** package.json package-lock.json + yaml.lock .gitignore .nojekyll CODEOWNERS LICENSE .coderabbit.yaml - ./*.md docs/CNAME docs/static/CNAME docs/package.json @@ -70,8 +93,15 @@ jobs: docs/docusaurus.config.js docs/babel.config.js docs/tsconfig.json - .coderabbit.yaml - + CODE_OF_CONDUCT.md + CODE_STYLE.md + CONTRIBUTING.md + DOCUMENTATION.md + INSTALLATION.md + ISSUE_GUIDELINES.md + PR_GUIDELINES.md + README.md + requirements.txt - name: List all changed unauthorized files if: steps.changed-unauth-files.outputs.any_changed == 'true' || steps.changed-unauth-files.outputs.any_deleted == 'true' env: @@ -142,4 +172,57 @@ jobs: if: github.event.pull_request.base.ref != 'develop' run: | echo "Error: Pull request target branch must be 'develop'. Please refer PR_GUIDELINES.md" + echo "Error: Close this PR and try again." exit 1 + + Validate-CodeRabbit: + name: Validate CodeRabbit Approval + runs-on: ubuntu-latest + if: github.actor != 'dependabot[bot]' + needs: [Code-Quality-Checks, Test-Docusaurus-Deployment] + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + - name: Validate CodeRabbit.ai Approval + run: | + chmod +x $GITHUB_WORKSPACE/.github/workflows/scripts/validate-coderabbit.sh + $GITHUB_WORKSPACE/.github/workflows/scripts/validate-coderabbit.sh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + GITHUB_REPOSITORY: ${{ github.repository }} + + Docstring-Compliance: + name: Check Docstring Compliance + runs-on: ubuntu-latest + needs: [Code-Quality-Checks] + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python 3.11 + uses: actions/setup-python@v4 + with: + python-version: 3.11 + + - name: Cache pip packages + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Install dependencies + run: | + python3 -m venv venv + source venv/bin/activate + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Run docstring compliance check + run: | + source venv/bin/activate + python .github/workflows/scripts/check_docstrings.py --directories switchmap setup bin tests .github diff --git a/.github/workflows/scripts/check_docstrings.py b/.github/workflows/scripts/check_docstrings.py new file mode 100755 index 0000000..8147297 --- /dev/null +++ b/.github/workflows/scripts/check_docstrings.py @@ -0,0 +1,773 @@ +#!/usr/bin/env python3 +"""Script to check for docstrings.""" + +import os +import re +import sys +import argparse +from collections import namedtuple +from docstring_parser import parse + +Violation = namedtuple("Violation", "line function issue action") + + +def validate_docstring(file_path): + """Validate docstrings in a file for compliance with the Google style guide. + + Args: + file_path (str): Path to the Python file to validate. + + Returns: + list: List of violations found in the file, with details about + the issue and corrective action. + + """ + # Initialize key variables + violations = [] + + # Read the file for processing + try: + with open(file_path, "r", encoding="utf-8") as fh_: + lines_with_hard_returns = fh_.readlines() + + except Exception: + return violations + + # Remove hard returns at the end of each line read + lines = [_.rstrip() for _ in lines_with_hard_returns] + + # Evaluate each line + for line_number, line in enumerate(lines): + + # Identify sections of the file that are functions or methods + if re.match(r"^\s*def ", line): + # Get the function name and its arguments + function = extract_function_arguments(line_number, lines) + + # Ignore test functions in test files + if ignore_function(function, file_path): + continue + + # Skip if there are python decorator exceptions + decorator = function_has_decorator(line_number, lines) + if bool(decorator): + if decorator_in_docstring_exception_list(decorator): + continue + + # Get the docstring + docstring = extract_docstring(function.name, line_number, lines) + if bool(docstring.violations): + # Add the violation to the list + violations.extend(docstring.violations) + + # Evaluate the relationship between the + # declared variables and the docstring + if bool(docstring.fatal) is False: + bad = match_arguments_to_docstring( + function, docstring, line_number + ) + if bool(bad): + violations.extend(bad) + + # Return + return violations + + +def ignore_function(function, file_path): + """Extract the docstring from a list of lines read from a file. + + Args: + function: Function object + file_path: Path to file under test + + Returns: + result: True if function must be ignored + + """ + # Initialize key variables + result = False + ignores = ["test_", "tearDownClass", "setUpClass", "setUp", "tearDown"] + + # Ignore test functions in test files + for ignore in ignores: + if function.name.startswith(ignore) and ("test_" in file_path): + result = True + + # Return + return result + + +def match_arguments_to_docstring(function, docstring, line_number): + """Extract the docstring from a list of lines read from a file. + + Args: + function: Function object + docstring: Docstring object + line_number: Number on which the function resides + + Returns: + result: Violation object list + + """ + # Initialize key variables + violations = [] + bad_argument_function = False + bad_argument_docstring = False + arguments_function = function.arguments + arguments_docstring = [_.arg_name for _ in docstring.parser.params] + + # Violation if the arguments don't match and return + if sorted(arguments_function) != sorted(arguments_docstring): + violations.append( + Violation( + line=line_number + 1, + function=function.name, + issue="""\ +The arguments defined in the docstring don't match those of the function.""", + action="""\ +Adjust your docstring to match the listed function arguments.""", + ) + ) + return violations + + ###################################################################### + # Logic below only works when both the function and doctring have args + ###################################################################### + + # Check whether docstring arguments match function arguments + for argument_function in arguments_function: + # Track whether the argument is defined + # in the docstring parameters + for argument_docstring in arguments_docstring: + if argument_docstring not in arguments_function: + violations.append( + Violation( + line=line_number + 1, + function=function.name, + issue=f"""\ +Argument '{argument_docstring}' defined in the docstring is not \ +an argument in the function""", + action=f"""\ +Remove argument '{argument_docstring}' from the docstring""", + ) + ) + bad_argument_function = True + break + if bad_argument_function: + break + + # We found an error, no need to continue generating violations + if not bad_argument_function: + # Check whether docstring arguments match function arguments + for argument_docstring in arguments_docstring: + # Track whether the argument is defined + # in the function parameters + for argument_function in arguments_function: + if argument_function not in arguments_docstring: + violations.append( + Violation( + line=line_number + 1, + function=function.name, + issue=f"""\ + Argument '{argument_function}' defined in the function is not \ + an argument in the docstring""", + action=f"""\ + Add argument '{argument_function}' to the Docstring""", + ) + ) + bad_argument_docstring = True + break + if bad_argument_docstring: + break + + # Return + return violations + + +def function_has_decorator(start, lines): + """Extract the arguments of a function read from a file. + + Args: + start: Starting line to process + lines: The file as a list of strings split by a new line separator + + Returns: + result: The decorator line + + """ + # Initialize key variable + result = None + + # Return + if start > 0: + previous_line = lines[start - 1].strip() + if previous_line.startswith("@"): + result = previous_line + return result + + +def decorator_in_docstring_exception_list(item): + """Extract the arguments of a function read from a file. + + Args: + item: Decorator to check + + Returns: + result: True if an exception + + """ + # Initialize key variable + result = False + exceptions = ["@property"] + property_exceptions = ["setter", "getter"] + + # Return + for exception in exceptions: + if exception in item.strip(): + result = True + break + + for exception in property_exceptions: + regex = f"^@[a-zA-Z0-9_]*.{exception}$" + if re.match(regex, item): + result = True + break + + # Return + return result + + +def extract_function_arguments(start, lines): + """Extract the arguments of a function read from a file. + + Args: + start: Starting line to process + lines: List of lines in the file + + Returns: + result: Function object + + """ + # Initialize key variables + func = "" + possibles = lines[start:] + arguments = [] + Function = namedtuple("Function", "name arguments") + method_keywords = ["self", "cls"] + + # Process the function + for line in possibles: + if bool(line) is False: + continue + elif ("'''" not in line) and ('"""' not in line): + func = f"{func}{line.strip()}" + else: + break + + # Get the arguments + items = func.split("(")[1].split(",") + name = func.split()[1].split("(")[0].strip() + for item in items: + result = item.split(")")[0].split("=")[0].strip() + if bool(result): + # Sometimes arguments have colons. We need everything before. + arguments.append(result.split(":")[0].strip()) + + # Fix arguments for methods + for keyword in method_keywords: + if keyword in arguments: + arguments.remove(keyword) + + # Return + result = Function(name=name, arguments=arguments) + return result + + +def extract_docstring(func_name, line_number, lines): + """Extract the docstring from a list of lines read from a file. + + Args: + line_number: Line where the function starts + lines: The file as a list of strings split by a new line separator + func_name: Name of the function for the docstring + + Returns: + result: namedtuple containing the docstring, and status + + """ + # Initialize key variables + violations = [] + parser = None + fatal = False + Docstring = namedtuple( + "Docstring", "violations docstring parser arguments fatal" + ) + docstring = "" + arguments = [] + found_start = False + found_end = False + + # Process Docstring + docstring_start = line_number + while docstring_start < len(lines): + if bool(is_docstring_delimiter(lines[docstring_start])) is False: + docstring_start += 1 + else: + found_start = True + break + + # Identify the start of the Docstring + if bool(found_start) is True: + # Identify the end of the docstring + docstring_end = docstring_start + 1 + while docstring_end < len(lines): + if bool(is_docstring_delimiter(lines[docstring_end])) is False: + docstring_end += 1 + else: + found_end = True + break + + # Check to make sure there are defined arguments + if bool(found_end) is False: + violations.append( + Violation( + line=line_number + 1, + function=func_name, + issue="""\ +Single line docstring without 'Args:' or 'Results:' sections defined.""", + action="""Define the 'Args:' or 'Results:' sections.""", + ) + ) + fatal = True + + # Extract lines within the docstring area + if found_start and found_end: + + # Get the lines of the Docstring, strip hard returns + valid_lines = lines[docstring_start : docstring_end + 1] + + # Convert the docstring lines to a string + docstring = "\n".join(valid_lines) + + # Parse the docstring + try: + parser = parse(docstring) + + except Exception as e: + violations.append( + Violation( + line=docstring_start, + function=func_name, + issue="Docstring parsing error", + action=f"""\ +Ensure the docstring is properly formatted: {e}""", + ) + ) + + # Evaluate Docstring description + docstring_evaluation = evaluate_docstring_description( + func_name, docstring_start, parser + ) + if bool(docstring_evaluation): + violations.extend(docstring_evaluation) + + # Evaluate the Args: section + argument_evaluation = evaluate_docstring_args( + func_name, docstring_start, docstring, parser + ) + if bool(argument_evaluation.violations): + violations.extend(argument_evaluation.violations) + else: + # Update docstring arguments as they are valid + arguments = argument_evaluation.arguments + + # Evaluate the Returns: section + bad_returns = evaluate_docstring_returns( + func_name, docstring_start, docstring, parser + ) + if bool(bad_returns): + violations.extend(bad_returns) + + else: + violations.append( + Violation( + line=docstring_start, + function=func_name, + issue="Unclosed docstring", + action="""\ +Ensure the docstring is properly closed with triple quotes.""", + ) + ) + + else: + violations.append( + Violation( + line=docstring_start, + function=func_name, + issue="Missing docstring", + action="""\ +Add a Google-style docstring to describe this function.""", + ) + ) + + # Return result + result = Docstring( + docstring=docstring, + violations=violations if bool(violations) else None, + parser=parser, + arguments=arguments, + fatal=fatal, + ) + return result + + +def evaluate_docstring_description(func_name, docstring_start, parser): + """Evaluate the Docstring description for validity. + + Args: + func_name: Function name + docstring_start: Line in file on which the docstring starts + parser: Docstring parser + + Returns: + violations: List of Violations objects + + """ + # Initialize key variables + violations = [] + + # Ensure there is an Docstring description + short_description = ( + parser.short_description.strip().replace("'''", "").replace('"""', "") + ) + if bool(short_description) is False: + violations.append( + Violation( + line=docstring_start, + function=func_name, + issue="Docstring doesn't have a valid description", + action="""\ +Add a docstring description to the first line.""", + ) + ) + + if bool(parser.blank_after_short_description) is False: + violations.append( + Violation( + line=docstring_start, + function=func_name, + issue="\ +The Docstring's short description on the first line doesn't \ +have a blank line after it.", + action="""\ +Add the trailing blank line.""", + ) + ) + + return violations + + +def evaluate_docstring_args(func_name, docstring_start, docstring, parser): + """Evaluate the Docstring arguments for validity. + + Args: + func_name: Function name + docstring_start: Line in file on which the docstring starts + docstring: Docstring + parser: Docstring parser + + Returns: + result: DocstringEvaluation object + + """ + # Initialize key variables + DocstringEvaluation = namedtuple( + "DocstringEvaluation", "violations arguments" + ) + violations = [] + arguments = [] + docstring_no_multiple_white_space = " ".join(docstring.split()) + + if "Args: None " in docstring_no_multiple_white_space: + return DocstringEvaluation(violations=violations, arguments=arguments) + else: + # Check for Args section + if "Args:" not in docstring: + violations.append( + Violation( + line=docstring_start, + function=func_name, + issue="Missing 'Args' section", + action="""\ +Add an 'Args:' section listing the arguments this function accepts.""", + ) + ) + else: + # Ensure there is an Args section + if bool(parser.params) is False: + violations.append( + Violation( + line=docstring_start, + function=func_name, + issue="Docstring doesn't have a valid 'Args:' section", + action="""\ +Add an 'Args:' section with values to the function's docstring""", + ) + ) + else: + # Evaluate each argument + for argument in parser.params: + if bool(argument.arg_name) is False: + violations.append( + Violation( + line=docstring_start, + function=func_name, + issue="""\ +Docstring has no 'Args:' section variable name and description.""", + action="""\ +Add an 'Args:' section with a variable name and description to \ +the function's docstring""", + ) + ) + if bool(argument.description) is False: + violations.append( + Violation( + line=docstring_start, + function=func_name, + issue=f"""\ +Docstring 'Args:' section variable '{argument.arg_name}' \ +needs a description.""", + action="Add description to the variable.", + ) + ) + + # Get the valid arguments + if bool(violations) is False: + arguments = [_.arg_name for _ in parser.params] + + # Return + result = DocstringEvaluation(violations=violations, arguments=arguments) + return result + + +def evaluate_docstring_returns(func_name, docstring_start, docstring, parser): + """Determine whether string is docstring start or stop. + + Args: + func_name: Function name + docstring_start: Line in file on which the docstring starts + docstring: Docstring + parser: Docstring parser + + Returns: + violations: list of violations + + """ + # Initialize key variables + violations = [] + docstring_no_multiple_white_space = " ".join(docstring.split()) + + # Check for Returns section + if "Returns:" not in docstring: + violations.append( + Violation( + line=docstring_start, + function=func_name, + issue="Missing 'Returns:' section", + action="""\ +Add a 'Returns:' section describing the return value.""", + ) + ) + elif "Returns: None " not in docstring_no_multiple_white_space: + + # The parser fails if the 'Args:' section is set to None AND there + # is a valid 'Returns:' section + # This is a workaround where we search for 'Returns: VARIABLE: ' + regex = r"^.*\s+Returns: (\S+): ([a-zA-Z0-9_]*).*$" + regex_match = re.match(regex, docstring_no_multiple_white_space) + if bool(parser.params) is False: + if bool(regex_match) is False: + violations.append( + Violation( + line=docstring_start, + function=func_name, + issue="""\ +Docstring has improperly formatted 'Returns:' section""", + action="""\ +Add a correctly formatted 'Returns:' section to the function's docstring""", + ) + ) + else: + if bool(regex_match.group(2)) is False: + violations.append( + Violation( + line=docstring_start, + function=func_name, + issue="""\ +Docstring 'Returns:' section with no description""", + action="""\ +Add a description to the 'Returns:' section to the function's docstring""", + ) + ) + return violations + + # Ensure there is an Returns section + if bool(parser.returns) is False: + violations.append( + Violation( + line=docstring_start, + function=func_name, + issue="Docstring has no 'Returns:' section", + action="""\ +Add a 'Returns:' section to the function's docstring""", + ) + ) + return violations + + # Ensure there is an Returns section value + if bool(parser.returns.type_name) is False: + violations.append( + Violation( + line=docstring_start, + function=func_name, + issue="""\ +Docstring has no 'Returns:' section variable name and description. \ +If the return value is 'None', then use 'None'""", + action="""\ +Add a 'Returns:' section with a variable name and description to \ +the function's docstring""", + ) + ) + + elif bool(parser.returns.description) is False: + violations.append( + Violation( + line=docstring_start, + function=func_name, + issue=f"""\ +Docstring 'Returns:' section variable \ +'{parser.returns.type_name}' needs a description.""", + action="""Add description to the variable.""", + ) + ) + + # Return + return violations + + +def is_docstring_delimiter(line): + """Determine whether string is docstring start or stop. + + Args: + line: String of text + + Returns: + result: True if it's a delimiter + + """ + # Return + result = bool( + line.strip().startswith('"""') or line.strip().startswith("'''") + ) + return result + + +def check_directory(directory, exclude_dirs=None): + """Check all Python files in a directory for docstring compliance. + + Specified directories are excluded. + + Args: + directory (str): Directory to scan. + exclude_dirs (list): List of directories to exclude. + + Returns: + dict: Dictionary of file violations. + """ + # Initialize key variables + all_violations = {} + _exclude_dirs = exclude_dirs if bool(exclude_dirs) else [] + + # Recursive directory search for files + for root, dirs, files in os.walk(directory): + # Skip excluded directories + dirs[:] = [ + d for d in dirs if os.path.join(root, d) not in _exclude_dirs + ] + + # Process files in each directory + for file in files: + if file.endswith(".py"): + # Print start of processing + file_path = os.path.join(root, file) + + # Identify violations in the file + violations = validate_docstring(file_path) + + # Add any found violations + if violations: + all_violations[file_path] = violations + + # Return + return all_violations + + +def main(): + """Start checking the docstrings. + + Args: + None + + Returns: + None + """ + # Header for the help menu of the application + parser = argparse.ArgumentParser( + description="""\ +This script checks specified directories for compliance with the \ +Google Docstring 'Args' and 'Returns' sections.""", + formatter_class=argparse.RawTextHelpFormatter, + ) + + # CLI argument for starting + parser.add_argument( + "--directories", + required=False, + default=".", + nargs="+", + type=str, + help="Directories to scan for docsctring compliant python files.", + ) + args = parser.parse_args() + + # Process the directories + for directory in args.directories: + # Identify violations + violations = check_directory(directory, exclude_dirs=None) + + # Create a message for the violation + if violations: + print("") + for file, issues in sorted(violations.items()): + for issue in issues: + print( + f"""\ +File Docstring Error: {file} +Line : {issue.line} +Function: {issue.function} +Issue: {issue.issue} +Corrective Action: {issue.action} +""" + ) + print( + f"""\ +Follow the online 'Google Python Style Guide' for our docstring expectations. +There are {len(violations)} docstring violations +""" + ) + + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/scripts/countline.py b/.github/workflows/scripts/countline.py index d0b03c5..1194be5 100755 --- a/.github/workflows/scripts/countline.py +++ b/.github/workflows/scripts/countline.py @@ -1,30 +1,27 @@ #!/usr/bin/env python3 -# -*- coding: UTF-8 -*- """Script to encourage more efficient coding practices. Methodology: - Analyses the `lib` and `test` directories to find files that exceed a - pre-defined number of lines of code. +Analyses the `lib` and `test` directories to find files that exceed a +pre-defined number of lines of code. - This script was created to help improve code quality by encouraging - contributors to create reusable code. +This script was created to help improve code quality by encouraging +contributors to create reusable code. -NOTE: +Notice: - This script complies with our python3 coding and documentation standards - and should be used as a reference guide. It complies with: +This script complies with our python3 coding and documentation standards +and should be used as a reference guide. It complies with: - 1) Pylint - 2) Pydocstyle - 3) Pycodestyle - 4) Flake8 - - Run these commands from the CLI to ensure the code is compliant for all - your pull requests. + 1) Pylint + 2) Pydocstyle + 3) Pycodestyle + 4) Flake8 +Run these commands from the CLI to ensure the code is compliant for all +your pull requests. """ - # Standard imports import os import sys diff --git a/.github/workflows/scripts/validate-coderabbit.sh b/.github/workflows/scripts/validate-coderabbit.sh new file mode 100755 index 0000000..d4f6aec --- /dev/null +++ b/.github/workflows/scripts/validate-coderabbit.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +echo "Step 1: Fetching all PR reviews..." + +response=$(curl -s -f -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/reviews?per_page=1000") || { + echo "Error: Failed to fetch reviews from GitHub API" + exit 1 +} + +latest_reviews=$(echo "$response" | jq -c '[.[]] | group_by(.user.login) | map(max_by(.submitted_at))') || { + echo "Error: Failed to process reviews JSON" + exit 1 +} + +if [ "$latest_reviews" = "null" ] || [ -z "$latest_reviews" ]; then + echo "Error: Invalid reviews data" + exit 1 +fi + +echo "Step 2: Checking approval status of 'coderabbitai[bot]'..." +approval_state=$(echo "$latest_reviews" | jq -r '[.[] | select(.user.login == "coderabbitai[bot]" and .state == "APPROVED")] | length') + +if [[ "$approval_state" =~ ^[0-9]+$ ]] && [[ $approval_state -gt 0 ]]; then + echo "Success: PR approved by CodeRabbit.ai." +else + echo "" + echo "ERROR:" + echo "" + echo "1) This PR is not approved by CodeRabbit.ai." + echo "2) In the 'Add a comment' section at the bottom" + echo " of the PR web page, add a comment with the" + echo " statement below to restart a review" + echo "" + echo "@coderabbitai full review" + exit 1 +fi diff --git a/.gitignore b/.gitignore index 15201ac..99b1229 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,69 @@ +############################################################################# +# +# Placed to reduce the risk of contributors uploading sensitive data +############################################################################# + +# Ignore hidden environment files / directory +*.switchmap + +# Ignore files in these directories and ALL subdirectories +var/** +etc/** + +# There are exceptions +!.gitignore + +############################################################################# +# Miscellaneous +############################################################################# + +.DS_Store + +############################################################################# +# Ignore VS Code files +############################################################################# + +.vscode/ +.vscode/* + +#!.vscode/settings.json +#!.vscode/tasks.json +#!.vscode/launch.json +#!.vscode/extensions.json +#!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +############################################################################# +# Ignore all vim / vi temporary files +############################################################################# +.idea* + +### Vim ### +# swap +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +# session +Session.vim +# temporary +.netrwhist +*~ +# auto-generated tag files +tags + +*.swp +*.un~ +*~ +.#* + +############################################################################# +# Python +############################################################################# + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/.pydocstyle b/.pydocstyle new file mode 100644 index 0000000..5386b23 --- /dev/null +++ b/.pydocstyle @@ -0,0 +1,3 @@ +[pydocstyle] +convention=google +add-ignore=D415,D205 \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..98ab2a0 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,69 @@ +# Contributing to our Project +Thank you for your interest in contributing to our project. Regardless of the size of the contribution you make, all contributions are welcome and are appreciated. + +If you are new to contributing to open source, please read the Open Source Guides on [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/). + +## Ways to Contribute +We know you are ready to start contributing code right away! Hers is a list of [good first issues](https://github.com/PalisadoesFoundation/switchmap-ng-docs/labels/good%20first%20issue) that contain issues with a limited scope. + +## Quicklinks + +- [Contributing to our Project](#contributing-to-our-project) + - [Ways to Contribute](#ways-to-contribute) + - [Quicklinks](#quicklinks) + - [Our Development Process](#our-development-process) + - [Issues](#issues) + - [Pull Requests](#pull-requests) + - [Git Flow](#git-flow) + - [Contributing Code](#contributing-code) + - [Internships](#internships) + - [Community](#community) + + + +### Our Development Process +We utilize GitHub issues and pull requests to keep track of issues and contributions from the community. + +#### Issues +Make sure you are following [issue report guidelines](ISSUE_GUIDELINES.md) available here before creating any new issues to the project. + +#### Pull Requests +[Pull Request guidelines](PR_GUIDELINES.md) is best resource to follow to start working on open issues. + +#### Git Flow +For this project, we utilize the GitFlow branching model. GitFlow is geared towards efficiently tracking development and managing releases. The model makes parallel development efforts easy and safe by isolating new development efforts from completed work. + +The different types of branches we may use are: +* Feature branches (feature/branch-name) +* Release branches (release/1.XX) +* Bug branches (bugfix/branch-name) +* Hotfix branches (hotfix/branch-name) + +Detailed document containing how GitFlow works: https://nvie.com/posts/a-successful-git-branching-model/ + +### Contributing Code +Code contributions to this project come in the form of pull requests. These are done by forking the repo and making changes locally. + +Make sure you have read the [Documentation for Setting up the Project](https://github.com/PalisadoesFoundation/switchmap-ng-docs#readme) + +The process of proposing a change to this project can be summarized as: +1. Fork the project repository and branch off `master`. +2. The repository can be cloned locally using `git clone `. +3. Make the desired changes to the project source code. +4. Run the website and test your changes. +5. If you've added code that should be tested, write tests. +6. After making changes you can add them to git locally using `git add `(to add changes only in a particular file) or `git add .` (to add all changes). +7. After adding the changes you need to commit them using `git commit -m ''`(look at the commit guidelines below for commit messages). +8. Once you have successfully commited your changes, you need to push the changes to the forked repo on github using: `git push origin `.(Here branch name must be name of the branch you want to push the changes to.) +9. Now create a pull request to the project repository from your forked repo. Open an issue regarding the same and link your PR to it. +10. Ensure the test suite passes, either locally or on CI once a PR has been created. +11. Review and address comments on your pull request if requested. + +### Internships +If you are participating in any of the various internship programs we ar members of then please read the [internship introduction guides](https://developer.palisadoes.org/docs/category/internships). + +## Community +There are many ways to communicate with the community. + +1. The Palisadoes Foundation has a Slack channel where members can assist with support and clarification. Visit the [Palisadoes Foundation's GitHub repository home page](https://github.com/PalisadoesFoundation) for the link to join our slack channel. +2. We also have a technical email list run by [freelists.org](https://www.freelists.org/). Search for "palisadoes" and join. Members on this list are also periodically added to our marketing email list that focuses on less technical aspects of our work. diff --git a/ISSUE_GUIDELINES.md b/ISSUE_GUIDELINES.md new file mode 100644 index 0000000..81e1c30 --- /dev/null +++ b/ISSUE_GUIDELINES.md @@ -0,0 +1,59 @@ +# Issue Report Guidelines + +:+1::tada: First off, thanks for taking the time to contribute! :tada::+1: + +In order to give everyone a chance to submit a issues reports and contribute to our projects, we have put restrictions in place. This section outlines the guidelines that should be imposed upon issue reports in our projects. + +___ +## Table of Contents + + +- [Issue Report Guidelines](#issue-report-guidelines) + - [Table of Contents](#table-of-contents) + - [Issue Management](#issue-management) + - [New Issues](#new-issues) + - [Existing Issues](#existing-issues) + - [Feature Request Issues](#feature-request-issues) + - [Monitoring the Creation of New Issues](#monitoring-the-creation-of-new-issues) + - [General Guidelines](#general-guidelines) + + +___ +## Issue Management + +In all cases please use the [GitHub open issue search](https://github.com/PalisadoesFoundation/switchmap-ng-docs/issues) to check whether the issue has already been reported. + +### New Issues +To create new issues follow these steps: + +1. Your issue may have already been created. Search for duplicate open issues before submitting yours.for similar deficiencies in the code.duplicate issues are created. +1. Verify whether the issue has been fixed by trying to reproduce it using the latest master or development branch in the repository. +1. Click on the [`New Issue`](https://github.com/PalisadoesFoundation/switchmap-ng-docs/issues/new/choose) button +1. Use the templates to create a standardized report of what needs to be done and why. +1. If you want to be assigned the issue that you have created, then add a comment immediately after submitting it. + +We welcome contributors who find new ways to make the code better. + +### Existing Issues + +You can also be a valuable contributor by searching for dormant issues. Here's how you can do that: + +1. **Previously Assigned Issues**: We regularly review issues and add a [`no-issue-activity`](https://github.com/PalisadoesFoundation/switchmap-ng-docs/issues?q=is%3Aissue+is%3Aopen+label%3Ano-issue-activity) label to them. Use the issue comments to ask whether the assignee is still working on the issue, and if not, ask for the issue to be assigned to you. +1. **Unassigned Issues**: If the issue is already reported and [not assigned to anyone](https://github.com/PalisadoesFoundation/switchmap-ng-docs/issues?q=is%3Aissue+is%3Aopen+no%3Aassignee) and you are interested in working on the issue then: + 1. Ask for the issue to be assigned to you in the issue comments + 2. Ask our contributors to assign it to you in our slack channel. + +Working on these types of existing issues is a good way of getting started with the community. + +### Feature Request Issues + +Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the mentors of the merits of this feature. Please provide as much detail and context as possible. + +### Monitoring the Creation of New Issues +1. Join our slack channel for automatic issue and pull request updates + +## General Guidelines + +1. Discuss issues in our various slack channels when necessary +2. Please do not derail or troll issues. +3. Keep the discussion on topic and respect the opinions of others. diff --git a/PR_GUIDELINES.md b/PR_GUIDELINES.md new file mode 100644 index 0000000..935d4b8 --- /dev/null +++ b/PR_GUIDELINES.md @@ -0,0 +1,31 @@ +# Pull Request Guidelines + +:+1::tada: First off, thanks for taking the time to contribute! :tada::+1: + +In order to give everyone a chance to submit a pull request and contribute to the project, we have put restrictions in place. This section outlines the guidelines that should be imposed upon pull requests in the project. + +## Pull Requests and Issues +1. Do not start working on any open issue and raise a PR unless the issue is assigned to you. PRs that don't meet these guidelines will be closed. +1. Pull requests must be based on [open issues](https://github.com/PalisadoesFoundation/switchmap-ng-docs/issues) available. +1. [Use this method to automatically close the issue when the PR is completed.](https://docs.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue) + +## Testing +1. All pull requests must have test units. If, for some reason, it is not possible to add tests, please let us know and explain why. In that case, you'll need to tell us what steps you followed to manually test your changes. +1. Please read our [CONTRIBUTING.md](CONTRIBUTING.md) document for details on our testing policy. + +## Pull Request Processing +1. We do not accept draft Pull Requests. They will be closed if submitted. We focus on work that is ready for immediate review. +1. Removing assigned reviewers from your Pull Request will cause it to be closed. The quality of our code is very important to us. Therefore we make experienced maintainers of our code base review your code. Removing these assigned persons is not in the best interest of this goal. +1. If you have not done so already, please read the `Pull Requests and Issues` and `Testing` sections above. +1. Each contributor may only create one pull request at a time. We have this rule in place due to our limited resources - if everyone was allowed to post multiple pull requests, we would not be able to review them properly. It is also better for contributors because you can focus on creating one quality PR - so spend time making sure it is as good as it can be. +1. Upon successful push to the fork, check if all tests are passing; if not, fix the issues and then create a pull request. +1. If the pull request's code quality is not up to par, or it would break the app, it will more likely be closed. So please be careful when creating a PR. +1. Please follow the PR template provided. Ensure the PR title clearly describes the problem it is solving. In the description, include the relevant issue number, snapshots, and videos after changes are added. +1. If you are borrowing a code, please disclose it. It is fine and sometimes even recommended to borrow code, but we need to know about it to assess your work. If we find out that your pull request contains a lot of code copied from elsewhere, we will close the pull request. +1. No Work In Progress. ONLY completed and working pull requests and with respective test units will be accepted. A WIP would fall under rule 4 and be closed immediately. +1. Please do not @mention contributors and mentors. Sometimes it takes time before we can review your pull request or answer your questions, but we'll get to it sooner or later. @mentioning someone just adds to the pile of notifications we get and it won't make us look at your issue faster. +1. Do not force push. If you make changes to your pull request, please simply add a new commit, as that makes it easy for us to review your new changes. If you force push, we'll have to review everything from the beginning. +1. PR should be small, easy to review and should follow standard coding styles. +1. If PR has conflicts because of recently added changes to the same file, resolve issues, test new changes, and submit PR again for review. +1. PRs should be atomic. That is, they should address one item (issue or feature) +1. After submitting PR, if you are not replying within 48 hours, then in that case, we may need to assign the issue to other contributors based on the priority of the issue. diff --git a/README.md b/README.md index e58f7e6..2b8ac8d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,28 @@ -# switchmap-ng-api +# Switchmap-NG API Documentation + +💬 Join the community on Slack from our [Palisadoes Foundation GitHub Home Page](https://github.com/PalisadoesFoundation) + +[![N|Solid](static/img/markdown/misc/logo.png)](https://github.com/PalisadoesFoundation/switchmap-ng-api) + +[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) +[![GitHub stars](https://img.shields.io/github/stars/PalisadoesFoundation/switchmap-ng-api.svg?style=social&label=Star&maxAge=2592000)](https://github.com/PalisadoesFoundation/switchmap-ng-api) +[![GitHub forks](https://img.shields.io/github/forks/PalisadoesFoundation/switchmap-ng-api.svg?style=social&label=Fork&maxAge=2592000)](https://github.com/PalisadoesFoundation/switchmap-ng-api) + +## About Palisadoes + +The [Palisadoes Foundation’s](https://www.palisadoes.org) open-source software projects started in 2016 when a group of expatriate Jamaicans wanted to assist development of new and existing information technologies for the island’s social good. + +Over the years the scope of our work has expanded. Our volunteers now live in all timezones of the globe and work on projects with a truly international scope. + +- [Our Website](https://www.palisadoes.org)
+- [Our Developer Website](https://developer.palisadoes.org) + +## About This Repository + +This repo hosts the documentation you see on the https://developer.palisadoes.org site. + +## Documentation + +- Want to contribute? Look at [CONTRIBUTING.md](CONTRIBUTING.md) to get started. + diff --git a/bin/.gitignore b/bin/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/docs/.gitignore b/docs/.gitignore index 7dd4990..d8a6577 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -20,3 +20,7 @@ package-lock.json npm-debug.log* yarn-debug.log* yarn-error.log* + +.yarn/* +.pnp.* +.yarnrc.yml \ No newline at end of file diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts index 485d610..0c85687 100644 --- a/docs/docusaurus.config.ts +++ b/docs/docusaurus.config.ts @@ -49,10 +49,10 @@ const config: Config = { // Replace with your project's social card image: 'img/docusaurus-social-card.jpg', navbar: { - title: 'My Site', + title: 'Talawa-docs', logo: { alt: 'My Site Logo', - src: 'img/logo.svg', + src: 'img/logos/logo.png', }, items: [ { @@ -62,9 +62,39 @@ const config: Config = { label: 'Tutorial', }, { - href: 'https://github.com/facebook/docusaurus', - label: 'GitHub', - position: 'right', + label: "Mobile Guide", + position: "left", + href: "https://docs-mobile.talawa.io/", + target: "_self", + }, + { + label: "Admin Guide", + position: "left", + href: "https://docs-admin.talawa.io/", + target: "_self", + }, + { + label: "API Guide", + position: "left", + href: "https://docs-api.talawa.io/", + target: "_self", + }, + { + label: "Demo", + position: "left", + href: "http://admin-demo.talawa.io/", + }, + { + to: "https://github.com/PalisadoesFoundation", + position: "right", + className: "header-github-link", + "aria-label": "GitHub repository", + }, + { + to: "https://www.youtube.com/@PalisadoesOrganization", + position: "right", + className: "header-youtube-link", + "aria-label": "Palisadoes Youtube channel", }, ], }, @@ -82,27 +112,51 @@ const config: Config = { }, { title: 'Community', + items: [ + { + label: " Slack", + to: "https://github.com/PalisadoesFoundation", + className: "footer__icon footer__slack", + }, + { + label: " News", + to: "https://www.palisadoes.org/news/", + className: "footer__icon footer__news", + }, + { + label: " Contact Us", + to: "https://www.palisadoes.org/contact/", + className: "footer__icon footer__contact", + }, + ], + }, + { + title: "Social Media", items: [ { - label: 'Stack Overflow', - href: 'https://stackoverflow.com/questions/tagged/docusaurus', + label: " Twitter", + to: "https://twitter.com/palisadoesorg?lang=en", + className: "footer__icon footer__twitter", }, { - label: 'Discord', - href: 'https://discordapp.com/invite/docusaurus', + label: " Facebook", + to: "https://www.facebook.com/palisadoesproject/", + className: "footer__icon footer__facebook", }, { - label: 'X', - href: 'https://x.com/docusaurus', + label: " Instagram", + to: "https://www.instagram.com/palisadoes/?hl=en", + className: "footer__icon footer__instagram", }, ], }, { - title: 'More', + title: "Development", items: [ { - label: 'GitHub', - href: 'https://github.com/facebook/docusaurus', + label: " GitHub", + to: "https://github.com/PalisadoesFoundation", + className: "footer__icon footer__github", }, ], }, @@ -116,4 +170,4 @@ const config: Config = { } satisfies Preset.ThemeConfig, }; -export default config; +export default config; \ No newline at end of file diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css index 2bc6a4c..8491107 100644 --- a/docs/src/css/custom.css +++ b/docs/src/css/custom.css @@ -5,26 +5,150 @@ */ /* You can override the default Infima variables here. */ + +@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono&display=swap"); +@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap"); + :root { - --ifm-color-primary: #2e8555; - --ifm-color-primary-dark: #29784c; - --ifm-color-primary-darker: #277148; - --ifm-color-primary-darkest: #205d3b; - --ifm-color-primary-light: #33925d; - --ifm-color-primary-lighter: #359962; - --ifm-color-primary-lightest: #3cad6e; --ifm-code-font-size: 95%; - --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.29); + --secondary-blue-900: #001c63; + --sidebar-bg-color: #f3f4f6; + --secondary-blue-500: #3970fd; + --primary-blue-600: #1e56e3; + --base-neutral-0: #ffffff; + --primary-neutral-800: #1f2a37; + --ifm-menu-color-active: #1e56e3; + --primary-neutral-600: #4d5761; + --ifm-breadcrumb-color-active: var(--primary-neutral-600); + --ifm-link-color: #1e56e3; + --ifm-button-background-color: #2e8555; + --ifm-button-background-color-dark: #205d3b; + --ifm-hover-overlay: rgba(0, 0, 0, 0.05); + --brand-color: black; + --next-prev-border-color: #e5e7eb; + --ifm-font-family-base: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, + Cantarell, Noto Sans, sans-serif, BlinkMacSystemFont, "Segoe UI", Helvetica, + Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } /* For readability concerns, you should choose a lighter palette in dark mode. */ [data-theme='dark'] { - --ifm-color-primary: #25c2a0; - --ifm-color-primary-dark: #21af90; - --ifm-color-primary-darker: #1fa588; - --ifm-color-primary-darkest: #1a8870; - --ifm-color-primary-light: #29d5b0; - --ifm-color-primary-lighter: #32d8b4; - --ifm-color-primary-lightest: #4fddbf; - --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); + --ifm-background: #111927; + --ifm-background-surface-color: var(--ifm-background-color); + --ifm-menu-color: var(--ifm-color-gray-200); + --ifm-toc-link-color: var(--ifm-color-gray-200); + --ifm-code-background: #001b66; + --ifm-color-content: var(--ifm-color-white); + --ifm-navbar-search-input-background-color: #001b66; + --ifm-table-stripe-background: #001242; + --ifm-navbar-search-input-placeholder-color: var(--ifm-color-gray-200); + --ifm-hover-overlay: rgba(0, 0, 0, 0); + --ifm-color-primary: #1e56e3; + --secondary-blue-900: #c6d6ff; + --sidebar-bg-color: #161f36; + --primary-neutral-800: #c9c9cc; + --ifm-button-background-color: #25c2a0; + --ifm-button-background-color-dark: #2e8555; + --ifm-navbar-link-color: #9da4ae; + --ifm-navbar-border-color:#2d3956; + --brand-color: white; + --primary-neutral-600: #c4c4c4; + --next-prev-border-color: #293441; +} + +.main-wrapper{ + background-color: var(--ifm-background); + display: block; + margin: 0 calc(-1 * var(--ifm-pre-padding)); + padding: 0 var(--ifm-pre-padding); +} + +.table-of-contents { + font-size: 0.75rem; +} + +.main__content{ + background-color: var(--ifm-background); +} + +.menu__link, +.menu * { + font-size: 0.7rem; + padding-left: 0.5rem; + text-transform: uppercase; + font-weight: 700; + line-height: 1.5; +} + +.menu__list { + border-bottom: 1px solid var(--next-prev-border-color); + padding: 0 15px; +} + +.navbar { + background-color: var(--sidebar-bg-color); + box-shadow: var(--ifm-navbar-shadow); + padding: 24px 48px; + height: auto; + border-bottom: 1px solid var(--ifm-navbar-border-color) ; +} + +.navbar__item { + font-size: 0.875rem; } + +.navbar__link:hover, +.navbar__link--active { + color: var(--ifm-color-primary); + text-decoration: none; +} + +.navbar__items--right > .navbar__item:not(:first-of-type) { + margin-left: 0.25px; +} + +.footer--dark { + --ifm-footer-background-color: #111927; + border-top: 1px solid var(--next-prev-border-color); +} + +.header-github-link:before { + content: ""; + width: 20px; + height: 20px; + display: flex; + background: url("/img/logos/github-dark.svg") no-repeat; + position: relative; + right: 8px; + top: 1.5px; +} + +.header-youtube-link:before { + content: ""; + width: 25px; + height: 30px; + display: flex; + background: url("/img/logos/youtube.svg") no-repeat; + position: relative; + right: 8px; + top: 4.5px; +} + +html[data-theme="dark"] .header-github-link:before { + background: url(/img/logos/github.svg) no-repeat; +} +html[data-theme="dark"] .header-youtube-link:before { + background: url(/img/logos/youtube-light.svg) no-repeat; +} + +.footer--dark li { + margin-bottom: 0; + padding: 0.5rem; + line-height: normal; +} + +.footer__icon { + margin: 0; + color: #fff; +} \ No newline at end of file diff --git a/docs/src/pages/index.tsx b/docs/src/pages/index.tsx index 270b7f9..2211f84 100644 --- a/docs/src/pages/index.tsx +++ b/docs/src/pages/index.tsx @@ -1,4 +1,3 @@ -import clsx from 'clsx'; import Link from '@docusaurus/Link'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import Layout from '@theme/Layout'; @@ -10,7 +9,7 @@ import styles from './index.module.css'; function HomepageHeader() { const { siteConfig } = useDocusaurusContext(); return ( -
+
{siteConfig.title} @@ -35,6 +34,7 @@ export default function Home(): JSX.Element {
@@ -42,4 +42,4 @@ export default function Home(): JSX.Element {
); -} +} \ No newline at end of file diff --git a/docs/static/img/logos/github-dark.svg b/docs/static/img/logos/github-dark.svg new file mode 100644 index 0000000..654102a --- /dev/null +++ b/docs/static/img/logos/github-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/static/img/logos/github.svg b/docs/static/img/logos/github.svg new file mode 100644 index 0000000..ab49f99 --- /dev/null +++ b/docs/static/img/logos/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/static/img/logos/logo.png b/docs/static/img/logos/logo.png new file mode 100644 index 0000000..62ab0a9 Binary files /dev/null and b/docs/static/img/logos/logo.png differ diff --git a/docs/static/img/logos/youtube-light.svg b/docs/static/img/logos/youtube-light.svg new file mode 100644 index 0000000..03a5666 --- /dev/null +++ b/docs/static/img/logos/youtube-light.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/static/img/logos/youtube.svg b/docs/static/img/logos/youtube.svg new file mode 100644 index 0000000..97a6123 --- /dev/null +++ b/docs/static/img/logos/youtube.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/etc/.gitignore b/etc/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..3a65c0d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,4 @@ +# Do not delete. This file is used to configure +# python black formatting +[tool.black] +line-length = 79 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5d73c11 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,35 @@ +# Miscellaneous +PyYAML + +# Flask Web Server +Flask +Flask-Table +Flask-Testing +Werkzeug +gunicorn + +# Data and Database +PyMySQL +PyMySQL[rsa] +SQLAlchemy +pandas + +# GraphQL interface for Flask +graphene-sqlalchemy + +# Testing +mock +pytest + +# Docstring Parser +docstring_parser + +# Other +more-itertools + +#Linting and formatting +flake8 +flake8-docstrings +pydocstyle +black +docstring_parser \ No newline at end of file diff --git a/setup/.gitignore b/setup/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/static/img/markdown/misc/logo.png b/static/img/markdown/misc/logo.png new file mode 100644 index 0000000..985fcfb Binary files /dev/null and b/static/img/markdown/misc/logo.png differ diff --git a/switchmap/.gitignore b/switchmap/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..e69de29