-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'develop' into feature/287-governance-website-structure
- Loading branch information
Showing
12 changed files
with
608 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# SPDX-FileCopyrightText: 2024 Helmholtz-Zentrum Dresden-Rossendorf | ||
# SPDX-License-Identifier: CC-BY-SA-4.0 | ||
# SPDX-FileContributor: David Pape | ||
|
||
name: "Add Plugin to Marketplace" | ||
description: "I want to add a plugin to the Hermes plugin marketplace." | ||
title: "[New Plugin]: " | ||
labels: ["documentation"] | ||
|
||
body: | ||
- type: markdown | ||
attributes: | ||
value: | | ||
Thank you for building a plugin for Hermes and sharing it with the community! | ||
The [Hermes plugin marketplace](https://hermes.software-metadata.pub#plugins) is a curated list of plugins on our website that allows you to share plugins that you developed, and others to find them. | ||
Via this issue template, you can send us the required information to add your plugin to the marketplace. Alternatively, you may file a pull request, adding the plugin to [`plugins.json`](https://github.com/softwarepub/hermes/tree/develop/docs/source/plugins.json) yourself. | ||
- id: "name" | ||
type: "input" | ||
attributes: | ||
label: "Name" | ||
description: "The name of the plugin" | ||
placeholder: "Foobar Harvesting and Quux Deposit Plugin" | ||
validations: | ||
required: true | ||
|
||
- id: "author" | ||
type: "input" | ||
attributes: | ||
label: "Author" | ||
description: "The author of the plugin, usually a team or organization" | ||
placeholder: "Team Quux at Fizzbuzz Institute" | ||
|
||
- id: "description" | ||
type: "textarea" | ||
attributes: | ||
label: "Description" | ||
description: "A short description of your plugin" | ||
placeholder: "Plugin for harvesting foobar files and uploading deposits to quux repo." | ||
|
||
- id: "steps" | ||
type: "dropdown" | ||
attributes: | ||
label: "Steps" | ||
description: "Steps of the Hermes workflow targeted by your plugin" | ||
multiple: true | ||
options: ["harvest", "process", "curate", "deposit", "postprocess"] | ||
|
||
- id: "harvested-files" | ||
type: "input" | ||
attributes: | ||
label: "Harvested files" | ||
description: "The types of files your plugin harvests (if it is a harvest plugin)" | ||
placeholder: "foobar, foobar.yml, foobar.json" | ||
|
||
- id: "repository-url" | ||
type: "input" | ||
attributes: | ||
label: "Repository" | ||
description: "The link to the repository where users can find and inspect the source code of your plugin" | ||
placeholder: "https://git.example.com/quux/hermes-plugin-quux" | ||
|
||
- id: "pypi-url" | ||
type: "input" | ||
attributes: | ||
label: "PyPI URL" | ||
description: "The link to your project on PyPI" | ||
placeholder: "https://pypi.org/project/hermes-plugin-quux/" | ||
|
||
- id: "comments" | ||
type: "textarea" | ||
attributes: | ||
label: "Comments" | ||
description: "Any additional comments you would like to add" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
# SPDX-FileCopyrightText: 2024 Helmholtz-Zentrum Dresden-Rossendorf | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# SPDX-FileContributor: David Pape | ||
|
||
import json | ||
import re | ||
from pathlib import Path | ||
from typing import Any, Dict | ||
|
||
from docutils import nodes | ||
from jsonschema import validate | ||
from sphinx.application import Sphinx | ||
from sphinx.util import logging | ||
from sphinx.util.console import colorize | ||
from sphinx.util.docutils import SphinxDirective | ||
|
||
from hermes.commands.marketplace import ( | ||
SchemaOrgOrganization, | ||
SchemaOrgSoftwareApplication, | ||
schema_org_hermes, | ||
) | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def log_message(text: str, detail: str = None) -> None: | ||
message = colorize("bold", "[Plugin Markup]") + " " + text | ||
if detail is not None: | ||
message += " " + colorize("darkgreen", detail) | ||
logger.info(message) | ||
|
||
|
||
def keywordify(text: str) -> str: | ||
"""Make keyword-friendly text. | ||
The result will only contain lowercase a through z and hyphens, e.g.: | ||
* CITATION.cff → citation-cff | ||
* codemeta.json → codemeta-json | ||
* LICENSE → license | ||
""" | ||
text = text.casefold() | ||
return re.sub(r"[^a-z]", "-", text) | ||
|
||
|
||
def plugin_to_schema_org(plugin: Dict[str, Any]) -> SchemaOrgSoftwareApplication: | ||
"""Convert plugin metadata from the used JSON format to Schema.org. | ||
The ``plugin`` is transformed into a ``schema:SoftwareApplication``. For most | ||
attributes of the plugin, a mapping into Schema.org terms is performed. The author | ||
is expressed as a ``schema:Organization`` using the given author field as the | ||
``name``. The steps targeted by the plugin are expressed using the ``keyword`` field | ||
by transforming them to the keywords ``hermes-step-<STEP>`` where ``<STEP>`` is the | ||
name of the workflow step. The ``harvested_files`` are also transformed into | ||
keywords by making the text "keyword-friendly" and prepending ``hermes-harvest-``. | ||
If the plugin is marked as a Hermes ``builtin``, this is expressed using | ||
``schema:isPartOf``. | ||
""" | ||
steps = plugin.get("steps", []) | ||
keywords = [f"hermes-step-{step}" for step in steps] | ||
if "harvest" in steps: | ||
harvested_files = plugin.get("harvested_files", []) | ||
keywords += [f"hermes-harvest-{keywordify(file)}" for file in harvested_files] | ||
|
||
return SchemaOrgSoftwareApplication( | ||
name=plugin.get("name"), | ||
url=plugin.get("repository_url"), | ||
install_url=plugin.get("pypi_url"), | ||
abstract=plugin.get("description"), | ||
author=SchemaOrgOrganization(name=au) if (au := plugin.get("author")) else None, | ||
is_part_of=schema_org_hermes if plugin.get("builtin", False) else None, | ||
keywords=keywords or None, | ||
) | ||
|
||
|
||
class PluginMarkupDirective(SphinxDirective): | ||
"""A Sphinx directive to render the ``plugins.json`` file to Schema.org markup. | ||
The plugins file and its jsonschema are passed to the directive as parameters, i.e., | ||
in Markdown: | ||
.. code-block:: markdown | ||
```{plugin-markup} path/to/plugins.json path/to/plugins-schema.json | ||
``` | ||
For each plugin listed in the file, a ``<script type="application/ld+json">`` tag | ||
is generated. | ||
""" | ||
|
||
required_arguments = 2 | ||
|
||
def run(self) -> list[nodes.Node]: | ||
filename = Path(self.get_source_info()[0]) # currently processing this file | ||
directory = filename.parent | ||
|
||
plugins_file = directory / self.arguments[0] | ||
log_message("reading plugins file", detail=str(plugins_file)) | ||
with open(plugins_file) as file: | ||
plugin_data = json.load(file) | ||
|
||
plugins_schema_file = directory / self.arguments[1] | ||
log_message("reading plugins schema file", detail=str(plugins_schema_file)) | ||
with open(plugins_schema_file) as file: | ||
plugin_schema = json.load(file) | ||
|
||
log_message("validating plugins") | ||
validate(plugin_data, plugin_schema) | ||
|
||
log_message("converting plugins to markup") | ||
tags = [] | ||
for plugin in plugin_data: | ||
markup = plugin_to_schema_org(plugin).model_dump_jsonld() | ||
tag = f'<script type="application/ld+json">{markup}</script>' | ||
tags.append(nodes.raw(text=tag, format="html")) | ||
|
||
return tags | ||
|
||
|
||
def setup(app: Sphinx): | ||
"""Wire up the directive so that it can be used as ``plugin-markup``.""" | ||
app.add_directive("plugin-markup", PluginMarkupDirective) | ||
return { | ||
"version": "0.1", | ||
"parallel_read_safe": True, | ||
"parallel_write_safe": True, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
{# | ||
SPDX-FileCopyrightText: 2024 Helmholtz-Zentrum Dresden-Rossendorf | ||
SPDX-License-Identifier: CC-BY-SA-4.0 | ||
SPDX-FileContributor: David Pape | ||
#} | ||
|
||
{% for step in ("harvest", "process", "curate", "deposit", "postprocess") %} | ||
|
||
### {{ step|title }} | ||
|
||
<ul> | ||
{%- for plugin in data -%} | ||
{%- if step in plugin.steps -%} | ||
<li style="margin-top: 0.5rem;"> | ||
{%- if plugin.repository_url -%} | ||
<a href="{{ plugin.repository_url }}" rel="nofollow">{{ plugin.name }}</a> | ||
{%- else -%} | ||
{{ plugin.name }} | ||
{%- endif -%} | ||
<span style="color: gray;"> by <em>{{ plugin.author }}</em><br></span> | ||
{%- if plugin.description -%} | ||
{{ plugin.description }}<br> | ||
{%- endif -%} | ||
{%- if plugin.builtin -%} | ||
<span style="color: gray;">This plugin is built into Hermes.</span><br> | ||
{%- elif plugin.pypi_url -%} | ||
<span style="color: gray;">Install via <a href="{{ plugin.pypi_url }}">PyPI</a>.</span><br> | ||
{%- endif -%} | ||
</li> | ||
{%- endif -%} | ||
{%- endfor -%} | ||
</ul> | ||
{% endfor %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.