diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 9b47990..388ef11 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -1,80 +1,487 @@ -# Sample workflow for building and deploying a Jekyll site to GitHub Pages -name: create widoco documentation +# ============================================================================== +# WORKFLOW: Create Widoco Documentation +# ============================================================================== +# Purpose: Generates and deploys human-readable HTML documentation for the ontology +# +# This workflow: +# 1. Detects when ontology files are built/updated +# 2. Generates HTML documentation using Widoco from the *-full.owl file +# 3. Deploys documentation to GitHub Pages for public access +# +# Widoco (WIzard for DOCumenting Ontologies) creates professional documentation +# that includes: +# - Class hierarchies and definitions +# - Property descriptions and domains/ranges +# - Annotation property documentation +# - Interactive WebVOWL diagrams +# - Multi-language support (English and German) +# +# Execution Chain Position: +# setup-repo → refresh-imports → qc → [DOCS] +# +# This is the final step in the workflow chain. +# +# Read more about Widoco: https://github.com/dgarijo/Widoco +# Read more about GitHub Pages: https://docs.github.com/en/pages +# ============================================================================== +name: Create Widoco Documentation + +# ============================================================================== +# WORKFLOW TRIGGERS +# ============================================================================== +# This workflow can be triggered in three ways: +# 1. Via repository_dispatch from qc workflow (after build completes) +# 2. Automatically on pushes to main branch that modify ontology files +# 3. Manually via workflow_dispatch for forced doc regeneration +# +# Note: Pull requests trigger documentation build for validation but do not +# deploy to GitHub Pages (see deploy job conditions). +# +# IMPORTANT: Push triggers skip commits made by github-actions[bot] to prevent +# duplicate runs when the workflow chain is triggered via repository_dispatch. +# ============================================================================== on: - workflow_run: - workflows: ["build"] - types: - - completed - branches: ["main"] + # ============================================================================ + # TRIGGER 1: Repository Dispatch (from qc workflow) + # ============================================================================ + # Listens for 'trigger-docs' event dispatched by qc.yml + # This ensures documentation is generated immediately after ontology build + # ============================================================================ + repository_dispatch: + types: [trigger-docs] + + # ============================================================================ + # TRIGGER 2: Push Events to Main Branch (for production deployments) + # ============================================================================ + # Triggers when ontology files are pushed to main branch + # + # Why main branch only? + # - GitHub Pages typically deploys from main/master + # - Prevents documentation churn from feature branch work + # - Ensures only stable, reviewed changes trigger public doc updates + # + # Why src/ontology/**? + # - Documentation is generated from ontology files + # - Only relevant when ontology content changes + # - Excludes unrelated changes (README, workflow files, etc.) + # + # To enable preview docs for other branches: + # Change branches: ["main"] to branches: ["*"] + # + # Note: This trigger is skipped for commits made by github-actions[bot] + # to prevent duplicate runs when triggered via repository_dispatch + # ============================================================================ + # push: + # branches: ["main"] # Production deployments from main only + # paths: + # - 'src/ontology/**' + + # ============================================================================ + # TRIGGER 3: Pull Request Events (for preview/validation) + # ============================================================================ + # Triggers documentation build during PR review + # Note: Deploy step is skipped for PRs (see deploy job condition) + # + # Purpose: + # - Validates that documentation can be generated successfully + # - Allows preview of documentation changes before merge + # - Catches Widoco errors early in development cycle + # # ============================================================================ + # pull_request: + # branches: ["*"] + # paths: + # - 'src/ontology/**' - # Allows you to run this workflow manually from the Actions tab + # ============================================================================ + # TRIGGER 4: Manual Trigger (for forced regeneration) + # ============================================================================ + # Allows manual execution via GitHub UI + # Useful for: + # - Forcing documentation refresh without code changes + # - Testing documentation generation + # - Recovering from failed deployments + # ============================================================================ workflow_dispatch: -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +# ============================================================================== +# ENVIRONMENT VARIABLES +# ============================================================================== +# Global variables available to all jobs in this workflow +# ============================================================================== +env: + # Default branch for git operations + DEFAULT_BRANCH: main + +# ============================================================================== +# PERMISSIONS +# ============================================================================== +# Granular permissions for GITHUB_TOKEN to enable GitHub Pages deployment +# +# Why these specific permissions? +# - contents: read : Allows reading repository files for building +# - pages: write : Enables uploading artifacts to GitHub Pages +# - id-token: write : Supports OIDC authentication for Pages deployment +# +# These are the minimum permissions needed for secure Pages deployment. +# Read more: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions +# ============================================================================== permissions: - contents: read - pages: write - id-token: write + contents: read # Read repo files + pages: write # Upload to Pages + id-token: write # OIDC authentication -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +# ============================================================================== +# CONCURRENCY CONTROL +# ============================================================================== +# Ensures only one Pages deployment runs at a time +# +# Why is this important? +# - Prevents race conditions during deployment +# - Ensures sequential processing of queued deployments +# - Avoids corrupted or partial documentation deployments +# +# Configuration: +# - group: "pages" : All Pages deployments share this concurrency group +# - cancel-in-progress: false : Don't cancel running deployments; queue instead +# +# Effect: If multiple commits trigger this workflow rapidly, they queue +# and deploy sequentially rather than racing or canceling each other. +# ============================================================================== concurrency: group: "pages" - cancel-in-progress: false + cancel-in-progress: false # Queue deployments instead of canceling +# ============================================================================== +# JOBS +# ============================================================================== jobs: - # Check job + # ============================================================================ + # JOB 1: check + # ============================================================================ + # Pre-flight check to verify required ontology file exists + # + # Purpose: + # - Prevents build failures in repositories without built ontologies + # - Skips workflow gracefully if *-full.owl doesn't exist + # - Provides clear feedback about missing files + # + # Outputs: + # - ontology-exists: Boolean flag indicating if file was found + # - ontology-file: Path to the *-full.owl file (if exists) + # + # Why check for *-full.owl? + # - This is the standard ODK output file for complete ontology releases + # - Contains merged ontology with all imports + # - Required input for Widoco documentation generation + # + # CRITICAL: Skips workflow for commits made by github-actions[bot] on push + # to prevent duplicate runs when triggered via repository_dispatch + # ============================================================================ check: runs-on: ubuntu-latest + + # CRITICAL: Skip this workflow if triggered by push from github-actions[bot] + # This prevents duplicate runs in the workflow chain + # The chain uses repository_dispatch, so push triggers from bot commits are redundant + # if: | + # github.event_name != 'push' || + # github.event.head_commit.author.name != 'github-actions[bot]' + + # Job outputs (available to dependent jobs via needs.check.outputs) outputs: ontology-exists: ${{ steps.check.outputs.exists }} ontology-file: ${{ steps.check.outputs.file }} + steps: - - name: Checkout + # ======================================================================== + # STEP 1.1: Checkout Repository + # ======================================================================== + # Fetch repository code to check for ontology file + # Full history included for consistency with other workflows + # ======================================================================== + - name: Checkout repository uses: actions/checkout@v4 + with: + fetch-depth: 0 # Full history + + # ======================================================================== + # STEP 1.2: Check for Ontology File + # ======================================================================== + # Searches for *-full.owl file in src/ontology/ + # + # Search logic: + # - find: Recursively searches directory + # - -name "*-full.owl": Matches any file ending in -full.owl + # - -type f: Only matches regular files (not directories) + # - head -1: Takes first match (handles multiple matches gracefully) + # + # Output handling: + # - If found: Sets exists=true and file= + # - If not found: Sets exists=false and file="" + # ======================================================================== - name: Check for ontology file id: check run: | + # Search for *-full.owl file ONTOLOGY_FILE=$(find src/ontology/ -name "*-full.owl" -type f | head -1) + + # Check if file was found if [ -z "$ONTOLOGY_FILE" ]; then echo "No *-full.owl file found in src/ontology/ directory." + echo "This usually means the ontology hasn't been built yet." echo "exists=false" >> $GITHUB_OUTPUT + echo "file=" >> $GITHUB_OUTPUT else echo "Found ontology file: $ONTOLOGY_FILE" echo "exists=true" >> $GITHUB_OUTPUT echo "file=$ONTOLOGY_FILE" >> $GITHUB_OUTPUT fi - # Build job + # ============================================================================ + # JOB 2: build + # ============================================================================ + # Generates HTML documentation using Widoco + # + # Dependencies: Requires check job to pass and find ontology file + # Condition: Only runs if ontology-exists == 'true' + # + # Process: + # 1. Setup GitHub Pages environment + # 2. Download Widoco JAR (pinned version for reproducibility) + # 3. Generate HTML documentation with Widoco + # 4. Create default entry point (index.html) + # 5. Upload documentation as Pages artifact + # ============================================================================ build: runs-on: ubuntu-latest + + # Job dependencies needs: check + + # Conditional execution: only run if ontology file exists if: needs.check.outputs.ontology-exists == 'true' + steps: - - name: Checkout + # ======================================================================== + # STEP 2.1: Checkout Repository + # ======================================================================== + # Fetch repository code for documentation generation + # ======================================================================== + - name: Checkout repository uses: actions/checkout@v4 + with: + fetch-depth: 0 # Full history + + # ======================================================================== + # STEP 2.2: Setup GitHub Pages Environment + # ======================================================================== + # Configures Node.js and other dependencies for Pages builds + # + # This action: + # - Detects and validates Pages configuration + # - Sets up build environment variables + # - Prepares for artifact upload + # + # Uses v5 for latest features and compatibility + # Read more: https://github.com/actions/configure-pages + # ======================================================================== - name: Setup Pages uses: actions/configure-pages@v5 - - name: Build HTML for main + + # ======================================================================== + # STEP 2.3: Build HTML Documentation with Widoco + # ======================================================================== + # Downloads and runs Widoco to generate HTML documentation + # + # Widoco Configuration: + # Version: v1.4.25 (pinned for reproducibility) + # Java Requirement: JDK 11+ (provided by runner) + # + # Command-line Options Explained: + # -ontFile + # Input: Path to the OWL ontology file + # Example: src/ontology/myonto-full.owl + # + # -outFolder + # Output: Directory for generated HTML files + # Set to ./_site for GitHub Pages compatibility + # + # -uniteSections + # Combines all documentation sections into unified pages + # Improves navigation and reduces page count + # + # -includeAnnotationProperties + # Documents annotation properties (labels, comments, etc.) + # Essential for complete ontology documentation + # + # -lang en-de + # Generates documentation in English and German + # Creates index-en.html and index-de.html + # To change languages: Use ISO codes (e.g., en-es for English/Spanish) + # + # -getOntologyMetadata + # Extracts and displays ontology metadata + # Includes: title, description, version, authors, etc. + # + # -noPlaceHolderText + # Removes placeholder text from documentation + # Creates cleaner, more professional output + # + # -rewriteAll + # Forces complete regeneration of all files + # Ensures documentation is fully up-to-date + # + # -webVowl + # Includes interactive WebVOWL visualization + # Provides graphical view of ontology structure + # Users can explore classes and relationships visually + # + # Memory Requirements: + # - Typical usage: 2-4GB RAM + # - Large ontologies may need more memory (adjust runner if needed) + # - Widoco uses Java, so heap size is configurable via JAVA_OPTS + # + # Output Files: + # - index-en.html : English documentation + # - index-de.html : German documentation + # - sections/ : Individual documentation sections + # - webvowl/ : WebVOWL visualization files + # - resources/ : CSS, JavaScript, images + # + # Read more: https://github.com/dgarijo/Widoco#usage + # ======================================================================== + - name: Build HTML documentation with Widoco run: | + # Download pinned Widoco release for reproducibility + # Using specific version ensures consistent output across builds + echo "Downloading Widoco v1.4.25..." wget -O widoco.jar https://github.com/dgarijo/Widoco/releases/download/v1.4.25/widoco-1.4.25-jar-with-dependencies_JDK-11.jar + + # Create output directory for GitHub Pages mkdir ./_site - java -jar widoco.jar -ontFile ${{ needs.check.outputs.ontology-file }} -outFolder ./_site -uniteSections -includeAnnotationProperties -lang en-de -getOntologyMetadata -noPlaceHolderText -rewriteAll -webVowl - - name: add default entry point + + # Generate documentation with Widoco + echo "Generating documentation with Widoco..." + java -jar widoco.jar \ + -ontFile ${{ needs.check.outputs.ontology-file }} \ + -outFolder ./_site \ + -uniteSections \ + -includeAnnotationProperties \ + -lang en-de \ + -getOntologyMetadata \ + -noPlaceHolderText \ + -rewriteAll \ + -webVowl + + echo "Documentation generation complete." + + # ======================================================================== + # STEP 2.4: Add Default Entry Point + # ======================================================================== + # Creates index.html as default landing page for GitHub Pages + # + # Why is this needed? + # - GitHub Pages serves index.html by default + # - Widoco generates index-en.html, index-de.html, etc. + # - Without index.html, Pages shows directory listing or 404 + # + # Solution: Copy English version to index.html + # - Provides default language for visitors + # - Users can switch to other languages via links in documentation + # + # To change default language: + # Replace index-en.html with index-de.html (or other language code) + # ======================================================================== + - name: Add default entry point run: | + echo "Creating default index.html from English version..." cp ./_site/index-en.html ./_site/index.html - - name: Upload artifact + echo "Default entry point created." + + # ======================================================================== + # STEP 2.5: Upload Pages Artifact + # ======================================================================== + # Packages documentation for GitHub Pages deployment + # + # What this does: + # - Compresses _site/ directory into artifact + # - Uploads artifact to GitHub (accessible to deploy job) + # - Prepares documentation for deployment + # + # Artifact contents: + # - All HTML files (index.html, sections, etc.) + # - WebVOWL visualization files + # - CSS, JavaScript, images + # - Multi-language documentation + # + # Uses v3 for stability + # Read more: https://github.com/actions/upload-pages-artifact + # ======================================================================== + - name: Upload Pages artifact uses: actions/upload-pages-artifact@v3 - # Deployment job + # ============================================================================ + # JOB 3: deploy + # ============================================================================ + # Deploys generated documentation to GitHub Pages + # + # Dependencies: Requires build job to complete successfully + # Condition: Only runs for non-PR events (prevents PR preview deployments) + # + # Environment: github-pages + # - Protected environment for production deployments + # - Can require approvals if configured in repo settings + # - Provides deployment URL for accessing published docs + # + # Process: + # 1. Downloads artifact from build job + # 2. Deploys to GitHub Pages + # 3. Returns public URL for documentation + # ============================================================================ deploy: + # Environment configuration + # Uses 'github-pages' environment for protected deployments + # Output URL is accessible via steps.deployment.outputs.page_url environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + + # Job dependencies needs: build + + # Conditional execution: skip for pull requests + # Why? + # - PRs shouldn't auto-deploy to production Pages + # - Prevents documentation churn during review + # - Deploy happens automatically after PR merge to main + # + # For branch-specific previews: + # Remove this condition and configure GitHub Pages to use branch deployments + if: github.event_name != 'pull_request' + steps: + # ======================================================================== + # STEP 3.1: Deploy to GitHub Pages + # ======================================================================== + # Deploys documentation artifact to GitHub Pages + # + # What this does: + # 1. Downloads artifact uploaded by build job + # 2. Extracts files to Pages hosting environment + # 3. Publishes documentation at configured Pages URL + # 4. Returns deployment URL as output + # + # Deployment URL format: + # - https://.github.io// (for user/org repos) + # - https://.github.io// (for org repos) + # - Custom domain if configured in repo Pages settings + # + # Uses v4 for latest deployment features + # Read more: https://github.com/actions/deploy-pages + # ======================================================================== - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@v4 \ No newline at end of file diff --git a/.github/workflows/qc.yml b/.github/workflows/qc.yml index 3af3d69..c5d7b52 100644 --- a/.github/workflows/qc.yml +++ b/.github/workflows/qc.yml @@ -1,39 +1,290 @@ -# Basic ODK workflow +# ============================================================================== +# WORKFLOW: Build Ontology (Quality Control) +# ============================================================================== +# Purpose: Builds ontology release assets and performs quality control checks +# +# This workflow: +# 1. Refreshes imports to ensure consistency +# 2. Generates release artifacts (OWL, JSON-LD, Turtle, etc.) +# 3. Runs quality control checks (syntax, consistency, etc.) +# 4. Commits generated assets back to the repository +# 5. Triggers the documentation workflow to continue the chain +# +# This is the core build workflow that transforms the edit file +# (*-edit.owl) into production-ready ontology releases in multiple formats. +# +# Execution Chain Position: +# setup-repo → refresh-imports → [BUILD/QC] → docs +# +# Read more about ODK builds: +# https://github.com/INCATools/ontology-development-kit#building-the-ontology +# ============================================================================== -name: build +name: Build Ontology -# Controls when the action will run. +# ============================================================================== +# WORKFLOW TRIGGERS +# ============================================================================== +# This workflow can be triggered in three ways: +# 1. Via repository_dispatch from refresh-imports workflow (after imports refresh) +# 2. Automatically on pushes that modify ontology source files +# 3. Manually via workflow_dispatch for forced builds +# +# Path filters ensure the workflow only runs when ontology files change, +# preventing unnecessary builds on unrelated commits (README, docs, etc.). +# +# IMPORTANT: Push triggers skip commits made by github-actions[bot] to prevent +# duplicate runs when the workflow chain is triggered via repository_dispatch. +# ============================================================================== on: - # Triggers the workflow on push or pull request events but only for the main branch - push: - branches: ["*"] - pull_request: - branches: ["*"] + # ============================================================================ + # TRIGGER 1: Repository Dispatch (from refresh-imports workflow) + # ============================================================================ + # Listens for 'trigger-qc' event dispatched by refresh-imports.yml + # This ensures build runs immediately after imports are refreshed + # ============================================================================ + repository_dispatch: + types: [trigger-qc] - # Allows you to run this workflow manually from the Actions tab + # ============================================================================ + # TRIGGER 2: Push Events (for regular development) + # ============================================================================ + # Triggers when any file in src/ontology/ is modified and pushed + # + # Why src/ontology/**? + # - Catches changes to edit files, components, imports, metadata + # - Ensures builds run after ontology content updates + # - Excludes unrelated changes (documentation, root README, etc.) + # + # Examples of files that trigger: + # - src/ontology/myonto-edit.owl (main edit file) + # - src/ontology/components/*.owl (component modules) + # - src/ontology/imports/*.owl (import modules) + # - src/ontology/Makefile (build configuration) + # + # Note: This trigger is skipped for commits made by github-actions[bot] + # to prevent duplicate runs when triggered via repository_dispatch + # ============================================================================ + # push: + # branches: ["*"] # Triggers on any branch + # paths: + # - 'src/ontology/**' + + # ============================================================================ + # TRIGGER 3: Pull Request Events (for PR validation) + # ============================================================================ + # Same as push trigger, but for pull requests + # Runs QC checks on PR branches to validate changes before merge + # Note: Commits are skipped for PRs (see commit step conditions) + # ============================================================================ + # pull_request: + # branches: ["*"] + # paths: + # - 'src/ontology/**' + + # ============================================================================ + # TRIGGER 4: Manual Trigger (for forced builds) + # ============================================================================ + # Allows manual execution via GitHub UI + # Useful for: + # - Testing build process without code changes + # - Forcing rebuild after external changes + # - Troubleshooting build issues + # ============================================================================ workflow_dispatch: -# A workflow run is made up of one or more jobs that can run sequentially or in parallel +# ============================================================================== +# ENVIRONMENT VARIABLES +# ============================================================================== +# Global variables available to all jobs in this workflow +# ============================================================================== +env: + # Default branch for git operations (used in some ODK make targets) + DEFAULT_BRANCH: main + +# ============================================================================== +# JOBS +# ============================================================================== jobs: - # This workflow contains a single job called "ontology_qc" + # ============================================================================ + # JOB: ontology_qc + # ============================================================================ + # Main job that performs the complete build and QC process + # + # Process Flow: + # 1. Checkout repository with full history + # 2. Refresh imports (ensures consistency) + # 3. Build all release assets (OWL, JSON-LD, Turtle, etc.) + # 4. Commit generated files back to repository + # 5. Trigger documentation workflow + # + # Container: ODK full image with all build tools + # + # CRITICAL: Skips workflow for commits made by github-actions[bot] on push + # to prevent duplicate runs when triggered via repository_dispatch + # ============================================================================ ontology_qc: - # The type of runner that the job will run on + # Use latest Ubuntu runner for stability runs-on: ubuntu-latest + + # CRITICAL: Skip this workflow if triggered by push from github-actions[bot] + # This prevents duplicate runs in the workflow chain + # The chain uses repository_dispatch, so push triggers from bot commits are redundant + # if: | + # github.event_name != 'push' || + # github.event.head_commit.author.name != 'github-actions[bot]' + + # Grant write permissions for committing generated assets + permissions: + contents: write + + # Use ODK container for consistent build environment + # Version v1.6 pinned for reproducibility + # Includes: ROBOT, OWLTools, make, Java, Python, reasoning tools container: obolibrary/odkfull:v1.6 - # Steps represent a sequence of tasks that will be executed as part of the job steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v4 + # ======================================================================== + # STEP 1: Checkout Repository + # ======================================================================== + # Fetch complete repository with full git history + # + # Why fetch-depth: 0? + # - Full history may be needed for ODK make targets + # - Allows git operations that reference commits/branches + # - Required for accurate versioning in releases + # ======================================================================== + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Full history + # ======================================================================== + # STEP 2: Build Ontology + # ======================================================================== + # Runs ODK make targets to build complete ontology release + # + # Make Targets: + # 1. refresh-imports: Updates external ontology modules (ensures consistency) + # 2. all_assets: Generates all release artifacts + # + # What all_assets generates: + # - {id}-full.owl : Complete ontology with all imports merged + # - {id}-base.owl : Core ontology without imports + # - {id}.owl : Main release file (typically same as -full) + # - {id}.json : JSON-LD serialization + # - {id}.ttl : Turtle serialization + # - {id}-simple.owl : Simplified version (if configured) + # - {id}-non-classified.owl : Pre-reasoning version (if configured) + # - Component files : Individual module builds + # - Report files : QC reports and statistics + # + # Environment Variables: + # - ROBOT_ENV: Sets Java heap size for ROBOT tool + # - ROBOT_JAVA_ARGS=-Xmx6G: Allocates 6GB RAM for reasoning/validation + # + # Why 6GB? + # - Large ontologies require significant memory for reasoning + # - Prevents OutOfMemory errors during classification + # - Adjust if builds fail with OOM errors (increase) or if builds + # are fast and memory-constrained (decrease) + # ======================================================================== - name: Build ontology env: - DEFAULT_BRANCH: main - run: cd src/ontology && make refresh-imports all_assets ROBOT_ENV='ROBOT_JAVA_ARGS=-Xmx6G' - - name: Commit files # commit the src folder + # Configure ROBOT tool memory allocation + # Increase if builds fail with OutOfMemory errors + ROBOT_ENV: 'ROBOT_JAVA_ARGS=-Xmx6G' + run: | + # Navigate to ontology source directory + cd src/ontology + + # Run ODK build targets + # - refresh-imports: Update external imports first + # - all_assets: Generate all release files + make refresh-imports all_assets + + # ======================================================================== + # STEP 3: Commit Ontology Assets + # ======================================================================== + # Commits generated release files back to the repository + # + # Conditions: + # - Only runs for push/dispatch events (not pull requests) + # - Only commits if changes detected (action skips empty commits) + # + # What gets committed: + # - src/ontology/*.owl : All OWL release files + # - src/ontology/*.json : JSON-LD serializations + # - src/ontology/*.ttl : Turtle serializations + # - src/ontology/imports/*.owl : Updated import modules + # + # Why --force flag? + # - Generated files are often in .gitignore + # - --force overrides gitignore rules for these specific files + # - Ensures release assets are tracked in version control + # + # Git History Note: + # - Author: github-actions[bot] (distinguishes from human commits) + # - Message: Clearly indicates automated build + # - Allows easy filtering of bot commits in git log + # ======================================================================== + - name: Commit ontology assets + # Skip commits for pull requests (review changes manually in PR) + if: github.event_name != 'pull_request' uses: EndBug/add-and-commit@v9 with: - message: "updated ontology" - add: "*.* --force" - cwd: "./src/" + # Descriptive commit message for git history + message: "Building the ontology from the edits" + + # Working directory (repository root) + cwd: "." + + # Add generated files, forcing inclusion despite .gitignore + # Pattern breakdown: + # - src/ontology/*.owl : All OWL files (base, full, simple, etc.) + # - src/ontology/*.json : JSON-LD serializations + # - src/ontology/*.ttl : Turtle serializations + # - src/ontology/imports/*.owl : Import modules + add: "src/ontology/*.owl src/ontology/*.json src/ontology/*.ttl src/ontology/imports/*.owl --force" + + # Use GitHub Actions bot as commit author default_author: github_actions + + # Push to current branch + push: true + + # ======================================================================== + # STEP 4: Trigger Documentation Workflow + # ======================================================================== + # Dispatches repository event to start the documentation generation workflow + # + # Workflow Chain: + # setup-repo → refresh-imports → qc → [DOCS] + # + # Why trigger docs after QC? + # - Documentation is generated from release assets (*-full.owl) + # - Ensures docs reflect the latest built ontology + # - Keeps documentation synchronized with ontology content + # + # Why repository_dispatch? + # - Allows explicit workflow chaining + # - Maintains clear separation between workflow stages + # - Prevents race conditions with concurrent triggers + # + # Condition: Only trigger for non-PR events + # - PRs get preview docs via push trigger after merge + # - Prevents duplicate doc builds during PR review + # + # Event type: trigger-docs + # Listened for by: docs.yml + # ======================================================================== + - name: Trigger Documentation Workflow + # Skip for pull requests (docs will build via push trigger after PR merge) + if: github.event_name != 'pull_request' + uses: peter-evans/repository-dispatch@v3 + with: + # Use default GitHub token (automatically available) + token: ${{ secrets.GITHUB_TOKEN }} + + # Event name that docs.yml listens for + event-type: trigger-docs \ No newline at end of file diff --git a/.github/workflows/refresh-imports.yml b/.github/workflows/refresh-imports.yml new file mode 100644 index 0000000..3a58850 --- /dev/null +++ b/.github/workflows/refresh-imports.yml @@ -0,0 +1,328 @@ +# ============================================================================== +# WORKFLOW: Refresh Ontology Imports +# ============================================================================== +# Purpose: Updates external ontology import modules to maintain consistency +# with upstream ontologies +# +# This workflow: +# 1. Detects changes to import-related files or receives trigger from setup-repo +# 2. Runs ODK make targets to refresh external ontology modules +# 3. Commits updated import files back to the repository +# 4. Triggers the QC workflow to continue the automation chain +# +# External imports are OWL files that include terms from other ontologies +# (e.g., BFO, PATO, CHEBI). Keeping them updated ensures consistency. +# +# Execution Chain Position: +# setup-repo → [REFRESH-IMPORTS] → qc → docs +# +# Read more about ODK imports: +# https://github.com/INCATools/ontology-development-kit#imports +# ============================================================================== + +name: Refresh Ontology Imports + +# ============================================================================== +# WORKFLOW TRIGGERS +# ============================================================================== +# This workflow can be triggered in three ways: +# 1. Via repository_dispatch from setup-repo workflow (initial setup) +# 2. Automatically on pushes that modify import-related files +# 3. Manually via workflow_dispatch for forced refresh +# +# Path filters ensure the workflow only runs when relevant files change, +# preventing unnecessary executions on unrelated commits. +# +# IMPORTANT: Push triggers skip commits made by github-actions[bot] to prevent +# duplicate runs when the workflow chain is triggered via repository_dispatch. +# ============================================================================== +on: + # ============================================================================ + # TRIGGER 1: Repository Dispatch (from setup-repo workflow) + # ============================================================================ + # Listens for 'trigger-refresh-imports' event dispatched by setup-repo.yml + # This ensures imports are refreshed immediately after initial ontology setup + # ============================================================================ + repository_dispatch: + types: [trigger-refresh-imports] + + # ============================================================================ + # TRIGGER 2: Push Events (for regular development) + # ============================================================================ + # Triggers when import-related files are modified and pushed + # + # Monitored paths: + # - src/ontology/imports/** : Import module definitions and OWL files + # - src/ontology/*-edit.owl : Main edit file (may contain import declarations) + # + # Why these paths? + # - Changes to import definitions require re-fetching external ontology terms + # - Edit file changes may add/remove imports that need processing + # + # Note: This trigger is skipped for commits made by github-actions[bot] + # to prevent duplicate runs when triggered via repository_dispatch + # ============================================================================ + push: + branches: ["main"] # Triggers only on main branch + paths: + # - 'src/ontology/imports/**' + # - 'src/ontology/*-edit.owl' + - 'src/ontology/**' + + + # ============================================================================ + # TRIGGER 3: Pull Request Events (for PR validation) + # ============================================================================ + # Same as push trigger, but for pull requests + # Allows validation of import changes during code review + # Note: Commits are skipped for PRs (see commit step conditions) + # ============================================================================ + pull_request: + branches: ["main"] + paths: + # - 'src/ontology/imports/**' + # - 'src/ontology/*-edit.owl' + - 'src/ontology/**' + + # ============================================================================ + # TRIGGER 4: Manual Trigger (for forced refresh) + # ============================================================================ + # Allows manual execution via GitHub UI + # Useful for: + # - Testing import refresh without code changes + # - Forcing refresh after upstream ontology updates + # - Troubleshooting import issues + # ============================================================================ + workflow_dispatch: + +# ============================================================================== +# ENVIRONMENT VARIABLES +# ============================================================================== +# Global variables available to all jobs in this workflow +# ============================================================================== +env: + # Default branch for git operations (used in some ODK make targets) + DEFAULT_BRANCH: main + +# ============================================================================== +# JOBS +# ============================================================================== +jobs: + # ============================================================================ + # JOB 1: check-ontology-dir + # ============================================================================ + # Pre-flight check to verify ontology directory exists + # + # Purpose: Prevents workflow failure in empty/misconfigured repositories + # - Runs before main job (cheap safety check) + # - Outputs boolean flag for conditional job execution + # - Skips entire workflow if src/ontology/ doesn't exist + # + # Additional check: Skips workflow for bot commits on push events + # - Prevents duplicate runs when workflow chain is active + # - Bot commits happen when workflows commit their outputs + # - Repository dispatch handles the workflow chain progression + # ============================================================================ + check-ontology-dir: + runs-on: ubuntu-latest + + # CRITICAL: Skip this workflow if triggered by push from github-actions[bot] + # This prevents duplicate runs in the workflow chain + # The chain uses repository_dispatch, so push triggers from bot commits are redundant + if: | + github.event_name != 'push' || + github.event.head_commit.author.name != 'github-actions[bot]' + + # Job outputs (available to dependent jobs via needs.check-ontology-dir.outputs) + outputs: + dir-exists: ${{ steps.check.outputs.exists }} + + steps: + # ======================================================================== + # STEP 1.1: Checkout Repository + # ======================================================================== + # Fetch repository code for directory check + # Lightweight checkout (no full history needed for directory check) + # ======================================================================== + - name: Checkout repository + uses: actions/checkout@v4 + + # ======================================================================== + # STEP 1.2: Check for Ontology Directory + # ======================================================================== + # Verifies src/ontology/ exists and sets output flag + # ======================================================================== + - name: Check for ontology directory + id: check + run: | + if [ -d "src/ontology" ]; then + echo "Ontology directory found." + echo "exists=true" >> $GITHUB_OUTPUT + else + echo "No src/ontology directory found; skipping workflow." + echo "exists=false" >> $GITHUB_OUTPUT + fi + + # ============================================================================ + # JOB 2: refresh-imports + # ============================================================================ + # Main job that performs import refresh operations + # + # Dependencies: Requires check-ontology-dir to pass + # Condition: Only runs if src/ontology/ directory exists + # Container: ODK full image with all necessary tools + # ============================================================================ + refresh-imports: + runs-on: ubuntu-latest + + # Grant write permissions for committing updated imports + permissions: + contents: write + + # Job dependencies + needs: check-ontology-dir + + # Conditional execution: only run if directory exists + if: needs.check-ontology-dir.outputs.dir-exists == 'true' + + # Use ODK container for consistent tooling environment + # Version v1.6 pinned for reproducibility + # Includes: ROBOT, OWLTools, make, Java, Python + container: obolibrary/odkfull:v1.6 + + steps: + # ======================================================================== + # STEP 2.1: Checkout Repository + # ======================================================================== + # Fetch complete repository with full git history + # + # Why fetch-depth: 0? + # - Full history may be needed for ODK make targets + # - Allows git operations that reference commits/branches + # - Required for accurate import mirroring + # ======================================================================== + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Full history + + # ======================================================================== + # STEP 2.2: Refresh Imports via ODK + # ======================================================================== + # Runs ODK make targets to update external ontology import modules + # + # Process: + # 1. Attempt standard refresh-imports target (most common) + # 2. If that fails, try per-import refresh (fallback for custom setups) + # + # Make variables: + # - IMP=true : Enable import module generation + # - MIR=true : Enable mirror mode (local caching of external ontologies) + # - PAT=false : Disable patient profile generation (if applicable) + # - -B : Force rebuild (treats all targets as needing update) + # + # What this does: + # - Downloads latest versions of external ontologies + # - Extracts only needed terms (defined in imports/*_terms.txt) + # - Generates import module OWL files (imports/*_import.owl) + # - Caches external ontologies locally (mirror/ directory) + # + # Fallback logic: + # If refresh-imports target doesn't exist in Makefile, attempts to + # refresh specific import files directly (e.g., imports/pmdco_import.owl) + # ======================================================================== + - name: Refresh imports via ODK + working-directory: src/ontology + run: | + # ===== OPTION A: Standard Refresh Target ===== + # Most ODK repositories have a refresh-imports target + # This target processes all imports defined in *-odk.yaml + echo "Attempting standard refresh-imports target..." + make IMP=true MIR=true PAT=false refresh-imports -B || { + echo "Standard refresh-imports target not found or failed." + echo "Attempting per-import refresh (fallback)..." + + # ===== OPTION B: Per-Import Refresh (Fallback) ===== + # If standard target fails, try refreshing specific imports + # Customize this section based on your ontology's imports + # Example: imports/pmdco_import.owl + # + # To find your import targets, check: + # 1. src/ontology/imports/ directory + # 2. project-odk.yaml import_group section + # 3. src/ontology/Makefile IMPORTS variable + make IMP=true MIR=true PAT=false imports/pmdco_import.owl -B || \ + echo "Specific import target failed; no changes needed" + } + + echo "Import refresh complete." + + # ======================================================================== + # STEP 2.3: Commit Updated Imports + # ======================================================================== + # Commits refreshed import files back to the repository + # + # Conditions: + # - Only runs for push/dispatch events (not pull requests) + # - Only commits if changes detected (action skips empty commits) + # + # What gets committed: + # - src/ontology/imports/*.owl : Updated import module files + # + # Why --force flag? + # - Import OWL files are often in .gitignore + # - --force overrides gitignore rules for these specific files + # - Ensures generated imports are tracked in version control + # + # Commit metadata: + # - Message: Descriptive message indicating automated refresh + # - Author: github-actions[bot] (distinguishes from human commits) + # ======================================================================== + - name: Commit updated imports + # Skip commits for pull requests (review changes manually in PR) + if: github.event_name != 'pull_request' + uses: EndBug/add-and-commit@v9 + with: + # Descriptive commit message for git history + message: "Refresh imports via ODK" + + # Working directory (repository root) + cwd: "." + + # Add only import OWL files, forcing inclusion despite .gitignore + add: "src/ontology/imports/*.owl --force" + + # Use GitHub Actions bot as commit author + default_author: github_actions + + # Push to current branch + push: true + + # ======================================================================== + # STEP 2.4: Trigger Next Workflow (QC) + # ======================================================================== + # Dispatches repository event to start the QC workflow + # + # Workflow Chain: + # setup-repo → refresh-imports → [QC] → docs + # + # Why repository_dispatch? + # - Allows explicit workflow chaining + # - Maintains clear separation between workflow stages + # - Prevents race conditions with concurrent triggers + # + # Condition: Only trigger for non-PR events (PRs don't auto-deploy) + # + # Event type: trigger-qc + # Listened for by: qc.yml + # ======================================================================== + - name: Trigger QC Workflow + # Skip for pull requests (QC will run via push trigger after PR merge) + if: github.event_name != 'pull_request' + uses: peter-evans/repository-dispatch@v3 + with: + # Use default GitHub token (automatically available) + token: ${{ secrets.GITHUB_TOKEN }} + + # Event name that qc.yml listens for + event-type: trigger-qc \ No newline at end of file diff --git a/.github/workflows/setup-repo.yml b/.github/workflows/setup-repo.yml new file mode 100644 index 0000000..a927f9a --- /dev/null +++ b/.github/workflows/setup-repo.yml @@ -0,0 +1,664 @@ +# ============================================================================== +# WORKFLOW: Setup New Ontology (End-to-End Production Ready) +# ============================================================================== +# Purpose: Initial setup of the ontology repository. This workflow automates the +# end-to-end configuration of a new PMD application ontology using ODK. +# It handles metadata, URI normalization (lowercase paths), imports, +# components, ID ranges, terms files, and generates a customized README. +# +# Key Features: +# - Normalizes ontology_id to lowercase for URIs/file paths (e.g., "AUTOCE" → "autoce"). +# - Uppercase preferredPrefix for entity IDs (e.g., "AUTOCE_0000001"). +# - Enforces SLME module extraction for imports to minimize bloat. +# - Generates Manchester-syntax ID ranges OWL for dicer-cli compatibility. +# - Custom terms files support (e.g., "PMD-terms.txt" → "pmd_terms.txt"). +# - Sets directory-style ontology IRI (e.g., https://w3id.org/pmd/autoce/). +# - Appends comprehensive README sections (Development, Structure, Contribution). +# +# Usage: Trigger via GitHub Actions with inputs (ontology_id lowercase recommended). +# Assumes input files: imports.txt, components.txt, creators.txt (optional). +# +# IMPROVEMENTS & FIXES: +# 1. ID Ranges (Step 7): Generates valid Manchester Syntax compliant with dicer-cli +# (using Prefixes and AnnotationProperty declarations). FIXED: Proper indentation, +# added missing prefixes (dce, xml, rdfs), corrected annotations (commas, no quotes +# on iddigits), robust line reading for creators.txt (handles names with spaces via +# IFS=$'\t' and line processing). BLOCK_SIZE set to 10000 to align with common +# practices (e.g., 0-9999, 10000-19999); sequential allocation without overflow +# for simplicity (extend creators.txt for more blocks). +# 2. URI Structure (Step 4): Ensures trailing slash for directory-style IRIs +# (e.g., https://w3id.org/pmd/autoce/). FIX: Forces lowercase for paths/URIs. +# 3. Import Terms (Step 8): Enforces specific terms files (e.g., pmd_terms.txt) +# and creates placeholders. UPDATED: Supports custom naming like PMD-terms.txt, +# but renames to ODK-expected {id}_terms.txt for SLME extraction. +# 4. Import Modules (Step 4): Enforces 'slme' module extraction to prevent leaking +# unwanted terms into your ontology. +# 5. Ontology IRI (Step 11.5): Explicitly sets directory-style IRI using ROBOT annotate +# to override ODK's default file-based IRI. +# 6. README (Step 6.5): Post-seed sed to ensure title/description interpolation. +# 7. README Custom (Step 6.7): Appends Development, Repository Structure, and Contribution sections +# with ODK acknowledgment and PMD-specific guidance. FIX: Proper heredoc variable expansion +# (unquoted << EOF for bash substitution; inline uppercase computation). +# 8. ID Ranges in Config (Step 4): FIXED: Robust bash syntax for yq integration (variable scoping, +# error handling, IFS=$'\t' for creators.txt to handle spaced names). +# 9. General: Enhanced error handling (set -euo pipefail everywhere), trimmed outputs, +# consistent indentation in Manchester OWL for parseability. Production-ready: +# - Idempotent where possible (e.g., check files exist). +# - Logs key actions for debugging. +# - Preserves .github/ workflows. +# - Triggers downstream for full pipeline. +# ============================================================================== +name: Setup New Ontology +on: + workflow_dispatch: + inputs: + ontology_id: + description: 'Ontology ID (lowercase, e.g., autoce) - will be normalized to lowercase' + required: true + ontology_title: + description: 'Ontology Title (e.g., "Automotive Components Ontology")' + required: true + id_digits: + description: 'Number of digits in entity IDs (default: 7 for _0000001 to _9999999)' + required: true + default: '7' +jobs: + setup_and_import: + runs-on: ubuntu-latest + permissions: + contents: write + # Using ODK container to ensure all ontology tools (yq, robot, make, python) are available + container: obolibrary/odkfull:v1.6 + steps: + # ======================================================================== + # STEP 1: Checkout Repository + # ======================================================================== + # Checks out the entire repo history for git operations. + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + # ======================================================================== + # STEP 2: Configure Git + # ======================================================================== + # Sets up git config for automated commits (bot user). + - name: Git Config + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global --add safe.directory "$GITHUB_WORKSPACE" + # ======================================================================== + # STEP 3: Install yq YAML Processor + # ======================================================================== + # yq is used to manipulate project-odk.yaml; install latest binary. + - name: Install yq + run: | + wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq + chmod +x /usr/bin/yq + # ======================================================================== + # STEP 4: Configure URI Structure, ID Ranges, and Import Products + # ======================================================================== + # Updates project-odk.yaml with inputs: metadata, URIs (lowercase paths), namespaces, + # components from components.txt, ID ranges from creators.txt, and imports from imports.txt. + # Always includes PMD Core as "pmd" import with SLME extraction. + - name: Configure URI Structure, ID Ranges, and Import Products + shell: bash + run: | + set -euo pipefail + # --- Load Inputs and Normalize --- + CONFIG="project-odk.yaml" + ID="${{ github.event.inputs.ontology_id }}" # Raw input (may have CAPS) + LOWER_ID=$(echo "$ID" | tr '[:upper:]' '[:lower:]') # Force lowercase for URIs/files + TITLE="${{ github.event.inputs.ontology_title }}" + DIGITS="${{ github.event.inputs.id_digits }}" + if [ ! -f "$CONFIG" ]; then + echo "ERROR: $CONFIG not found!" + exit 1 + fi + PREFIX=$(echo "$ID" | tr '[:lower:]' '[:upper:]') # Uppercase for entity prefixes (e.g., AUTOCE_) + echo "=== Configuring Ontology: $ID (normalized: $LOWER_ID, prefix: $PREFIX) ===" + # -------------------------------------------------------------------- + # 1. BASIC METADATA (use LOWER_ID for file paths) + # -------------------------------------------------------------------- + yq -i ".id = \"$LOWER_ID\"" "$CONFIG" + yq -i ".title = \"$TITLE\"" "$CONFIG" + yq -i ".edit_ontology_file = \"src/ontology/$LOWER_ID-edit.owl\"" "$CONFIG" + yq -i ".repo = \"$GITHUB_REPOSITORY\"" "$CONFIG" # Optional: for README templating + # -------------------------------------------------------------------- + # 2. URI STRUCTURE (FIX: TRAILING SLASH + LOWERCASE PATHS) + # -------------------------------------------------------------------- + # Defines https://w3id.org/pmd/{lower_id}/ (Directory style) + yq -i ".uribase = \"https://w3id.org/pmd\"" "$CONFIG" + yq -i ".uribase_suffix = \"$LOWER_ID/\"" "$CONFIG" + yq -i ".preferredPrefix = \"$PREFIX\"" "$CONFIG" + # -------------------------------------------------------------------- + # 3. NAMESPACES (CRITICAL: For new entity ID generation, e.g., https://w3id.org/pmd/autoce/AUTOCE_0000001) + # -------------------------------------------------------------------- + yq -i ".namespaces = [\"https://w3id.org/pmd/$LOWER_ID/\"]" "$CONFIG" + # -------------------------------------------------------------------- + # 4. CI/CD & ARRAYS (Ensure empty arrays for safe appending) + # -------------------------------------------------------------------- + yq -i ".ci = []" "$CONFIG" + yq -i '.components.products = (.components.products // [])' "$CONFIG" + yq -i '.import_group.products = (.import_group.products // [])' "$CONFIG" + yq -i '.idranges = (.idranges // [])' "$CONFIG" + + # -------------------------------------------------------------------- + # 5. COMPONENT PRODUCTS (Pass 1: Filenames Only) + # -------------------------------------------------------------------- + # We add filenames ONLY. We add template config in Step 10 to avoid build errors during seed. + if [ -f "component_seeds.txt" ]; then + echo "Processing components from component_seeds.txt..." + grep -vE '^\s*#|^\s*$' component_seeds.txt | cut -d'|' -f1 | sort | uniq | while read -r comp_name; do + comp_name=$(echo "$comp_name" | xargs) + if [ -n "$comp_name" ]; then + # Only add filename for now + yq -i ".components.products += [{\"filename\": \"${comp_name}.owl\"}]" "$CONFIG" + echo " Registered component: $comp_name.owl" + fi + done + fi + + # -------------------------------------------------------------------- + # 6. ID RANGES CONFIGURATION (from creators.txt: one creator per line; allocates 10k blocks) + # FIXED: IFS=$'\t' for nl output; handles spaced names via full line processing. + # -------------------------------------------------------------------- + if [ -f "creators.txt" ]; then + echo "Processing ID ranges from creators.txt..." + ID_PREFIX="https://w3id.org/pmd/$LOWER_ID/${PREFIX}_" # e.g., https://w3id.org/pmd/autoce/AUTOCE_ + BLOCK_SIZE=10000 + nl -ba creators.txt | while IFS=$'\t' read -r idx line || [ -n "$idx" ]; do + idx=$(echo "$idx" | xargs) # Trim any padding spaces from nl + clean_line=$(echo "$line" | sed 's/^\s*#.*$//' | xargs) # Remove comments, trim/collapse spaces + if [ -z "$clean_line" ]; then continue; fi + creator="$clean_line" + RANGE_START=$(( (idx - 1) * BLOCK_SIZE )) + RANGE_END=$(( RANGE_START + BLOCK_SIZE - 1 )) + export ALLOCATED_TO="$creator" + export IDS_FOR="$LOWER_ID" + export ID_PREFIX_VAR="$ID_PREFIX" + export ID_DIGITS_VAR="$DIGITS" + export R_START="$RANGE_START" + export R_END="$RANGE_END" + yq -i '.idranges += [{ + "allocatedto": env(ALLOCATED_TO), + "idsfor": env(IDS_FOR), + "idprefix": env(ID_PREFIX_VAR), + "iddigits": env(ID_DIGITS_VAR), + "range_start": env(R_START), + "range_end": env(R_END) + }]' "$CONFIG" + echo " Allocated range $RANGE_START-$RANGE_END to: $creator" + done + else + echo "No creators.txt found - no ID ranges added." + fi + # -------------------------------------------------------------------- + # 7. IMPORT PRODUCTS (from imports.txt: id|url format; always add PMD Core) + # -------------------------------------------------------------------- + echo "Configuring import products..." + # Always add PMD Core (id: "pmdco" for simpler terms file handling) + yq -i '.import_group.products += [{ + "id": "pmdco", + "title": "PMD Core Ontology", + "mirror_from": "https://raw.githubusercontent.com/materialdigital/core-ontology/refs/heads/main/pmdco-full.owl", + "module_type": "slme", + "base_iris": ["https://w3id.org/pmd/co/"] + }]' "$CONFIG" + echo " Added core import: pmd (SLME extraction)" + # Add additional imports from imports.txt (SLME enforced) + if [ -f "imports.txt" ]; then + while IFS='|' read -r import_id import_url || [ -n "$import_id" ]; do + if echo "$import_id" | grep -qE '^\s*#'; then continue; fi + + import_id=$(echo "${import_id:-}" | xargs | tr '[:upper:]' '[:lower:]') # Normalize import_id to lowercase + import_url=$(echo "${import_url:-}" | xargs) + if [ -z "$import_id" ] || [ -z "$import_url" ]; then continue; fi + echo " - Adding import: $import_id from $import_url" + + export IMPORT_ID="$import_id" + export IMPORT_URL="$import_url" + yq -i '.import_group.products += [{ + "id": env(IMPORT_ID), + "mirror_from": env(IMPORT_URL), + "module_type": "slme" + }]' "$CONFIG" + done < imports.txt + else + echo "No imports.txt found - only PMD Core added." + fi + echo "=== Configuration Complete (URIs use $LOWER_ID) ===" + # ======================================================================== + # STEP 5: Run ODK Seed + # ======================================================================== + # Generates initial ODK structure (src/, .github/, etc.) based on updated project-odk.yaml. + - name: Run ODK Seed + shell: bash + run: | + set -euo pipefail + echo "Running ODK seed..." + /tools/odk.py seed -c -C project-odk.yaml \ + --gitname "${{ github.actor }}" \ + --gitemail "${{ github.actor }}@users.noreply.github.com" + # ======================================================================== + # STEP 6: Move Generated Files + # ======================================================================== + # Moves ODK-generated files from target/{id}/ to root; cleans up conflicts. + - name: Move Generated Files + shell: bash + run: | + set -euo pipefail + ID="${{ github.event.inputs.ontology_id }}" + LOWER_ID=$(echo "$ID" | tr '[:upper:]' '[:lower:]') + TARGET_DIR="target/$LOWER_ID" # ODK uses lowercase from config + if [ ! -d "$TARGET_DIR" ]; then + echo "ERROR: Target directory $TARGET_DIR not found!" + exit 1 + fi + # Cleanup ODK github artifacts to avoid conflict with existing + rm -rf "$TARGET_DIR/.github" + + # Move files to root + cp -r "$TARGET_DIR"/* . + if [ -f "$TARGET_DIR/.gitignore" ]; then cp "$TARGET_DIR/.gitignore" .; fi + + # Cleanup target + rm -rf target/ + echo "Files moved from $TARGET_DIR to root." + # ======================================================================== + # STEP 6.5: Ensure README Interpolation (Title/Description) + # ======================================================================== + # Basic sed replacements for ODK-generated README placeholders. + - name: Ensure README Interpolation + shell: bash + run: | + set -euo pipefail + LOWER_ID=$(echo "${{ github.event.inputs.ontology_id }}" | tr '[:upper:]' '[:lower:]') + TITLE="${{ github.event.inputs.ontology_title }}" + if [ -f "README.md" ]; then + sed -i "s|Placeholder Title|$TITLE|g" README.md + sed -i "s|placeholder_id|$LOWER_ID|g" README.md + echo "README interpolated: Title='$TITLE', ID='$LOWER_ID'" + else + echo "WARNING: README.md not found - skipping interpolation." + fi + # ======================================================================== + # STEP 6.7: Customize README (Development, Structure, Contribution) + # ======================================================================== + # Appends PMD/ODK-specific sections to README.md for user guidance. + # FIX: Uses unquoted heredoc (<< EOF) for bash variable expansion; computes uppercase inline. + - name: Customize README + shell: bash + run: | + set -euo pipefail + LOWER_ID=$(echo "${{ github.event.inputs.ontology_id }}" | tr '[:upper:]' '[:lower:]') + UPPER_ID=$(echo "${{ github.event.inputs.ontology_id }}" | tr '[:lower:]' '[:upper:]') + TITLE="${{ github.event.inputs.ontology_title }}" + REPO="${{ github.repository }}" + if [ ! -f "README.md" ]; then + echo "ERROR: README.md not found!" + exit 1 + fi + # Ensure newline before appending + echo "" >> README.md + # Append Development section (with inline uppercase for example) + cat >> README.md << EOF + ## Development + This ontology is developed using OWL and managed with the [Ontology Development Kit (ODK)](https://github.com/INCATools/ontology-development-kit). To edit: + - Open \`${LOWER_ID}-edit.owl\` (located in \`src/ontology/\`) in [Protégé](https://protege.stanford.edu/) or your preferred OWL editor. + - Create new entities (classes, properties) within the namespace \`https://w3id.org/pmd/${LOWER_ID}/\`. + - Example class ID: \`https://w3id.org/pmd/${LOWER_ID}/${UPPER_ID}_0000001\` (PREFIX is uppercase). + - Use the \`Makefile\` for automation: + - \`make test\`: Run quality control (OWL reasoner checks, syntax validation). + - \`make refresh-imports\`: Update imported ontologies (e.g., PMD Core, LOGO) with SLME extraction. + - \`make release\`: Build release artifacts (full, base, etc.) in TTL/OWL/JSON formats. + - \`make update_repo\`: Sync changes to the repo structure. + Quick start: After setup, edit in Protégé, commit, and push to trigger CI builds. + EOF + # Append Repository Structure section + cat >> README.md << EOF + ## Repository Structure + This repository provides the modular implementation of ${TITLE}, developed and maintained using the [Ontology Development Kit (ODK)](https://github.com/INCATools/ontology-development-kit). + ### Top-level directories + * **.github/:** GitHub configuration files, including CI workflows and templates. + * **docs/:** Documentation sources for the ontology website and user guides (optional; add as needed). + * **patterns/:** Logical patterns and SHACL shapes used to maintain consistent ontology design (optional). + * **src/:** Main development folder generated and managed through ODK. + * **ontology/components/:** – Modular ontology components (classes, properties, axioms). + * **ontology/${LOWER_ID}-edit.owl:** – Primary editable ontology file used during development (ontology editors' version). + * **ontology/imports/:** Extracted terms from imported ontologies (via SLME). + ### Ontology versions (generated on release) + * **${LOWER_ID}-full.owl/ttl:** Complete ontology with all imports and full axiomatization. + * **${LOWER_ID}-base.owl/ttl:** Core entities without extended imports. + * **${LOWER_ID}-simple.owl/ttl:** Simplified version with basic subclass and existential axioms. + * **${LOWER_ID}-minimal.owl/ttl:** Lightweight minimal version for quick onboarding (recommended for beginners). + * **${LOWER_ID}.owl/ttl:** Main ontology file contains the full version. + ### Other files + * README.md, LICENSE.txt, CONTRIBUTING.md – Project overview, license, and contribution guidelines. + * imports.txt, components.txt, creators.txt – Configuration for setup (optional edits). + EOF + # Append Contribution section (PMD-specific) + cat >> README.md << EOF + ## Contribution + We welcome contributions to the ${TITLE} ontology! + To get involved: + - Please use this GitHub repository's **[Issue tracker](https://github.com/${REPO}/issues)** to request new terms/classes or report errors or specific concerns related to the ontology. + - For creation of application ontologies using PMD core ontologies, we advise using the **[application-ontology-template](https://github.com/materialdigital/application-ontology-template/)**. It applies the same framework used here and mirrors the pmdco with all its modules. + - Write about your specific modeling concerns or any other discussable topics in the **[discussion forum](https://github.com/${REPO}/discussions)**. + - Participate in our **PMD Playground Meetings**: Our Ontology Playground, organized online every second Friday from 1-2 pm (CET), is a great opportunity to connect with developers and our proactive community to shape the PMDco. Please register via our [mailing list](https://www.lists.kit.edu/sympa/subscribe/ontology-playground?previous_action=info). + - If you need further information, please feel free to contact us via **[info@material-digital.de](mailto:info@material-digital.de)** + EOF + echo "README customized with Development, Structure, and Contribution sections (using $LOWER_ID)." + # ======================================================================== + # STEP 7: Generate ID Ranges OWL File (FIX: VALID MANCHESTER SYNTAX) + # ======================================================================== + # Creates {lower_id}-idranges.owl in Manchester syntax for ID allocation (used by dicer-cli). + # Allocates blocks from creators.txt; declares annotation properties and datatypes. + # FIX: Ensured variable scoping in subshells; robust error handling. Proper indentation, + # added full prefixes, annotations format (indents/commas), line reading (IFS=$'\t' for spaces). + # BLOCK_SIZE=10000 for 10k blocks (e.g., 0-9999); sequential. + - name: Generate ID Ranges OWL File + shell: bash + run: | + set -euo pipefail + ID="${{ github.event.inputs.ontology_id }}" + LOWER_ID=$(echo "$ID" | tr '[:upper:]' '[:lower:]') + DIGITS="${{ github.event.inputs.id_digits }}" + PREFIX_UPPER=$(echo "$ID" | tr '[:lower:]' '[:upper:]') + ID_PREFIX="https://w3id.org/pmd/$LOWER_ID/${PREFIX_UPPER}_" + IDRANGE_FILE="src/ontology/${LOWER_ID}-idranges.owl" + CREATORS_FILE="creators.txt" + if [ ! -f "$CREATORS_FILE" ]; then + echo "No creators.txt found - skipping ID ranges generation." + exit 0 + fi + mkdir -p "src/ontology" + # ------------------------------------------------------- + # HEADER WITH PREFIXES AND ANNOTATION PROPERTIES (Manchester Syntax) + # ------------------------------------------------------- + { + echo "Prefix: rdf: " + echo "Prefix: xsd: " + echo "Prefix: owl: " + echo "Prefix: rdfs: " + echo "Prefix: xml: " + echo "Prefix: dce: " + # Define Prefixes for ID Range Annotations + echo "Prefix: allocatedto: " + echo "Prefix: idsfor: " + echo "Prefix: idprefix: " + echo "Prefix: iddigits: " + echo "Prefix: idrange: " + + echo "" + echo "Ontology: " + echo "" + + # Ontology Annotations (using prefixes for dicer-cli safety; indented, commas on non-last) + echo "Annotations:" + echo " idsfor: \"$PREFIX_UPPER\"," + echo " idprefix: \"$ID_PREFIX\"," + echo " iddigits: $DIGITS" + echo "" + + # Declare Annotation Properties (required for Manchester) + echo "AnnotationProperty: allocatedto:" + echo "" + echo "AnnotationProperty: idsfor:" + echo "" + echo "AnnotationProperty: idprefix:" + echo "" + echo "AnnotationProperty: iddigits:" + echo "" + } > "$IDRANGE_FILE" + # ------------------------------------------------------- + # WRITE RANGES (One Datatype per Creator/Block) + # ------------------------------------------------------- + BLOCK_SIZE=10000 + nl -ba "$CREATORS_FILE" | while IFS=$'\t' read -r idx line || [ -n "$idx" ]; do + idx=$(echo "$idx" | xargs) # Trim nl padding + clean_line=$(echo "$line" | sed 's/^\s*#.*$//' | xargs) # Remove comments, trim/collapse + if [ -z "$clean_line" ]; then continue; fi + + RANGE_START=$(( (idx - 1) * BLOCK_SIZE )) + RANGE_END=$(( RANGE_START + BLOCK_SIZE - 1 )) + { + echo "Datatype: idrange:$idx" + echo " Annotations:" + echo " allocatedto: \"$clean_line\"" + echo " " + echo " EquivalentTo:" + echo " xsd:integer[>= $RANGE_START , <= $RANGE_END]" + echo " " + } >> "$IDRANGE_FILE" + echo " Added range $RANGE_START-$RANGE_END for: $clean_line" + done + # Required Base Datatypes (no indent) + { + echo "Datatype: xsd:integer" + echo "Datatype: rdf:PlainLiteral" + } >> "$IDRANGE_FILE" + echo "ID Ranges file generated: $IDRANGE_FILE" + # ======================================================================== + # STEP 8: Setup Import Terms Files (FIX: SPECIFIC FILES + CUSTOM NAMING SUPPORT) + # ======================================================================== + # Creates/copies terms files in src/ontology/imports/ for SLME extraction. + # Supports custom names (e.g., PMD-terms.txt) or standard (pmd_terms.txt); falls back to empty placeholder. + - name: Setup Import Terms Files + shell: bash + run: | + set -euo pipefail + IMPORTS_DIR="src/ontology/imports" + mkdir -p "$IMPORTS_DIR" + # Function: Process terms for one import (custom → standard → placeholder) + process_terms_file() { + local onto_id=$1 # e.g., "pmd" (lowercase) + local custom_source="${onto_id^^}-terms.txt" # e.g., PMD-terms.txt + local standard_source="${onto_id}_terms.txt" # e.g., pmd_terms.txt + local target_file="$IMPORTS_DIR/${onto_id}_terms.txt" # ODK-expected for SLME + # Prioritize custom, then standard + local source_file="" + if [ -f "$custom_source" ]; then + echo " - Found custom terms file: $custom_source" + source_file="$custom_source" + elif [ -f "$standard_source" ]; then + echo " - Found standard terms file: $standard_source" + source_file="$standard_source" + else + echo " - No terms file for $onto_id. Creating empty placeholder." + { + echo "# Terms to import from $onto_id ontology (SLME extraction)" + echo "# Format: One IRI per line (e.g., https://w3id.org/pmd/co/PMDCO_0000001)" + echo "# Leave empty to import nothing beyond references." + } > "$target_file" + return + fi + # Copy to ODK-expected target + cp "$source_file" "$target_file" + echo " - Prepared ODK terms: $target_file" + } + # 1. Process PMD Core (id: "pmd") + echo "Processing PMD Core terms..." + process_terms_file "pmdco" + # 2. Process Additional Imports (from imports.txt, normalized lowercase) + if [ -f "imports.txt" ]; then + while IFS='|' read -r import_id import_url || [ -n "$import_id" ]; do + if echo "$import_id" | grep -qE '^\s*#'; then continue; fi + import_id=$(echo "${import_id:-}" | xargs | tr '[:upper:]' '[:lower:]') + if [ -n "$import_id" ]; then + echo "Processing terms for $import_id..." + process_terms_file "$import_id" + fi + done < imports.txt + fi + echo "Terms files setup complete in $IMPORTS_DIR." + # ======================================================================== + # STEP 9: Refresh Imports + # ======================================================================== + # Runs ODK's make refresh-imports to mirror and extract imports (SLME via terms files). + - name: Refresh Imports + shell: bash + run: | + set -euo pipefail + echo "Refreshing imports with SLME extraction..." + cd src/ontology + make refresh-imports IMP=true MIR=true ROBOT_ENV='ROBOT_JAVA_ARGS=-Xmx8G' + echo "Imports refreshed successfully." + # ======================================================================== + # STEP 10: Initialize Component Templates and Reconfigure ODK + # ======================================================================== + # 1. Creates TSV templates from component_seeds.txt + # 2. Updates the ODK config to enable "use_template: true" + # 3. Regenerates the Makefile so it now knows how to build them + - name: Initialize Component Templates + shell: bash + run: | + set -euo pipefail + ID="${{ github.event.inputs.ontology_id }}" + LOWER_ID=$(echo "$ID" | tr '[:upper:]' '[:lower:]') + + # Path to the internal ODK config file generated by Seed + INTERNAL_CONFIG="src/ontology/${LOWER_ID}-odk.yaml" + + # 1. Setup Directories + mkdir -p src/templates + mkdir -p src/ontology/config + + # 2. Create config/context.json + if [ ! -f "src/ontology/config/context.json" ]; then + echo "{ + \"@context\": { + \"$LOWER_ID\": \"https://w3id.org/pmd/$LOWER_ID/\", + \"pmdco\": \"https://w3id.org/pmd/co/\", + \"rdf\": \"http://www.w3.org/1999/02/22-rdf-syntax-ns#\", + \"rdfs\": \"http://www.w3.org/2000/01/rdf-schema#\", + \"owl\": \"http://www.w3.org/2002/07/owl#\" + } + }" > src/ontology/config/context.json + fi + + # 3. Process Seeds into TSV and Update Config + if [ -f "component_seeds.txt" ]; then + echo "Generating templates and updating configuration..." + + # Identify unique components + grep -vE '^\s*#|^\s*$' component_seeds.txt | cut -d'|' -f1 | sort | uniq | while read -r comp_name; do + comp=$(echo "$comp_name" | xargs) + if [ -z "$comp" ]; then continue; fi + + # A. Generate TSV File + TSV_FILE="src/templates/${comp}.tsv" + if [ ! -f "$TSV_FILE" ]; then + echo -e "ID\tLabel\tParent Class" > "$TSV_FILE" + echo -e "ID\tA rdfs:label\tSC %" >> "$TSV_FILE" + + # Grep for this component's specific rows + grep "^$comp" component_seeds.txt | while IFS='|' read -r _ id label parent || [ -n "$id" ]; do + echo -e "$(echo $id|xargs)\t$(echo $label|xargs)\t$(echo $parent|xargs)" >> "$TSV_FILE" + done + echo " Created template: $TSV_FILE" + fi + + # B. Update ODK Config to enable templates + # We find the component by filename and inject the template settings + export FILENAME="${comp}.owl" + export TEMPLATE_FILE="${comp}.tsv" + + yq -i '(.components.products[] | select(.filename == env(FILENAME))) += { + "use_template": true, + "template_options": "--add-prefixes config/context.json", + "templates": [env(TEMPLATE_FILE)] + }' "$INTERNAL_CONFIG" + + echo " Enabled templates for $comp in $INTERNAL_CONFIG" + done + + # 4. Regenerate Makefile + echo "Regenerating repository structure to apply template settings..." + cd src/ontology + make update_repo + echo "Makefile updated." + + else + echo "No component_seeds.txt found." + fi + # ======================================================================== + # STEP 11: Remove Root Class + # ======================================================================== + # Removes ODK-generated root class (e.g., {PREFIX}_0000000) from edit.owl. + - name: Remove Root Class + shell: bash + run: | + set -euo pipefail + ID="${{ github.event.inputs.ontology_id }}" + LOWER_ID=$(echo "$ID" | tr '[:upper:]' '[:lower:]') + PREFIX=$(echo "$ID" | tr '[:lower:]' '[:upper:]') + EDIT_FILE="src/ontology/${LOWER_ID}-edit.owl" + if [ -f "$EDIT_FILE" ]; then + sed -i "/${PREFIX}_0000000/d" "$EDIT_FILE" + sed -i '/root node/d' "$EDIT_FILE" + echo "Removed root class from $EDIT_FILE." + else + echo "WARNING: $EDIT_FILE not found - skipping root class removal." + fi + # ======================================================================== + # STEP 11.5: Set Ontology IRI to Directory Style + # ======================================================================== + # Uses ROBOT annotate to enforce directory-style IRI (e.g., https://w3id.org/pmd/autoce/) + # in the edit.owl (overrides ODK defaults). + - name: Set Ontology IRI to Directory Style + shell: bash + run: | + set -euo pipefail + LOWER_ID=$(echo "${{ github.event.inputs.ontology_id }}" | tr '[:upper:]' '[:lower:]') + EDIT_FILE="src/ontology/${LOWER_ID}-edit.owl" + ONT_IRI="https://w3id.org/pmd/${LOWER_ID}/" + if [ -f "$EDIT_FILE" ]; then + robot annotate --input "$EDIT_FILE" \ + --ontology-iri "$ONT_IRI" \ + -o "$EDIT_FILE" + echo "Ontology IRI set to directory-style: $ONT_IRI" + else + echo "WARNING: $EDIT_FILE not found - skipping IRI annotation." + fi + # ======================================================================== + # STEP 12: Run QC and Update Repo + # ======================================================================== + # Runs ODK's make test (reasoning, validation) and update_repo (syncs structure). + - name: Run QC and Update Repo + shell: bash + run: | + set -euo pipefail + echo "Running QC tests and repo update..." + cd src/ontology + make test ROBOT_ENV='ROBOT_JAVA_ARGS=-Xmx8G' + make update_repo + echo "QC passed; repo updated." + # ======================================================================== + # STEP 13: Commit and Push Changes + # ======================================================================== + # Stages all changes, commits with descriptive message, pushes to main. + - name: Commit and Push Changes + shell: bash + run: | + set -euo pipefail + LOWER_ID=$(echo "${{ github.event.inputs.ontology_id }}" | tr '[:upper:]' '[:lower:]') + git add . + git reset .github 2>/dev/null || true # Preserve custom workflows + git commit -m "chore: Setup ${LOWER_ID^^} ontology (end-to-end complete) + Auto-generated via Setup New Ontology workflow: + - Configured project-odk.yaml (URIs: https://w3id.org/pmd/${LOWER_ID}/) + - Initialized components, imports (SLME), ID ranges + - Generated ${LOWER_ID}-edit.owl and ${LOWER_ID}-idranges.owl + - Customized README.md with development guides" || echo "No changes to commit" + git push origin HEAD:${{ github.ref_name }} + echo "Changes committed and pushed." + # ======================================================================== + # STEP 14: Trigger Workflow Chain + # ======================================================================== + # Dispatches downstream workflows (e.g., refresh-imports) for full pipeline. + - name: Trigger Refresh Imports Workflow + uses: peter-evans/repository-dispatch@v3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + event-type: trigger-refresh-imports \ No newline at end of file diff --git a/.github/workflows/update-repo.yml b/.github/workflows/update-repo.yml new file mode 100644 index 0000000..e830a14 --- /dev/null +++ b/.github/workflows/update-repo.yml @@ -0,0 +1,350 @@ +# ============================================================================== +# WORKFLOW: Update Repo Config +# ============================================================================== +# Purpose: Synchronizes repository structure with ODK configuration changes +# +# This workflow: +# 1. Detects changes to the ontology ODK configuration file (*-odk.yaml) +# 2. Runs ODK update_repo make target to synchronize repository structure +# 3. Commits updated configuration files back to the repository +# +# What update_repo does: +# - Updates owlnet configuration files +# - Synchronizes SPARQL query templates +# - Updates release artifact configurations +# - Regenerates Makefile components (if needed) +# - Updates documentation templates +# +# This workflow is INDEPENDENT of the main workflow chain and runs whenever +# configuration files are modified. It does not trigger other workflows. +# +# Workflow Position: Independent (does not chain with others) +# +# Read more about ODK update_repo: +# https://github.com/INCATools/ontology-development-kit#update_repo +# ============================================================================== + +name: Update Repo Config + +# ============================================================================== +# WORKFLOW TRIGGERS +# ============================================================================== +# This workflow triggers when ODK configuration files are modified. +# It is independent of the main workflow chain (setup-repo → imports → qc → docs) +# and runs on-demand based on configuration changes. +# ============================================================================== +on: + # ============================================================================ + # TRIGGER 1: Push Events (for configuration changes) + # ============================================================================ + # Triggers when ODK configuration files are modified and pushed + # + # Monitored files: + # - src/ontology/*-odk.yaml : Ontology-specific ODK configuration + # - project-odk.yaml : Root project configuration + # + # Why these files? + # - Changes to ODK config require repository structure updates + # - Ensures repo stays synchronized with configuration + # - Examples: Adding components, changing release settings, updating imports + # + # Examples of changes that trigger: + # - Adding new component products + # - Changing import configurations + # - Modifying release settings + # - Updating metadata (title, description, etc.) + # ============================================================================ + push: + branches: ["main"] # Triggers on any branch + paths: + - 'src/ontology/*-odk.yaml' + - 'project-odk.yaml' + + # ============================================================================ + # TRIGGER 2: Pull Request Events (for PR validation) + # ============================================================================ + # Same as push trigger, but for pull requests + # Validates that configuration updates work correctly before merge + # Note: Commits are skipped for PRs (see commit step conditions) + # ============================================================================ + pull_request: + branches: ["main"] + paths: + - 'src/ontology/*-odk.yaml' + - 'project-odk.yaml' + + # ============================================================================ + # TRIGGER 3: Manual Trigger (for forced updates) + # ============================================================================ + # Allows manual execution via GitHub UI + # Useful for: + # - Testing configuration updates without file changes + # - Forcing synchronization after external changes + # - Troubleshooting configuration issues + # ============================================================================ + workflow_dispatch: + + # ============================================================================ + # TRIGGER 4: Repository Dispatch (optional, for workflow integration) + # ============================================================================ + # Can be triggered by other workflows if needed + # Not used in standard workflow chain, but available for custom integrations + # ============================================================================ + repository_dispatch: + types: [trigger-update-repo] + +# ============================================================================== +# ENVIRONMENT VARIABLES +# ============================================================================== +# Global variables available to all jobs in this workflow +# ============================================================================== +env: + # Default branch for git operations + DEFAULT_BRANCH: main + +# ============================================================================== +# JOBS +# ============================================================================== +jobs: + # ============================================================================ + # JOB 1: check-ontology-dir + # ============================================================================ + # Pre-flight check to verify ontology directory exists + # + # Purpose: Prevents workflow failure in empty/misconfigured repositories + # - Runs before main job (cheap safety check) + # - Outputs boolean flag for conditional job execution + # - Skips workflow gracefully if src/ontology/ doesn't exist + # ============================================================================ + check-ontology-dir: + runs-on: ubuntu-latest + + # Job outputs (available to dependent jobs via needs.check-ontology-dir.outputs) + outputs: + dir-exists: ${{ steps.check.outputs.exists }} + + steps: + # ======================================================================== + # STEP 1.1: Checkout Repository + # ======================================================================== + # Fetch repository code for directory check + # Lightweight checkout (no full history needed for directory check) + # ======================================================================== + - name: Checkout repository + uses: actions/checkout@v4 + + # ======================================================================== + # STEP 1.2: Check for Ontology Directory + # ======================================================================== + # Verifies src/ontology/ exists and sets output flag + # ======================================================================== + - name: Check for ontology directory + id: check + run: | + if [ -d "src/ontology" ]; then + echo "Ontology directory found." + echo "exists=true" >> $GITHUB_OUTPUT + else + echo "No src/ontology directory found; skipping workflow." + echo "exists=false" >> $GITHUB_OUTPUT + fi + + # ============================================================================ + # JOB 2: update-config + # ============================================================================ + # Main job that performs repository configuration updates + # + # Dependencies: Requires check-ontology-dir to pass + # Condition: Only runs if src/ontology/ directory exists + # Container: ODK full image with all necessary tools + # ============================================================================ + update-config: + runs-on: ubuntu-latest + + # Grant write permissions for committing updated configs + permissions: + contents: write + + # Job dependencies + needs: check-ontology-dir + + # Conditional execution: only run if directory exists + if: needs.check-ontology-dir.outputs.dir-exists == 'true' + + # Use ODK container for consistent tooling environment + # Version v1.6 pinned for reproducibility + # Includes: ROBOT, OWLTools, make, Java, Python + container: obolibrary/odkfull:v1.6 + + steps: + # ======================================================================== + # STEP 2.1: Checkout Repository + # ======================================================================== + # Fetch complete repository with full git history + # + # Why fetch-depth: 0? + # - Full history may be needed for ODK make targets + # - Allows git operations that reference commits/branches + # - Required for accurate configuration synchronization + # ======================================================================== + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Full history + + # ======================================================================== + # STEP 2.2: Configure Git + # ======================================================================== + # Sets up git identity for automated commits + # + # Why configure git? + # - Required for making commits in containerized environment + # - Uses GitHub Actions bot identity to distinguish from human commits + # - safe.directory required when running in Docker containers + # + # Bot identity format: + # - Name: github-actions[bot] + # - Email: github-actions[bot]@users.noreply.github.com + # - This is the standard GitHub Actions bot identity + # ======================================================================== + - name: Configure Git + run: | + # Set git user identity for commits + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + + # Add workspace as safe directory (required in containers) + git config --global --add safe.directory $GITHUB_WORKSPACE + + # ======================================================================== + # STEP 2.3: Run ODK Update Repo + # ======================================================================== + # Updates repository structure using ODK make targets + # + # Process: + # 1. Detect ontology ID from project-odk.yaml + # 2. Copy project-odk.yaml to expected ODK location + # 3. Run make update_repo to synchronize repository + # + # Why copy config file? + # - ODK expects config at src/ontology/${ONT_ID}-odk.yaml + # - Root project-odk.yaml is our source of truth + # - Copy ensures ODK can find and use the configuration + # + # What update_repo does: + # - Regenerates owlnet configuration files + # - Updates SPARQL query templates + # - Synchronizes release artifact configurations + # - Updates documentation templates + # - Regenerates Makefile components (if changed) + # + # Make flags: + # - -B: Force rebuild (treats all targets as needing update) + # + # Error handling: + # - Exits with error if ontology ID cannot be detected + # - Provides clear error message for troubleshooting + # + # Read more: https://github.com/INCATools/ontology-development-kit#update_repo + # ======================================================================== + - name: Run ODK Update Repo + working-directory: src/ontology + run: | + # ===== Detect Ontology ID ===== + # Extract ontology ID from root project-odk.yaml + # grep: Find line starting with "id:" + # head -n1: Take first match (handles multiple lines) + # awk: Extract second field (the actual ID value) + ONT_ID=$(grep "^id:" ../../project-odk.yaml | head -n1 | awk '{print $2}') + + # Validate that ID was found + if [ -z "$ONT_ID" ]; then + echo "Error: Could not detect Ontology ID from project-odk.yaml" + echo "Expected format: 'id: ' in project-odk.yaml" + exit 1 + fi + + echo "Detected Ontology ID: $ONT_ID" + + # ===== Copy Configuration to Expected Location ===== + # ODK expects config at src/ontology/${ONT_ID}-odk.yaml + # Copy root config to this location for ODK processing + echo "Copying project-odk.yaml to ${ONT_ID}-odk.yaml..." + cp ../../project-odk.yaml "${ONT_ID}-odk.yaml" + + # ===== Run Update Command ===== + # Synchronize repository structure with configuration + # -B flag forces rebuild of all targets + echo "Running make update_repo..." + make update_repo -B + + echo "Repository configuration update complete." + + # ======================================================================== + # STEP 2.4: Commit Configuration Changes + # ======================================================================== + # Commits updated configuration files back to the repository + # + # Conditions: + # - Only runs for push/dispatch events (not pull requests) + # - Only commits if changes detected (action skips empty commits) + # + # What gets committed: + # - src/ directory : All updated configuration files + # - owlnet configuration + # - SPARQL query templates + # - Release artifact configurations + # - Documentation templates + # - Updated Makefile components + # + # Commit metadata: + # - Message: Descriptive message indicating ODK config update + # - Author: github-actions[bot] (distinguishes from human commits) + # + # Why commit entire src/ directory? + # - update_repo may modify multiple files in different locations + # - Safer to capture all changes than risk missing files + # - Git only commits actual changes, so no harm in broad path + # ======================================================================== + - name: Commit changes + # Skip commits for pull requests (review changes manually in PR) + if: github.event_name != 'pull_request' + uses: EndBug/add-and-commit@v9 + with: + # Descriptive commit message for git history + message: "ODK: Update repo configuration" + + # Add all changes in src/ directory + # This captures all files modified by update_repo + add: "src" + + # Working directory (repository root) + cwd: "." + + # Use GitHub Actions bot as commit author + default_author: github_actions + + # Push to current branch + push: true + +# ============================================================================== +# WORKFLOW NOTES +# ============================================================================== +# This workflow is independent and does NOT trigger other workflows in the chain. +# It runs whenever ODK configuration files are modified and ensures the +# repository structure stays synchronized with the configuration. +# +# Typical use cases: +# 1. Adding new component products → update_repo generates component structure +# 2. Changing import settings → update_repo updates import processing +# 3. Modifying release settings → update_repo updates release configurations +# 4. Updating metadata → update_repo regenerates documentation templates +# +# To integrate with workflow chain (if needed in future): +# Add a final step to trigger another workflow: +# - name: Trigger Next Workflow +# uses: peter-evans/repository-dispatch@v3 +# with: +# token: ${{ secrets.GITHUB_TOKEN }} +# event-type: trigger- +# ============================================================================== \ No newline at end of file diff --git a/component_seeds.txt b/component_seeds.txt new file mode 100644 index 0000000..4d0441c --- /dev/null +++ b/component_seeds.txt @@ -0,0 +1,4 @@ +# ComponentName | ID | Label | ParentID +material_data | https://w3id.org/pmd/co/PMD_0000000 | material | https://w3id.org/pmd/co/PMD_0000001 +material_data | http://purl.obolibrary.org/obo/BFO_0000017 | realizable entity | http://purl.obolibrary.org/obo/BFO_0000020 +process_data | https://w3id.org/pmd/co/PMD_0000907 | primary shaping from the plastic state | https://w3id.org/pmd/co/PMD_0000899 \ No newline at end of file diff --git a/components.txt b/components.txt new file mode 100644 index 0000000..7fc62a7 --- /dev/null +++ b/components.txt @@ -0,0 +1,6 @@ +# Add your component names here (one per line) +# Do not add .owl extension, just the name. +material_data +process_data +sustainability_info +dismantling_data \ No newline at end of file diff --git a/creators.txt b/creators.txt new file mode 100644 index 0000000..e00d537 --- /dev/null +++ b/creators.txt @@ -0,0 +1,4 @@ +Sai +Teja +Reddy +others \ No newline at end of file diff --git a/imports.txt b/imports.txt new file mode 100644 index 0000000..b3ca7db --- /dev/null +++ b/imports.txt @@ -0,0 +1,39 @@ +# ============================================================================== +# External Ontology Imports Configuration +# ============================================================================== +# This file defines external ontologies to import into your application ontology. +# Each line defines one import with the format: import_id|import_url +# +# Format: +# import_id|import_url +# +# Where: +# - import_id: Short identifier for the ontology (lowercase, no spaces) +# This will be used as the filename prefix (e.g., "logo" → "logo.owl") +# - import_url: Direct URL to the ontology OWL file +# +# IMPORTANT NOTES: +# 1. The pipe character "|" is the delimiter between ID and URL +# 2. Lines starting with # are comments and will be ignored +# 3. Empty lines are ignored +# 4. PMD Core Ontology (pmdco) is ALWAYS imported automatically - don't add it here +# 5. For each import, you can optionally create a corresponding terms file +# (e.g., logo_terms.txt) in the root directory to specify which classes to import +# +# ============================================================================== + +# Example: Import the Logistics Ontology from PMD +# Uncomment the line below to enable this import: +# logo|https://raw.githubusercontent.com/materialdigital/logistics-application-ontology/main/logo.owl + +# Example: Import another external ontology +# Uncomment and modify as needed: +# myonto|https://example.org/ontologies/myonto.owl + +# ============================================================================== +# Add your imports below this line +# ============================================================================== + +logo|https://raw.githubusercontent.com/materialdigital/logistics-application-ontology/refs/heads/main/log-full.owl +tto|https://raw.githubusercontent.com/materialdigital/tensile-test-ontology/refs/heads/main/tto-full.owl +hto|https://raw.githubusercontent.com/materialdigital/heat-treatment-application-ontology/refs/heads/main/src/ontology/hto-full.owl \ No newline at end of file diff --git a/pmdco_terms.txt b/pmdco_terms.txt new file mode 100644 index 0000000..51f00d0 --- /dev/null +++ b/pmdco_terms.txt @@ -0,0 +1,23 @@ +https://w3id.org/pmd/co/PMD_0000833 #manufacturing process +http://purl.obolibrary.org/obo/OBI_0000070 #assay +https://w3id.org/pmd/co/PMD_0000583 #computing process +https://w3id.org/pmd/co/PMD_0000892 #portion of matter +https://w3id.org/pmd/co/PMD_0000602 #Device +http://purl.obolibrary.org/obo/OBI_0000112 #Specimen role +https://w3id.org/pmd/co/PMD_0000907 # primary shaping from the plastic state +http://purl.obolibrary.org/obo/BFO_0000040 #material entity +https://w3id.org/pmd/co/PMD_0000868 #natural organic material +https://w3id.org/pmd/co/PMD_0000661 #glass +https://w3id.org/pmd/co/PMD_0000952 #strength +https://w3id.org/pmd/co/PMD_0000877 #optical property +https://w3id.org/pmd/co/PMD_0050004 #thermoplastics +https://w3id.org/pmd/co/PMD_0000891 #disconnected material entity aggregate +https://w3id.org/pmd/co/PMD_0020102 #mass proportion +https://w3id.org/pmd/co/PMD_0020104 #volume proportion +http://purl.obolibrary.org/obo/IAO_0020000 #identifier +https://w3id.org/pmd/co/PMD_0000597 #Density +https://w3id.org/pmd/co/PMD_0000848 #mechanical property +https://w3id.org/pmd/co/PMD_0000967 #temperature +https://w3id.org/pmd/co/PMD_0000882 #phase boundary +https://w3id.org/pmd/co/PMD_0000777 #heat capacity +https://w3id.org/pmd/co/PMD_0000949 #stiffness \ No newline at end of file diff --git a/project-odk.yaml b/project-odk.yaml new file mode 100644 index 0000000..9ca60e9 --- /dev/null +++ b/project-odk.yaml @@ -0,0 +1,174 @@ +# ============================================================================== +# PROJECT-ODK.YAML - PMD Core Application Ontology Configuration +# ============================================================================== +# This is the main configuration file for the Ontology Development Kit (ODK). +# It defines how your ontology is structured, built, and released. +# +# IMPORTANT: This file will be automatically updated by the setup workflow. +# Manual edits may be overwritten during setup. +# +# Documentation: https://github.com/INCATools/ontology-development-kit +# ============================================================================== + +# ------------------------------------------------------------------------------ +# BASIC METADATA +# ------------------------------------------------------------------------------ +# These identify your ontology and its location in version control + +id: placeholder_id +title: "Placeholder Title" +github_org: materialdigital +repo: placeholder_repo +git_main_branch: main +license: "CC-BY-4.0" +description: > + PMD Core application ontology generated via ODK Template. + +# ------------------------------------------------------------------------------ +# ONTOLOGY FILE CONFIGURATION +# ------------------------------------------------------------------------------ +# Defines the format and location of your ontology files + +# edit_format: Format of the edit file (owl = OWL/XML, ofn = OWL Functional) +edit_format: owl + +# edit_ontology_file: Path to your main ontology development file +# This is where you make changes to your ontology +# Will be updated to: src/ontology/-edit.owl +edit_ontology_file: "src/ontology/placeholder_id-edit.owl" + +# ------------------------------------------------------------------------------ +# URI STRUCTURE (PMD CORE STANDARD) +# ------------------------------------------------------------------------------ +# Defines how IRIs are constructed for your ontology and its entities +# +# PMD Core Structure: https://w3id.org/pmd/co// +# +# Example for ontology "tryce": +# - Ontology IRI: https://w3id.org/pmd/co/tryce/tryce.owl +# - Entity IDs: https://w3id.org/pmd/co/tryce/TRYCE_0000001 +# - Components: https://w3id.org/pmd/co/tryce/components/annotations.owl + +# uribase: Base path for all ontology IRIs (WITHOUT trailing slash or ID) +# ODK will append uribase_suffix to form the complete ontology IRI +uribase: "https://w3id.org/pmd/co" + +# uribase_suffix: Your ontology ID (gets appended to uribase) +# Combined result: https://w3id.org/pmd/co// +uribase_suffix: "placeholder_id" + +# preferredPrefix: Uppercase prefix used in entity IDs and serializations +# Example: "TRYCE" results in entity IDs like TRYCE_0000001 +preferredPrefix: "PLACEHOLDER" + +# ------------------------------------------------------------------------------ +# NAMESPACES +# ------------------------------------------------------------------------------ +# Defines which IRI patterns belong to your ontology +# CRITICAL: This tells ODK where to generate new entity IDs +# +# Format: Must include trailing slash +# Example: ["https://w3id.org/pmd/co/tryce/"] +# +# When you create a new class in Protégé, ODK uses this namespace to generate: +# https://w3id.org/pmd/co/tryce/TRYCE_0000001 + +namespaces: + - "https://w3id.org/pmd/co/placeholder_id/" + +# ------------------------------------------------------------------------------ +# TEMPLATES (DISABLED) +# ------------------------------------------------------------------------------ +# We edit OWL files directly rather than using ROBOT templates + +use_templates: false +use_context: true + +# ------------------------------------------------------------------------------ +# IMPORTS: PMD CORE ONTOLOGY +# ------------------------------------------------------------------------------ +# Defines external ontologies to import +# +# PMD Core is the upper-level ontology for all PMD application ontologies +# module_type: slme = Syntactic Locality Module Extractor (extracts only needed terms) + +import_group: + products: + - id: pmdco + title: "PMD Core Ontology" + # Source of PMD Core ontology to import + mirror_from: "https://raw.githubusercontent.com/materialdigital/core-ontology/refs/heads/main/pmdco-full.owl" + # slme: Extract only terms referenced in your ontology (reduces file size) + module_type: slme + # base_iris: Tells ODK which IRI patterns belong to PMD Core + # This prevents PMD Core entities from being treated as local entities + base_iris: + - https://w3id.org/pmd/co/ + +# ------------------------------------------------------------------------------ +# COMPONENTS +# ------------------------------------------------------------------------------ +# Modular OWL files for organizing ontology content +# Examples: annotations.owl, individuals.owl, relations.owl +# +# Components are separate OWL files that get merged during build +# This helps organize large ontologies into logical modules +# +# This section will be populated by the setup workflow if components.txt exists + +components: + products: [] + +# ------------------------------------------------------------------------------ +# RELEASES +# ------------------------------------------------------------------------------ +# Defines what files are generated when you release your ontology + +# primary_release: The main release file (usually 'full') +primary_release: full + +# release_artefacts: Types of release files to generate +# - base: Just your ontology (no imports) +# - full: Your ontology + all imports merged +release_artefacts: + - base + - full + +# export_formats: File formats to generate for each release +# - owl: OWL/XML (standard format, verbose) +# - ttl: Turtle (human-readable RDF) +# - json: JSON-LD (for web applications) +export_formats: + - owl + - ttl + - json + +# ------------------------------------------------------------------------------ +# CI/CD CONFIGURATION +# ------------------------------------------------------------------------------ +# Controls GitHub Actions workflow generation +# +# IMPORTANT: Set to empty array [] to disable ODK's default workflows +# We use custom workflows in .github/workflows/ instead + +ci: [] + +# ------------------------------------------------------------------------------ +# ID RANGES +# ------------------------------------------------------------------------------ +# Defines how entity IDs are structured and allocated to contributors +# +# Format: +# - idsfor: Your ontology ID +# - idprefix: Base IRI for entity IDs (must match namespace + PREFIX) +# - iddigits: Number of digits in IDs (7 = _0000001 to _9999999) +# +# Example for ontology "tryce": +# idprefix: "https://w3id.org/pmd/co/tryce/TRYCE_" +# Result: https://w3id.org/pmd/co/tryce/TRYCE_0000001 +# +# This section will be populated by the setup workflow + +idranges: [] + +namespaces: []