Skip to content
Draft
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
2 changes: 1 addition & 1 deletion hermes.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
sources = ["cff"]

[curate]
method = "software_card"
plugin = "software_card"
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
]

Expand Down
70 changes: 49 additions & 21 deletions src/hermes_plugin_software_card/curate.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
"""Module containing the Software CaRD curation plugin for HERMES."""

import json
from pathlib import Path
from io import StringIO

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,
Expand All @@ -20,17 +22,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/"
Expand Down Expand Up @@ -65,25 +66,59 @@ 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()
ctx.prepare_step("curate")
with ctx["result"] as cache:
graph_io = StringIO()
self._validation_graph.print(format="json-ld", out=graph_io)
cache["validation"] = json.loads(graph_io.getvalue())
graph_io.close()
ctx.finalize_step("curate")

print(create_report(self._validation_graph), end="\n\n")
if self._environment is None:
print("Software CaRD plugin not running in CI environment.")
else:
Expand All @@ -95,10 +130,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)
Loading