Skip to content

Commit

Permalink
Add CI workflow and code review changes
Browse files Browse the repository at this point in the history
workflow for schema update has been added. Somre refactoring to get
100 test coverage requirement and apply code review comments.
  • Loading branch information
emikeb committed Jul 29, 2024
1 parent b4a87fc commit 0fee64e
Show file tree
Hide file tree
Showing 10 changed files with 152 additions and 172 deletions.
39 changes: 39 additions & 0 deletions .github/workflows/update-schema.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
name: Update Schema

"on":
push:
branches:
- main
workflow_dispatch:
inputs: {}

jobs:
generate-schema:
name: Generate and Upload Schema
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.12"

- name: Install
run: python -m pip install retasc

- name: Generate schema
run: retasc generate-schema schema.yaml

- name: Prepare deployment directory
run: |
mkdir -p public
cp schema.yaml public/
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: public
publish_branch: gh-pages
22 changes: 14 additions & 8 deletions src/retasc/__main__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-3.0-or-later
import argparse
import sys

from retasc import __doc__ as doc
from retasc import __version__
Expand All @@ -27,17 +28,22 @@ def parse_args():

generate_parser = subparsers.add_parser("generate-schema", help="Generate a schema")
generate_parser.add_argument(
"schema_file", type=str, help="Path to the schema file to generate"
"schema_file", type=str, help="Output schema file to generate"
)

return parser.parse_args()


args = parse_args()
init_logging()
init_tracing()
def main():
args = parse_args()
init_logging()
init_tracing()

if args.command == "validate-rule":
validate_rule(args.rule_file)
elif args.command == "generate-schema":
generate_schema(args.schema_file)
try:
if args.command == "validate-rule":
validate_rule(args.rule_file)
elif args.command == "generate-schema":
generate_schema(args.schema_file)
except Exception as e:
print(f"An error occurred: {e}")
sys.exit(1)
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
version: 1
name: "Example Rule"
prerequisites:
pp_schedule_item_name: "Release Date"
Expand Down
18 changes: 10 additions & 8 deletions src/retasc/validator/generate_schema.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import sys
import logging

import yaml

from retasc.validator.models import Rule

logger = logging.getLogger(__name__)

def generate_schema(output_path="src/retasc/validator/schemas/rules_schema.yaml"):

def generate_schema(output_path: str) -> None:
schema = Rule.model_json_schema()
schema_yaml = yaml.dump(schema, sort_keys=False)
with open(output_path, "w") as schema_file:
schema_file.write(schema_yaml)


if __name__ == "__main__":
generate_schema(sys.argv[1])
try:
with open(output_path, "w") as schema_file:
schema_file.write(schema_yaml)
except Exception as e:
logger.error(f"Error generating schema: {e}")
raise e
19 changes: 6 additions & 13 deletions src/retasc/validator/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
class JiraIssue(BaseModel):
"""Represents a Jira issue, which can have subtasks."""

template: str = Field(..., description="The template string for the jira issue.")
template: str = Field(description="The template string for the jira issue.")
subtasks: list["JiraIssue"] = Field(
default=[], description="The subtasks for the jira issue."
)
Expand All @@ -13,11 +13,8 @@ class JiraIssue(BaseModel):
class Prerequisites(BaseModel):
"""Defines the prerequisites needed for a rule."""

pp_schedule_item_name: str = Field(
..., description="The name of the pp schedule item."
)
pp_schedule_item_name: str = Field(description="The name of the pp schedule item.")
days_before_or_after: int = Field(
...,
description=(
"The number of days to adjust the schedule relative to the PP schedule item date. "
"A negative value indicates the number of days before the PP schedule item date, "
Expand All @@ -34,11 +31,7 @@ class Prerequisites(BaseModel):
class Rule(BaseModel):
"""Represents a rule which includes prerequisites and Jira issues."""

version: int = Field(..., description="The version of the rule.")
name: str = Field(..., description="The name of the rule.")
prerequisites: Prerequisites = Field(
..., description="The prerequisites for the rule."
)
jira_issues: list[JiraIssue] = Field(
..., description="The jira issues for the rule."
)
version: int = Field(description="The version of the rule.")
name: str = Field(description="The name of the rule.")
prerequisites: Prerequisites = Field(description="The prerequisites for the rule.")
jira_issues: list[JiraIssue] = Field(description="The jira issues for the rule.")
63 changes: 0 additions & 63 deletions src/retasc/validator/schemas/rules_schema.yaml

This file was deleted.

11 changes: 2 additions & 9 deletions src/retasc/validator/validate_rules.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,24 @@
import logging
import sys

import yaml
from pydantic import ValidationError

from retasc.retasc_logging import init_logging
from retasc.validator.models import Rule

init_logging()
logger = logging.getLogger(__name__)


def validate_rule(rule_file):
def validate_rule(rule_file: str) -> bool:
with open(rule_file) as file:
rule_data = yaml.safe_load(file)
return validate_rule_dict(rule_data)


def validate_rule_dict(rule_data):
def validate_rule_dict(rule_data: dict) -> bool:
try:
Rule(**rule_data)
logger.info("The rule is valid.")
return True
except ValidationError as err:
logger.error(f"The rule is invalid: {err}")
return False


if __name__ == "__main__":
validate_rule(sys.argv[1])
20 changes: 5 additions & 15 deletions tests/test_generate_schema.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import sys
from runpy import run_module
from unittest.mock import patch

import pytest
import yaml

from retasc.validator.generate_schema import generate_schema
Expand All @@ -18,14 +15,7 @@ def test_generate_schema(tmp_path):
assert schema == expected_schema


def test_generate_schema_script(tmp_path):
schema_file = tmp_path / "rules_schema.yaml"

with patch.object(sys, "argv", ["generate_schema", str(schema_file)]):
run_module("retasc.validator.generate_schema", run_name="__main__")

with open(schema_file) as f:
schema = yaml.safe_load(f)

expected_schema = Rule.model_json_schema()
assert schema == expected_schema
def test_generate_schema_exception():
with pytest.raises(Exception) as e:
generate_schema(output_path=".")
assert "Is a directory" in str(e.value)
45 changes: 27 additions & 18 deletions tests/test_main.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# SPDX-License-Identifier: GPL-3.0-or-later
import sys
from runpy import run_module
from unittest.mock import MagicMock, patch
from unittest.mock import patch

from pytest import mark, raises

from retasc.__main__ import main


def run_main(*args, code=None):
with patch.object(sys, "argv", ["retasc", *args]):
if code is None:
run_module("retasc")
main()
return

with raises(SystemExit) as e:
run_module("retasc")

main()
assert e.value.code == code


Expand Down Expand Up @@ -43,19 +43,28 @@ def test_dummy_run(capsys):
assert stderr == ""


def test_validate_rule_called(tmp_path):
rule_file = "mock"
with patch(
"retasc.validator.validate_rules.validate_rule", MagicMock(return_value=True)
) as mock_validate_rule:
run_main("validate-rule", str(rule_file), code=None)
mock_validate_rule.assert_called_once_with(str(rule_file))
@patch("retasc.__main__.validate_rule")
def test_validate_rule(mock_validate_rule, capsys):
run_main("validate-rule", "test_rule.yaml")
mock_validate_rule.assert_called_once_with("test_rule.yaml")
stdout, stderr = capsys.readouterr()
assert stdout == ""
assert stderr == ""


@patch("retasc.__main__.generate_schema")
def test_generate_schema(mock_generate_schema, capsys):
run_main("generate-schema", "output_schema.json")
mock_generate_schema.assert_called_once_with("output_schema.json")
stdout, stderr = capsys.readouterr()
assert stdout == ""
assert stderr == ""


def test_generate_schema_called():
schema_file = "mock"
def test_main_exception(capsys):
with patch(
"retasc.validator.generate_schema.generate_schema", MagicMock(return_value=True)
) as mock_generate_schema:
run_main("generate-schema", str(schema_file), code=None)
mock_generate_schema.assert_called_once_with(str(schema_file))
"retasc.__main__.validate_rule", side_effect=Exception("Test exception")
):
run_main("validate-rule", "test_rule.yaml", code=1)
stdout, stderr = capsys.readouterr()
assert "An error occurred: Test exception" in stdout
Loading

0 comments on commit 0fee64e

Please sign in to comment.