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

Add changelog template and create a linting pipeline #14

Merged
merged 3 commits into from
Aug 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
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
35 changes: 35 additions & 0 deletions .github/workflows/lint-and-format.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Lint and Format

on:
workflow_dispatch:
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 .
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- New feature or enhancement descriptions.
- Details about added functionality, modules, or components.

### Changed
- Details about any changes to existing functionality.
- Information about updated dependencies.

### Deprecated
- List any features that are deprecated but still available.

### Removed
- Details about removed features, components, or deprecated functionality.
- Information about dropped support for environments or dependencies.

### Fixed
- List of bug fixes, including references to issue numbers.
- Details about fixed vulnerabilities or security improvements.

### Security
- Descriptions of security-related updates and fixes.

## [Version 1.0.0] - YYYY-MM-DD
### Added
- Initial release of the project.
- Description of the core features and functionality.
44 changes: 43 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# MetaCall Test Center

![Python](https://img.shields.io/badge/python-3.12-blue.svg)

## Overview

MetaCall Test Center is a comprehensive testing framework designed for MetaCall projects and examples. It provides a structured and efficient way to define, run, and manage test cases across different environments. The primary script, `testing.py`, integrates seamlessly into CI/CD pipelines and supports local testing. This project adheres to best practices, SOLID principles, and design patterns to ensure maintainability, scalability, and ease of contribution.
Expand Down Expand Up @@ -126,9 +128,49 @@ We welcome contributions to the MetaCall Test Center! Here are a few ways you ca
- **Extend Functionality**: Implement support for additional environments or enhance existing ones.
- **Documentation**: Improve and expand the documentation to help new users and contributors.

### Guidelines
To keep the project organized and maintain a clear history, we ask that all contributors follow these guidelines:

### Contribution Process

1. **Fork the Repository**: Create a fork of the repository and make your changes in a new branch.
2. **Write Clear Commit Messages**: Use clear and descriptive commit messages that explain the changes you are making.
3. **Update the Changelog**:
- Before submitting a pull request, make sure to update the `CHANGELOG.md` file.
- Add your changes under the `Unreleased` section, categorizing them under `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`, or `Security`.
- Use bullet points to list your changes and include references to related issue numbers if applicable.
4. **Submit a Pull Request**: After making your changes and updating the changelog, submit a pull request. Make sure your pull request includes a description of the changes and why they are necessary.

### Changelog Format

- **Unreleased**: Add any new changes here before a version is released.
- **Version Tags**: When a new version is released, create a new section in the changelog with the version number and date.

### Commit and Pull Request Tips

- **Keep it Simple**: Make small, focused commits and pull requests that address one issue or feature at a time.
- **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.

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.
- Provide clear and concise commit messages.
- Open an issue to discuss potential changes before submitting significant modifications.

Thank you for contributing to this project! Your efforts help make this project better for everyone.
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):
}
]

'''
"""
Loading
Loading