diff --git a/ontopy/ontokit/setup.py b/ontopy/ontokit/setup.py new file mode 100644 index 00000000..259874ce --- /dev/null +++ b/ontopy/ontokit/setup.py @@ -0,0 +1,83 @@ +"""Module for the ontokit setup sub-command.""" + +# pylint: disable=fixme + +import shutil +from glob import glob +from pathlib import Path +from string import Template + + +def setup_arguments(subparsers): + """Define arguments for the setup sub-command.""" + parser = subparsers.add_parser( + "setup", + help=( + "Set up a repository with various github workflows, including " + "publishing of squashed and inferred ontologies, generation of " + "documentation, releases, etc..." + ), + ) + parser.set_defaults(subcommand=setup_subcommand) + parser.add_argument( + "root", + metavar="PATH", + help="Root folder of repository to setup.", + ) + parser.add_argument( + "--ontology-name", + "-n", + metavar="NAME", + help=( + "Name of the ontology. By default it is inferred from the base " + "name of the `root` folder." + ), + ) + parser.add_argument( + "--ontology-prefix", + "-p", + metavar="PREFIX", + help=( + "Prefix for the ontology. By default it is inferred from the " + "turtle file `{ONTOLOGY_NAME}.ttl`." + ), + ) + parser.add_argument( + "--ontology-iri", + "-i", + metavar="IRI", + help=( + "IRI for the ontology. By default it is inferred from the " + "turtle file `{ONTOLOGY_NAME}.ttl`." + ), + ) + + +def setup_subcommand(args): + """Implements the setup sub-command.""" + + thisdir = Path(__file__).resolve().parent + srcdir = thisdir / "setup" + + root = Path(args.root) + workflows_dir = root / ".github" / "workflows" + workflows_dir.mkdir(mode=0o755, parents=True, exist_ok=True) + + # TODO: infer ONTOLOGY_PREFIX and ONTOLOGY_IRI + ontology_name = args.ontology_name if args.ontology_name else root.name + ontology_prefix = args.ontology_prefix + ontology_iri = args.ontology_iri + + shutil.copy(srcdir / "emmocheck_conf.yml", root / ".github") + + for fname in glob(str(srcdir / "workflows" / "*.yml")): + template = Template(Path(fname).read_text()) + substituted = template.safe_substitute( + { + "ONTOLOGY_NAME": ontology_name, + "ONTOLOGY_PREFIX": ontology_prefix, + "ONTOLOGY_IRI": ontology_iri, + } + ) + outfile = workflows_dir / Path(fname).name + outfile.write_text(substituted) diff --git a/ontopy/ontokit/setup/emmocheck_conf.yml b/ontopy/ontokit/setup/emmocheck_conf.yml new file mode 100644 index 00000000..6fd3b4d3 --- /dev/null +++ b/ontopy/ontokit/setup/emmocheck_conf.yml @@ -0,0 +1,66 @@ +# Configurations used when running emmocheck from the ci_emmocheck workflow + +test_namespace: + exceptions: + - manufacturing.EngineeredMaterial + +test_quantity_dimension: + exceptions: + - emmo.ModelledQuantitativeProperty + - emmo.MeasuredQuantitativeProperty + - emmo.ConventionalQuantitativeProperty + - emmo.QuantitativeProperty + - emmo.Quantity + - emmo.OrdinalQuantity + - emmo.BaseQuantity + - emmo.PhysicalConstant + - emmo.PhysicalQuantity + - emmo.ExactConstant + - emmo.MeasuredConstant + - emmo.DerivedQuantity + - emmo.ISQBaseQuantity + - emmo.InternationalSystemOfQuantity + - emmo.ISQDerivedQuantity + - emmo.SIExactConstant + - microstructure.PhysicalField + - microstructure.PhysicalScalarField + - microstructure.PhysicalDiscretisedField + - microstructure.VoxelField + - microstructure.PixelField + - microstructure.PhysicalTensorField + - microstructure.PhysicalVectorField + - microstructure.ConcentrationField + - microstructure.AverageQuantity + - microstructure.ReferenceFrame + - microstructure.GlobalReferenceFrame + - microstructure.LocalReferenceFrame + - microstructure.GeneralisedDensity + - microstructure.LengthDensity # should not be ignored!!! + - microstructure.Orientation # does this have a unit? LengthFractionUnit? + - microstructure.OrientationDistribution + - microstructure.StatisticalQuantity + - microstructure.MicrostructureQuantity + +test_unit_dimension: + exceptions: + - emmo.MultipleUnit + - emmo.SubMultipleUnit + - emmo.OffSystemUnit + - emmo.PrefixedUnit + - emmo.NonPrefixedUnit + - emmo.SpecialUnit + - emmo.DerivedUnit + - emmo.BaseUnit + - emmo.UnitSymbol + - emmo.SICoherentDerivedUnit + - emmo.SINonCoherentDerivedUnit + - emmo.SISpecialUnit + - emmo.SICoherentUnit + - emmo.SIPrefixedUnit + - emmo.SIBaseUnit + - emmo.SIUnitSymbol + - emmo.SIUnit + +test_description: + exceptions: + - electrochemistry.Electrolyte diff --git a/ontopy/ontokit/setup/workflows/cd_ghpages.yml b/ontopy/ontokit/setup/workflows/cd_ghpages.yml new file mode 100644 index 00000000..1f437872 --- /dev/null +++ b/ontopy/ontokit/setup/workflows/cd_ghpages.yml @@ -0,0 +1,129 @@ +name: Deploy on GitHub Pages +on: push +#on: +# push: +# branches: [master] + +env: + ONTOLOGY_NAME: $ONTOLOGY_NAME + ONTOLOGY_PREFIX: $ONTOLOGY_PREFIX + ONTOLOGY_IRI: $ONTOLOGY_IRI + +permissions: + contents: write + + +jobs: + deploy-on-ghpages: + #concurrency: ci-${{ github.ref }} # Recommended if you intend to make multiple deployments in quick succession. + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: 3.11 + + - name: Install EMMOntoPy + run: | + pip install --upgrade pip + #pip install EMMOntoPy + pip install -U git+https://github.com/emmo-repo/EMMOntoPy.git@annotating + + - name: Install temgo and tripper + run: | + pip install . + #pip install tripper[datadoc] + #pip install -U git+https://github.com/EMMC-ASBL/tripper.git@master + pip install -U git+https://github.com/EMMC-ASBL/tripper.git@datadoc-redefine-option + + - name: Install ROBOT + run: | + mkdir bin + wget -nv https://github.com/ontodev/robot/releases/download/v1.9.6/robot.jar + mv robot.jar bin/. + curl https://raw.githubusercontent.com/ontodev/robot/master/bin/robot > bin/robot + chmod +x bin/robot + ls -l bin/ + + - name: Download Widoco + run: | + wget --quiet https://github.com/dgarijo/Widoco/releases/download/v1.4.25/widoco-1.4.25-jar-with-dependencies_JDK-17.jar + + - name: Create squashed ontology + run: | + mkdir build + cp README.md LICENSE build/. + + ontoconvert \ + -saw \ + --namespace="emmo:https://w3id.org/emmo#" \ + --namespace="${ONTOLOGY_PREFIX}:${ONTOLOGY_IRI}#" \ + ${ONTOLOGY_NAME}-dependencies.ttl \ + build/${ONTOLOGY_NAME}-dependencies.ttl + + ontoconvert \ + -sawe \ + --namespace="emmo:https://w3id.org/emmo#" \ + --namespace="${ONTOLOGY_PREFIX}:${ONTOLOGY_IRI}#" \ + --base-iri="${ONTOLOGY_IRI}#" \ + --iri="${ONTOLOGY_IRI}" \ + ${ONTOLOGY_NAME}.ttl \ + build/${ONTOLOGY_NAME}.ttl + + ontoconvert \ + -awe \ + --namespace="emmo:https://w3id.org/emmo#" \ + --namespace="${ONTOLOGY_PREFIX}:${ONTOLOGY_IRI}#" \ + --base-iri="${ONTOLOGY_IRI}#" \ + --iri="${ONTOLOGY_IRI}" \ + --copy-annotation="elucidation-->http://purl.org/dc/terms/description" \ + --copy-annotation="prefLabel-->http://www.w3.org/2000/01/rdf-schema#label" \ + ${ONTOLOGY_NAME}.ttl \ + build/${ONTOLOGY_NAME}-doc.ttl + + - name: Create inferred ontology + run: | + # Running HermiT via ontoconvert fails with custom datatypes. + # Use ROBOT instead. + # + #ontoconvert \ + # -sawe \ + # --base-iri="${ONTOLOGY_IRI}#" \ + # --iri="${ONTOLOGY_IRI}" \ + # --infer=HermiT \ + # ${ONTOLOGY_NAME}.ttl \ + # build/${ONTOLOGY_NAME}-inferred.ttl + # + bin/robot reason \ + --reasoner HermiT \ + --input build/${ONTOLOGY_NAME}.ttl \ + --output build/${ONTOLOGY_NAME}-inferred.ttl + + - name: Generate markdown documentation of all keywords + run: | + keywords -i build/${ONTOLOGY_NAME}-doc.ttl --keywords build/${ONTOLOGY_NAME}.md --namespace-filter=${ONTOLOGY_IRI} --redefine=allow + + - name: Generate Widoco documentation + run: | + java -jar widoco-1.4.25-jar-with-dependencies_JDK-17.jar \ + -ontFile build/${ONTOLOGY_NAME}-doc.ttl \ + -outFolder build/widoco \ + -getOntologyMetadata \ + -oops \ + -rewriteAll \ + -saveConfig build/widoco/widoco.conf \ + - webVowl \ + -licensius \ + -includeAnnotationProperties + + + + - name: Deploy to GitHub Pages + uses: JamesIves/github-pages-deploy-action@v4 + with: + folder: build + branch: gh-pages diff --git a/ontopy/ontokit/setup/workflows/cd_release.yml b/ontopy/ontokit/setup/workflows/cd_release.yml new file mode 100644 index 00000000..63bf9331 --- /dev/null +++ b/ontopy/ontokit/setup/workflows/cd_release.yml @@ -0,0 +1,40 @@ +name: Release new version + +on: + release: + types: [published] + +env: + ONTOLOGY_NAME: $ONTOLOGY_NAME + TAG: ${{ github.ref_name }} + +permissions: + contents: write + +jobs: + release_version: + runs-on: ubuntu-latest + + steps: + - name: Checkout gh-pages + uses: actions/checkout@v4 + with: + ref: gh-pages + + - name: Create and copy generated files to versions/ + run: | + mkdir -p versions/${TAG#v} + cp -f \ + README.md \ + ${ONTOLOGY_NAME}.ttl \ + ${ONTOLOGY_NAME}-dependencies.ttl \ + ${ONTOLOGY_NAME}-inferred.ttl \ + versions/${TAG#v}/. + + - name: Push to gh-pages + run: | + git config --global user.email "${ONTOLOGY_NAME}@emmc.eu" + git config --global user.name "${ONTOLOGY_NAME}" + git add versions/${TAG#v} + git commit -m "Release version ${TAG#v}" + git push origin gh-pages diff --git a/ontopy/ontokit/setup/workflows/ci_tests.yml b/ontopy/ontokit/setup/workflows/ci_tests.yml new file mode 100644 index 00000000..a3655437 --- /dev/null +++ b/ontopy/ontokit/setup/workflows/ci_tests.yml @@ -0,0 +1,28 @@ +name: CI tests +on: [push] + +env: + ONTOLOGY_NAME: $ONTOLOGY_NAME + +jobs: + ci_testing: + concurrency: ci-${{ github.ref }} # Recommended if you intend to make multiple deployments in quick succession. + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: 3.11 + + - name: Install EMMOntoPy + run: | + pip install --upgrade pip + pip install EMMOntoPy + + - name: Test + run: | + emmocheck --configfile=.github/emmocheck_conf.yml ${ONTOLOGY_NAME}.ttl diff --git a/tools/ontokit b/tools/ontokit new file mode 100755 index 00000000..c807664c --- /dev/null +++ b/tools/ontokit @@ -0,0 +1,42 @@ +#!/usr/bin/env python +"""General toolkit for managing ontologies.""" +import argparse +from ontopy.ontokit.setup import setup_arguments + + +def main(argv: "list" = None): + """Main function. + + Arguments: + argv: List of arguments, similar to `sys.argv[1:]`. + Mainly for testing purposes, since it allows one to invoke the tool + manually / through Python. + + """ + # General options + parser = argparse.ArgumentParser( + description=__doc__, + # usage="ontokit [GENERAL_OPTIONS] SUBCOMMAND [SUBCOMMAND_OPTIONS]" + ) + parser.add_argument( + "--debug", action="store_true", help="Show Python traceback on error." + ) + + # Add sub-command arguments + subparsers = parser.add_subparsers(required=True, help="Subcommands:") + setup_arguments(subparsers) + + args = parser.parse_args(argv) + + # Call the subcommand handler + try: + return args.subcommand(args) + except Exception as exc: # pylint: disable=broad-exception-caught + if args.debug: + raise + print(f"{exc.__class__.__name__}: {exc}") + return exc + + +if __name__ == "__main__": + main()