Contributions to the S2DM repository are welcome.
Note
This guide is for contributions to the S2DM approach itself.
If you want to contribute to a certain data specification of a particular domain that follows the S2DM approach, then refer to the project, team, or organization that hosts the specification files.
- Verify whether your concern or feature request is already covered in the documented issues or discussions. If not, then create one.
- Propose a solution to the documented issue by commenting the intention.
- Work on it and create a pull request.
S2DM uses uv for packaging and
dependency management.
To start developing with S2DM, install uv
using the recommended method.
Once uv is installed, install the dependencies with the following command:
uv syncIt will create a virtual environment .venv in the root of the project.
Some features require Node.js dependencies for GraphQL schema operations. Install them with:
npm installThis installs @graphql-inspector/cli, @graphql-inspector/core, and graphql packages required by:
s2dm diff graphql- Structured diff outputs2dm check version-bump- Version bump detections2dm validate graphql- Schema validations2dm similar graphql- Type similarity searchs2dm registry initands2dm registry update- Registry functionality
Note
The @requires_graphql_inspector decorator automatically locates and injects the path to the local node_modules directory. Commands will fail with clear error messages if dependencies are missing. The GraphQL Inspector wrapper resolves the CLI path once during initialization for optimal performance.
You can run things in the virtual environment by using a uv run prefix for commands, e.g.:
uv run <some-command>Tip
You can run things without typing everytime uv run by activating the virtual environment:
source .venv/bin/activateTo deactivate the virtual environment simply run:
deactivateThe rest of this document assumes you are in the virtual environment by either activating or prefixing commands with uv run.
Pre-commit hooks can be set up with:
pre-commit install
pre-commit install --hook-type commit-msgThe first command installs hooks that run before commits (code formatting, linting, type checking, etc.).
The second command installs the commit-msg hook that validates commit messages using gitlint.
Pre-commit hooks automatically run:
- Ruff: Code formatting and linting
- Mypy: Type checking on
src/directory (uses your local virtual environment) - Various checks: YAML, TOML, trailing whitespace, etc.
- Gitlint: Commit message validation (commit-msg stage)
Tip
The mypy hook uses language: system with uv run, which means it uses your local virtual environment's dependencies. This is faster and avoids duplicating dependency lists.
Note
Both hooks are required: the first validates your code, the second enforces conventional commit message standards as described in the Commit Message Enforcement section.
Run tests with the following command:
pytest --cov-report term-missing --cov=s2dm -vvNew code should ideally have tests and not break existing tests.
Some tests require the @graphql-inspector/cli package to be installed via npm. These tests are marked with @pytest.mark.graphql_inspector.
If you don't have Node.js dependencies installed:
These tests will automatically be skipped with a message:
SKIPPED [9] tests/conftest.py:309: graphql-inspector not found. Run 'npm install' to install dependencies.
To explicitly skip these tests:
# Skip all graphql_inspector tests
pytest -m "not graphql_inspector"
# Skip graphql_inspector tests with verbose output
pytest -m "not graphql_inspector" -v
# Run only graphql_inspector tests
pytest -m "graphql_inspector"To run these tests:
-
Install Node.js dependencies first:
npm install
-
Then run all tests normally:
pytest
Simplified Semantic Data Modeling uses type annotations throughout, and mypy to do the checking.
Automatic checking: Type checking runs automatically via pre-commit hooks when you commit changes to src/.
Manual checking: To manually type check the entire codebase:
mypy src/s2dm
# or with uv:
uv run mypy src/s2dmThe mypy configuration is defined in pyproject.toml under [tool.mypy] with strict = true mode enabled, which includes comprehensive type checking rules.
Simplified Semantic Data Modeling uses ruff for code formatting.
Since it is very fast it makes sense to setup your editor to format on save.
Use ruff format to format all files in the current directory
This project uses semantic versioning with an automated release pipeline that analyzes commit messages following the Conventional Commits specification.
Our versioning system automatically determines the appropriate version bump based on commit message patterns:
- Patch releases (e.g., 0.1.1 → 0.1.2): Triggered by commits starting with
fix:orperf: - Minor releases (e.g., 0.1.0 → 0.2.0): Triggered by commits starting with
feat: - Major releases (e.g., 0.1.0 → 1.0.0): Triggered by commits with breaking changes:
- Commits with
!after the type (e.g.,feat!:orfix!:) - Commits containing
BREAKING CHANGE:in the body
- Commits with
Currently, we use zero-based versioning (0.x.y series) for pre-1.0 development:
- Breaking changes bump the minor version instead of major (0.1.0 → 0.2.0)
- This is controlled by the
ZERO_BASED_VERSIONING: trueenvironment variable in.github/workflows/release.yml - When ready for stable releases, set this to
falseto switch to standard semantic versioning
The release process is fully automated through GitHub Actions (.github/workflows/release.yml):
- Commit Analysis: Scans all commits since the last tag to determine version bump type
- Version Bumping: Uses bump-my-version to update version files
- Changelog Generation: Uses git-cliff to generate structured changelogs
- Tagging: Creates annotated Git tags with the new version
- GitHub Releases: Automatically creates GitHub releases with changelog notes
We use gitlint to enforce conventional commit message standards:
- Configuration: See
.gitlintfor rules and settings - Rules Enabled:
contrib-title-conventional-commits- Enforces conventional commit format- Custom title length limits (5-100 characters)
- Ignores GitHub Actions bot commits
Tip
Recovering failed commit messages: If gitlint rejects your commit, Git saves your message in .git/COMMIT_EDITMSG. Recover it with:
git commit --edit --file=.git/COMMIT_EDITMSGOr create a convenient alias for quick recovery:
git config --global alias.recommit 'commit -s --edit --file=.git/COMMIT_EDITMSG'
# Then simply use: git recommitTest your message before committing:
echo "feat: my feature" | gitlintFollow this format for all commits:
<type>[optional scope]: <description>
[optional body]
Signed-off-by: Your Name <your.email@example.com>
[optional footer(s)]Important: All commits must include a Signed-off-by line (Developer Certificate of Origin).
Adding sign-off automatically:
# Use -s flag when committing
git commit -s -m "feat: your message"
# Or configure git to always prompt for sign-off with an alias
git config alias.cs 'commit -s'
# Then use: git cs -m "feat: your message"The Signed-off-by line certifies that you have the right to submit the code under the project's license.
Common types:
feat: New featuresfix: Bug fixesdocs: Documentation changesstyle: Code style changes (formatting, etc.)refactor: Code refactoringperf: Performance improvementstest: Adding or updating testschore: Maintenance tasksci: CI/CD changes
Breaking changes:
- Add
!after type:feat!: remove deprecated API - Or include
BREAKING CHANGE:in footer
Examples:
# Feature for exporters
feat(exporters): add jsonschema exporter
This adds a new exporter that converts schemas to JSON Schema format.
Signed-off-by: John Doe <john.doe@example.com>
# Fix in graphql processing
fix: resolve memory leak in graphql processing
Signed-off-by: John Doe <john.doe@example.com>
# Feature including breaking change
feat!: migrate to new configuration format
The configuration file structure has been updated to YAML format.
Old TOML configs are no longer supported.
Signed-off-by: John Doe <john.doe@example.com>