diff --git a/hermes.toml b/hermes.toml index c83d9fa..8957f87 100644 --- a/hermes.toml +++ b/hermes.toml @@ -7,4 +7,4 @@ sources = ["cff"] [curate] -method = "software_card" +plugin = "software_card" diff --git a/pyproject.toml b/pyproject.toml index 1b16f2e..f67851b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ classifiers = [ ] requires-python = ">=3.11" dependencies = [ - "hermes @ git+https://github.com/softwarepub/hermes.git@develop", + "hermes @ git+https://github.com/softwarepub/hermes.git@refactor/data-model", "software-card-policies @ git+https://github.com/softwarepub/software-card-policies.git", ] diff --git a/src/hermes_plugin_software_card/curate.py b/src/hermes_plugin_software_card/curate.py index 3fe7f70..370e22b 100644 --- a/src/hermes_plugin_software_card/curate.py +++ b/src/hermes_plugin_software_card/curate.py @@ -6,9 +6,10 @@ """Module containing the Software CaRD curation plugin for HERMES.""" import json -from pathlib import Path -from hermes.commands.curate.base import BaseCuratePlugin +from hermes.commands.curate.base import HermesCurateCommand, HermesCuratePlugin +from hermes.model import SoftwareMetadata +from hermes.model.hermes_cache import HermesCacheManager from software_card_policies.config import Config from software_card_policies.data_model import ( make_shacl_graph, @@ -20,17 +21,16 @@ from hermes_plugin_software_card import environment -class SoftwareCaRDCuratePlugin(BaseCuratePlugin): +class SoftwareCaRDCuratePlugin(HermesCuratePlugin): """Software CaRD curation plugin.""" - def __init__(self, command, ctx): + def __init__(self): """Initialize the plugin.""" - super().__init__(command, ctx) + super().__init__() self._data_graph = None self._shacl_graph = None self._conforms = False self._validation_graph = None - self._report = None self._environment = environment.get() self._app_base_url = "https://software-metadata.pub/software-card/" @@ -65,25 +65,55 @@ def __init__(self, command, ctx): } } - def prepare(self): + def __call__( + self, + command: HermesCurateCommand, # noqa: ARG002 + metadata: SoftwareMetadata, + ) -> SoftwareMetadata: + """Entry point of the callable. + + This method runs the main logic of the plugin. It calls the other methods of the + object in the correct order. Depending on the result of + ``is_publication_approved`` either the valid metadata or a new, empty + ``SoftwareMetadata`` object is returned. + """ + self.prepare(metadata) + self.validate() + self.create_report() + + if not self.is_publication_approved(): + return SoftwareMetadata() + + return metadata + + def prepare(self, metadata: SoftwareMetadata): """Prepare the validation. - The metadata given in the context is parsed as an RDF graph and then validated - using the Software CaRD validation. + The metadata given in ``metadata`` is parsed as an RDF graph for validation. """ - text = json.dumps(self.ctx.get_data()["curate"]) - self._data_graph = read_rdf_resource(format="json-ld", data=text) + self._data_graph = read_rdf_resource( + format="json-ld", data=json.dumps(metadata.ld_value) + ) self._shacl_graph = make_shacl_graph(Config.from_dict(self._validation_config)) def validate(self): - """Run Software CaRD validation.""" + """Run Software CaRD validation on the given software metadata.""" conforms, validation_graph = validate_graph(self._data_graph, self._shacl_graph) self._conforms = conforms self._validation_graph = validation_graph def create_report(self): - """Create basic text report.""" - self._report = create_report(self._validation_graph) + """Create validation report. + + This creates the report both as a machine-readble JSON-LD file, and prints a + human-readable report, and the URL to the Software CaRD web app to the screen. + """ + ctx = HermesCacheManager() + validation_file = ctx.cache_dir / "curate" / "validation.json" + validation_file.parent.mkdir(exist_ok=True, parents=True) + self._validation_graph.serialize(validation_file, format="json-ld") + + print(create_report(self._validation_graph), end="\n\n") if self._environment is None: print("Software CaRD plugin not running in CI environment.") else: @@ -95,10 +125,3 @@ def create_report(self): def is_publication_approved(self) -> bool: """Decide whether the publication of the software is approved.""" return self._conforms - - def process_decision_positive(self): - """Write the given metadata into the curate directory.""" - curate_output = Path(self.ctx.get_cache("curate", self.ctx.hermes_name)) - Path.mkdir(curate_output.parent) - with open(curate_output, "w") as curate_output_fh: - json.dump(self.ctx.get_data(), curate_output_fh)