Running rs-metadata#

How to run the validator in CI, locally, from a pre-commit hook, from a CI system other than GitHub Actions, and inside your editor.

The GitHub Action and the command-line tool share one engine, so a result you get locally is exactly the result CI will get.


GitHub Actions#

The common case needs no configuration:

name: Validate software metadata

on: [push, pull_request]

jobs:
  metadata:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: LUMC-DCC/rs-metadata@v1

You get inline annotations on the pull request diff, a job summary, and a rs-metadata-report.json build artifact.

Inputs#

Every input is an escape hatch. An ordinary repository needs none of them.

Input

Default

Purpose

codemeta

""

Path to the anchor record, if it is not in the repository root. Shorthand for sources: codemeta=PATH

sources

""

Paths to metadata files kept outside the root, one ID=PATH per line

working-directory

.

Directory to validate

fail-on

error

Lowest severity that fails the job: error, warning, never

report

rs-metadata-report.json

Where the JSON report is written

upload-report

true

Upload the report as a build artifact

artifact-name

rs-metadata-report

Name of that artifact

python-version

3.12

Python used to run the validator

Outputs#

Output

Value

status

passed, passed-with-warnings or failed

errors, warnings, notes

Finding counts

report-path

Path to the JSON report

Common variations#

Treat recommendations as blocking. Reasonable once your repositories are already clean; not a good first move.

- uses: LUMC-DCC/rs-metadata@v1
  with:
    fail-on: warning

Metadata kept outside the root.

- uses: LUMC-DCC/rs-metadata@v1
  with:
    codemeta: metadata/codemeta.json

One record, packaging metadata elsewhere. When codemeta.json describes the repository as a whole but the packaging metadata sits in a subdirectory, name the files rather than moving them:

- uses: LUMC-DCC/rs-metadata@v1
  with:
    sources: |
      pyproject=backend/pyproject.toml
      package-json=frontend/package.json

Ids are the ones the report lists under Metadata sources — codemeta, cff, github, zenodo, biotools, pyproject, package-json, r-description, cargo, julia-project and dockerfile. A path given here is asserted to exist: if the file is not there, that is an error rather than a silent skip, so a typo cannot quietly validate nothing.

A monorepo with several packages, each with its own codemeta.json. Run the action once per package with a distinct artifact name:

jobs:
  metadata:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        package: [tool-a, tool-b]
    steps:
      - uses: actions/checkout@v4
      - uses: LUMC-DCC/rs-metadata@v1
        with:
          working-directory: packages/${{ matrix.package }}
          artifact-name: rs-metadata-report-${{ matrix.package }}

Artifact names must be unique within a workflow run. In a matrix, either give each job a distinct artifact-name as above, or set upload-report: false.

Report only, never fail. Useful while rolling the standard out across existing repositories.

- uses: LUMC-DCC/rs-metadata@v1
  with:
    fail-on: never

Act on the outcome in a later step.

- uses: LUMC-DCC/rs-metadata@v1
  id: metadata
  with:
    fail-on: never

- if: steps.metadata.outputs.status != 'passed'
  run: echo "::notice::Metadata needs attention before the next release."

Command line#

pip install rs-metadata

Command

What it does

rs-metadata init

Create any missing metadata files and CI workflow

rs-metadata validate

Validate the current directory

rs-metadata validate path/to/repo

Validate another repository

rs-metadata validate --verbose

Also show informational findings

rs-metadata validate --strict

Treat warnings as failures

rs-metadata validate --format json

Print the machine-readable report

rs-metadata validate --report FILE

Also write the report to a file

rs-metadata explain <code>

Explain one diagnostic code

rs-metadata explain

List every diagnostic code

rs-metadata --version

Tool, profile and CodeMeta versions

Other flags: --source ID=PATH (repeatable) to name a metadata file kept outside the repository root, --codemeta PATH as shorthand for --source codemeta=PATH, --fail-on {error,warning,never}, and --color {auto,always,never}. Color also honors the NO_COLOR and FORCE_COLOR environment variables.

rs-metadata validate --source pyproject=backend/pyproject.toml

Exit status#

Code

Meaning

0

Passed, possibly with warnings

1

Findings at or above the --fail-on threshold

2

Usage error — bad arguments, or the path is not a directory


Other CI systems#

Only the annotation renderer is GitHub-specific. Elsewhere, install the package and run the CLI.

GitLab CI

validate-metadata:
  image: python:3.12
  script:
    - pip install rs-metadata
    - rs-metadata validate --report rs-metadata-report.json
  artifacts:
    when: always
    paths:
      - rs-metadata-report.json

Jenkins, Azure Pipelines, a cron job, anything else

pip install rs-metadata
rs-metadata validate --format json --report rs-metadata-report.json

The JSON report is a stable interface meant to be read outside CI.


Pre-commit#

To catch problems before they reach CI:

# .pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: rs-metadata
        name: Validate software metadata
        entry: rs-metadata validate
        language: python
        additional_dependencies: ["rs-metadata"]
        pass_filenames: false
        files: '^(codemeta\.json|CITATION\.cff|\.zenodo\.json|biotools\.json|pyproject\.toml|package\.json|DESCRIPTION|Cargo\.toml|Project\.toml|Dockerfile)$'

pass_filenames: false matters: the validator takes a repository, not a list of files. The files pattern only decides when the hook runs.


Editor setup#

Both schemas are published by this documentation site, at the URL each one’s own $id names:

Schema

URL

Profile

https://lumc-dcc.github.io/rs-metadata/schema/1.0.0/codemeta-lumc.schema.json

Report

https://lumc-dcc.github.io/rs-metadata/schema/1.0.0/rs-metadata-report.schema.json

The path carries the release version, so a $ref written against one keeps resolving to the schema it was written against. There is no floating “latest” URL, deliberately: a schema that changes under a stable URL breaks consumers silently. A test asserts each $id matches where the site actually serves it.

Point your editor at the profile schema for completion, inline errors and hover documentation while writing codemeta.json.

VS Code — .vscode/settings.json:

{
  "json.schemas": [
    {
      "fileMatch": ["codemeta.json"],
      "url": "https://lumc-dcc.github.io/rs-metadata/schema/1.0.0/codemeta-lumc.schema.json"
    }
  ]
}

Any editor with a JSON language server — add $schema to the file itself:

{
  "$schema": "https://lumc-dcc.github.io/rs-metadata/schema/1.0.0/codemeta-lumc.schema.json",
  "@context": ["https://w3id.org/codemeta/3.1"]
}

$schema is not a CodeMeta property, but it describes the file rather than the software, so rs-metadata accepts it without complaint and JSON-LD ignores it.

The schema gives structure and completion. Run the validator for check digits, SPDX identifiers and cross-file consistency.


Reproducible output#

Set SOURCE_DATE_EPOCH to freeze the report timestamp, making two runs byte-for-byte identical:

SOURCE_DATE_EPOCH=1780000000 rs-metadata validate --format json

Useful for diffing reports across commits.

Comparing against GitHub’s own metadata#

A repository’s description, topics, homepage and detected license live on GitHub rather than in any file, and they drift like any other copy — more easily, in fact, because they are edited in a web form rather than committed alongside the code.

Inside GitHub Actions this needs no configuration. The runner already writes the event payload to disk and points GITHUB_EVENT_PATH at it, and that payload carries the repository object, so rs-metadata reads it from there. No network call, no token, no permissions to grant.

Anywhere else, fetch it once and hand it over:

gh api repos/OWNER/REPO > github-repo.json

rs-metadata picks up a github-repo.json in the repository root automatically, or take it from elsewhere:

rs-metadata validate . --source github=/tmp/github-repo.json

The validator still makes no network call of its own — you made it, which keeps the run reproducible and lets it work offline.

Nothing is read from a fork. A fork has its own URL, and a description and topics copied at the moment it was made, while its codemeta.json still describes the upstream software; comparing them would fail every fork’s CI on metadata that is not wrong.