Skip to content

Commit

Permalink
chore: Update code formatting and linting configurations
Browse files Browse the repository at this point in the history
  • Loading branch information
mostafa committed Aug 18, 2024
1 parent 8bbe015 commit f24ffcb
Show file tree
Hide file tree
Showing 16 changed files with 278 additions and 135 deletions.
3 changes: 3 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[flake8]
max-line-length = 88
exclude = .git,__pycache__,build,dist
34 changes: 34 additions & 0 deletions .github/workflows/lint-and-format.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Lint and Format

on:
pull_request:
branches:
- main

env:
pythonVersion: 3.12

jobs:
lint-and-format:
runs-on: ubuntu-latest

steps:
- name: Check out the code
uses: actions/checkout@v2

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.pythonVersion }}

- name: Install dependencies
run: |
pip install flake8 black
apt install flake8
apt install black
- name: Run flake8
run: flake8 .

- name: Run black check
run: black --check .
1 change: 0 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
name: MetaCall Examples CI

on:
workflow_dispatch:
pull_request:
push:
branches:
Expand Down
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,22 @@ To keep the project organized and maintain a clear history, we ask that all cont
- **Explain Your Changes**: Clearly explain the motivation and context for your changes in the pull request description.
- **Run Tests**: Ensure that all tests pass locally before submitting your pull request.

### Guidelines
To ensure code quality and consistency, please follow these guidelines:

1. **Linter**: Run `flake8` to check for style violations.
```bash
flake8 .
```

2. **Formatter**: Format your code using `black`.
```bash
black .
```

3. **Pull Requests**: Before submitting a pull request, ensure that your code passes the linter and formatter checks. The CI pipeline will automatically run these checks on your PR.


### General Guidelines

- Follow the existing code style and structure.
- Ensure that all tests pass before submitting a pull request.
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[tool.black]
line-length = 88
4 changes: 0 additions & 4 deletions test-suites/test-time-app-web.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,3 @@ code-files:
- name: Check index.html is fully returned
function-call: index()
expected-pattern: '<html>[\w\W]*</html>'




46 changes: 34 additions & 12 deletions testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,57 +6,78 @@
from testing.test_runner import TestRunner
from testing.test_suites_extractor import TestSuitesExtractor


def parse_arguments():
''' Parse the command line arguments '''
parser = argparse.ArgumentParser(description="Run test suites in specified environments.")
"""Parse the command line arguments"""
parser = argparse.ArgumentParser(
description="Run test suites in specified environments."
)
parser.add_argument("-f", "--file", required=True, help="The test suite file name.")
parser.add_argument("-V", "--verbose", action="store_true", help="Increase output verbosity.")
parser.add_argument("-e", "--envs", nargs="+", default=["cli"], help="Environments to run the tests on (cli, faas).")
parser.add_argument(
"-V", "--verbose", action="store_true", help="Increase output verbosity."
)
parser.add_argument(
"-e",
"--envs",
nargs="+",
default=["cli"],
help="Environments to run the tests on (cli, faas).",
)
return parser.parse_args()


def setup_logger(verbose):
''' Setup logger with the appropriate logging level '''
"""Setup logger with the appropriate logging level"""
logger = Logger.get_instance()
logger.set_level("DEBUG" if verbose else "INFO")
return logger


def extract_test_suites(file_name):
''' Extract test suites from the test suite file '''
"""Extract test suites from the test suite file"""
try:
test_suites_extractor = TestSuitesExtractor(file_name)
return test_suites_extractor.extract_test_suites()
except Exception as e:
raise RuntimeError(f"Error extracting test suites: {e}")


def clone_repo_if_needed(repo_url):
''' Clone the repository if not already cloned '''
"""Clone the repository if not already cloned"""
try:
repo_manager = RepoManager.get_instance(repo_url)
repo_manager.clone_repo_if_not_exist()
except Exception as e:
raise RuntimeError(f"Error cloning repository: {e}")


def deploy_faas_if_needed(envs, project_path, logger):
''' Deploy the project as a local FaaS if required '''
"""Deploy the project as a local FaaS if required"""
if "faas" in envs:
deploy_manager = DeployManager.get_instance(project_path)
if not deploy_manager.deploy_local_faas():
logger.error("Error deploying the project. Removing 'faas' from environments.")
logger.error(
"Error deploying the project. Removing 'faas' from environments."
)
envs.remove("faas")


def run_tests(envs, test_suites):
''' Run the tests in the specified environments '''
"""Run the tests in the specified environments"""
test_runner = TestRunner(envs)
test_runner.run_tests(test_suites)


def main():
args = parse_arguments()
logger = setup_logger(args.verbose)

try:
project_name, project_path, repo_url, test_suites = extract_test_suites(args.file)
project_name, project_path, repo_url, test_suites = extract_test_suites(
args.file
)
logger.info(f"Testing Project: {project_name}")

clone_repo_if_needed(repo_url)
deploy_faas_if_needed(args.envs, project_path, logger)
run_tests(args.envs, test_suites)
Expand All @@ -65,5 +86,6 @@ def main():
logger.error(e)
exit(1)


if __name__ == "__main__":
main()
41 changes: 25 additions & 16 deletions testing/deploy_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import json
from testing.logger import Logger


class DeployManager:
_instance = None

Expand All @@ -17,15 +18,17 @@ def __init__(self, project_path):

@staticmethod
def get_instance(project_path=None):
''' Static access method for singleton '''
"""Static access method for singleton"""
if DeployManager._instance is None:
if project_path is None:
raise ValueError("Project path must be provided for the first instance.")
raise ValueError(
"Project path must be provided for the first instance."
)
DeployManager(project_path)
return DeployManager._instance

def set_environment_variables(self, env_vars):
''' Set environment variables '''
"""Set environment variables"""
try:
for key, value in env_vars.items():
os.environ[key] = value
Expand All @@ -35,30 +38,35 @@ def set_environment_variables(self, env_vars):
return True

def deploy_local_faas(self):
''' Deploy the project as a local FaaS '''
env_vars = {
'NODE_ENV': 'testing',
'METACALL_DEPLOY_INTERACTIVE': 'false'
}
"""Deploy the project as a local FaaS"""
env_vars = {"NODE_ENV": "testing", "METACALL_DEPLOY_INTERACTIVE": "false"}

if not self.set_environment_variables(env_vars):
return False

try:
deploy_command = f"metacall-deploy --dev --workdir {self.project_path}"
subprocess.run(deploy_command, capture_output=True, text=True, shell=True, check=True)
subprocess.run(
deploy_command, capture_output=True, text=True, shell=True, check=True
)
self.logger.debug("Local FaaS deployed successfully.")
return True
except subprocess.CalledProcessError as e:
self.logger.error(f"Error deploying the project: {e}")
return False

def get_local_base_url(self):
''' Get the base URL of the deployed local FaaS '''
"""Get the base URL of the deployed local FaaS"""
inspection_command = "metacall-deploy --inspect OpenAPIv3 --dev"
try:
result = subprocess.run(inspection_command, capture_output=True, text=True, shell=True, check=True)
server_url = json.loads(result.stdout)[0]['servers'][0]['url']
result = subprocess.run(
inspection_command,
capture_output=True,
text=True,
shell=True,
check=True,
)
server_url = json.loads(result.stdout)[0]["servers"][0]["url"]
self.logger.debug(f"Local FaaS base URL: {server_url}")
return server_url
except subprocess.CalledProcessError as e:
Expand All @@ -68,13 +76,14 @@ def get_local_base_url(self):
return None

def deploy_remote_faas(self):
''' Deploy the project as a remote FaaS '''
"""Deploy the project as a remote FaaS"""
pass

def get_remote_base_url(self):
''' Get the base url of the deployed remote faas '''
"""Get the base url of the deployed remote faas"""


'''
"""
Paths: http://localhost:9000/aee940974fd5/examples-testing/v1/call/index
Exmaple output
[
Expand Down Expand Up @@ -128,4 +137,4 @@ def get_remote_base_url(self):
}
]
'''
"""
26 changes: 14 additions & 12 deletions testing/logger.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import logging


class Logger:
''' Singleton class to manage the logging '''
"""Singleton class to manage the logging"""

_instance = None

def __init__(self):
Expand All @@ -10,28 +12,28 @@ def __init__(self):
else:
Logger._instance = self
self.logger = logging.getLogger("CLI_Tool")
self.level = "INFO" # default level
self.level = "INFO" # default level
handler = logging.StreamHandler()
formatter = logging.Formatter('%(levelname)s - %(message)s')
formatter = logging.Formatter("%(levelname)s - %(message)s")
handler.setFormatter(formatter)
self.logger.addHandler(handler)
self.logger.setLevel(logging.INFO)

@staticmethod
def get_instance():
''' Static access method for singleton '''
"""Static access method for singleton"""
if Logger._instance is None:
Logger()
return Logger._instance

def set_level(self, level):
''' Set the logging level '''
"""Set the logging level"""
level_map = {
"DEBUG": logging.DEBUG,
"INFO": logging.INFO,
"WARNING": logging.WARNING,
"ERROR": logging.ERROR,
"CRITICAL": logging.CRITICAL
"CRITICAL": logging.CRITICAL,
}
self.level = level.upper()
self.logger.setLevel(level_map.get(level.upper(), logging.INFO))
Expand All @@ -40,16 +42,16 @@ def get_level(self):
return self.level

def debug(self, msg, *args, **kwargs):
self.logger.debug('\033[94m' + msg + '\033[0m', *args, **kwargs)
self.logger.debug("\033[94m" + msg + "\033[0m", *args, **kwargs)

def info(self, msg, *args, **kwargs):
self.logger.info('\033[92m' + msg + '\033[0m', *args, **kwargs)
self.logger.info("\033[92m" + msg + "\033[0m", *args, **kwargs)

def warning(self, msg, *args, **kwargs):
self.logger.warning('\033[93m' + msg + '\033[0m', *args, **kwargs)
self.logger.warning("\033[93m" + msg + "\033[0m", *args, **kwargs)

def error(self, msg, *args, **kwargs):
self.logger.error('\033[91m' + msg + '\033[0m', *args, **kwargs)
self.logger.error("\033[91m" + msg + "\033[0m", *args, **kwargs)

def critical(self, msg, *args, **kwargs):
self.logger.critical('\033[95m' + msg + '\033[0m', *args, **kwargs)
self.logger.critical("\033[95m" + msg + "\033[0m", *args, **kwargs)
Loading

0 comments on commit f24ffcb

Please sign in to comment.