Skip to content

Commit f3bf097

Browse files
author
DevForge Engineer
committed
Merge remote-tracking branch 'origin/master'
2 parents 2379038 + 45b887a commit f3bf097

5 files changed

Lines changed: 56 additions & 6 deletions

File tree

CHANGELOG.md

273 Bytes

# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [1.7.0] - 2026-05-15 ### Added - VS Code extension with live preview, diff, and quick convert - Right-click conversion from file explorer - Custom editor for `.schemaforge` files - Auto-refresh preview on file save ## [1.6.0] - 2026-05-15 ### Added - Scala case class support (Doobie/Quill/Slick) as 11th format ## [1.5.0] - 2026-05-15 ### Added - Entity Framework Core (C#) support as 10th format - Data annotations generation for EF Core entities ## [1.4.0] - 2026-05-15 ### Added - MCP (Model Context Protocol) server for AI agent integration - `schemaforge mcp` command (stdio and SSE modes) - `schemaforge check` command — schema consistency across directories - `schemaforge formats` command — list supported formats - `schemaforge detect` command — identify format from filename - CI/CD workflow for automated testing and publishing ### Changed - Consolidated test workflow configuration ## [1.3.0] - 2026-05-15 ### Added - GraphQL SDL format support as 9th schema format - Bidirectional conversion between GraphQL and all other formats - Enum, directive, and custom scalar support in GraphQL ## [1.2.0] - 2026-05-15 ### Added - JSON Schema support (draft 2020-12) as 8th format - JSON Schema import/export with type mapping - URI-friendly enum value generation ## [1.1.0] - 2026-05-15 ### Added - Custom type mapping configuration via YAML/JSON override files - Template variables in type overrides: `{length}`, `{precision}`, `{scale}`, `{values}` - `--type-map` CLI option for all convert commands ## [1.0.0] - 2026-05-15 ### Added - Stable release with comprehensive docs and CLI polish - Licensing gating via `revenueholdings-license` - Star badge and call-to-action in README ### Fixed - Version bump from 1.0.0 to 1.7.0 alignment (internal consistency) ## [0.9.0] - 2026-05-15 ### Changed - Shared generator base module (`_base.py`) for reduced code duplication - Refactored `fn:` default handling for cross-format function defaults ## [0.8.0] - 2026-05-15 ### Added - Alembic migration generation as 7th format (generator-only) - `--output` support for migration script generation - Alembic `op.create_table`, `op.add_column`, `op.create_index` output ## [0.7.0] - 2026-05-15 ### Added - MySQL table options: `ENGINE=InnoDB`, `AUTO_INCREMENT`, `DEFAULT CHARSET`, `COMMENT` - Inline ENUM column type: `ENUM('small', 'medium', 'large')` parsing and roundtripping ## [0.6.0] - 2026-05-15 ### Added - SQL parser edge cases: `TEMPORARY TABLE`, backtick quoting, quoted identifiers - `fn:` default prefix preservation across roundtrips ### Fixed - Roundtrip fidelity for function-based default values ## [0.5.0] - 2026-05-15 ### Added - SQLAlchemy declarative model support as 5th format - `schemaforge diff` command for line-level schema comparison - Batch directory mode (`schemaforge check --dir`) - Demo fixtures with blog schema in all formats - 17 new roundtrip and edge-case tests ### Fixed - PRAGMA KEY implies NOT NULL in SQL parser - Generator index handling for SQLAlchemy ## [0.4.0] - 2026-05-15 ### Added - Django models support as 4th format - TypeORM entities support as 3rd format - Parser/generator registration system in convert registry ### Fixed - `convert_schema` and `register_format` functions restored after merge conflict ## [0.3.0] - 2026-05-15 ### Added - TypeORM entities support as 3rd format - Decorator-based entity parsing and generation ## [0.2.0] - 2026-05-15 ### Added - Drizzle ORM schema support as 2nd format - Drizzle parser/generator registered in convert registry ## [0.1.0] - 2026-05-14 ### Added - Initial beta release - Core bidirectional conversion engine - SQL DDL ↔ Prisma schema conversion - Internal Representation (IR) architecture - CLI interface with `convert` command - Test suite with 270+ passing tests - CI workflow with ruff lint and pytest - CONTRIBUTING.md for contributor guidance

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[Unreleased]

Fixed

  • schemaforge check now exits non-zero when a schema file fails to convert (e.g. a malformed JSON/SQL file). Previously a conversion failure with no pairwise mismatch produced a "Mismatches: 0" report and exited 0, so CI could pass while a schema silently failed to parse. The report now emits an explicit FAIL: N file(s) failed to convert line and the CLI keys its exit code off it.

[1.7.0] - 2026-05-15

Added

  • VS Code extension with live preview, diff, and quick convert
  • Right-click conversion from file explorer
  • Custom editor for .schemaforge files
  • Auto-refresh preview on file save

[1.6.0] - 2026-05-15

Added

  • Scala case class support (Doobie/Quill/Slick) as 11th format

[1.5.0] - 2026-05-15

Added

  • Entity Framework Core (C#) support as 10th format
  • Data annotations generation for EF Core entities

[1.4.0] - 2026-05-15

Added

  • MCP (Model Context Protocol) server for AI agent integration
  • schemaforge mcp command (stdio and SSE modes)
  • schemaforge check command — schema consistency across directories
  • schemaforge formats command — list supported formats
  • schemaforge detect command — identify format from filename
  • CI/CD workflow for automated testing and publishing

Changed

  • Consolidated test workflow configuration

[1.3.0] - 2026-05-15

Added

  • GraphQL SDL format support as 9th schema format
  • Bidirectional conversion between GraphQL and all other formats
  • Enum, directive, and custom scalar support in GraphQL

[1.2.0] - 2026-05-15

Added

  • JSON Schema support (draft 2020-12) as 8th format
  • JSON Schema import/export with type mapping
  • URI-friendly enum value generation

[1.1.0] - 2026-05-15

Added

  • Custom type mapping configuration via YAML/JSON override files
  • Template variables in type overrides: {length}, {precision}, {scale}, {values}
  • --type-map CLI option for all convert commands

[1.0.0] - 2026-05-15

Added

  • Stable release with comprehensive docs and CLI polish
  • Licensing gating via revenueholdings-license
  • Star badge and call-to-action in README

Fixed

  • Version bump from 1.0.0 to 1.7.0 alignment (internal consistency)

[0.9.0] - 2026-05-15

Changed

  • Shared generator base module (_base.py) for reduced code duplication
  • Refactored fn: default handling for cross-format function defaults

[0.8.0] - 2026-05-15

Added

  • Alembic migration generation as 7th format (generator-only)
  • --output support for migration script generation
  • Alembic op.create_table, op.add_column, op.create_index output

[0.7.0] - 2026-05-15

Added

  • MySQL table options: ENGINE=InnoDB, AUTO_INCREMENT, DEFAULT CHARSET, COMMENT
  • Inline ENUM column type: ENUM('small', 'medium', 'large') parsing and roundtripping

[0.6.0] - 2026-05-15

Added

  • SQL parser edge cases: TEMPORARY TABLE, backtick quoting, quoted identifiers
  • fn: default prefix preservation across roundtrips

Fixed

  • Roundtrip fidelity for function-based default values

[0.5.0] - 2026-05-15

Added

  • SQLAlchemy declarative model support as 5th format
  • schemaforge diff command for line-level schema comparison
  • Batch directory mode (schemaforge check --dir)
  • Demo fixtures with blog schema in all formats
  • 17 new roundtrip and edge-case tests

Fixed

  • PRAGMA KEY implies NOT NULL in SQL parser
  • Generator index handling for SQLAlchemy

[0.4.0] - 2026-05-15

Added

  • Django models support as 4th format
  • TypeORM entities support as 3rd format
  • Parser/generator registration system in convert registry

Fixed

  • convert_schema and register_format functions restored after merge conflict

[0.3.0] - 2026-05-15

Added

  • TypeORM entities support as 3rd format
  • Decorator-based entity parsing and generation

[0.2.0] - 2026-05-15

Added

  • Drizzle ORM schema support as 2nd format
  • Drizzle parser/generator registered in convert registry

[0.1.0] - 2026-05-14

Added

  • Initial beta release
  • Core bidirectional conversion engine
  • SQL DDL ↔ Prisma schema conversion
  • Internal Representation (IR) architecture
  • CLI interface with convert command
  • Test suite with 270+ passing tests
  • CI workflow with ruff lint and pytest
  • CONTRIBUTING.md for contributor guidance

src/schemaforge/check.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def check_directory(
7373
failures.append(f" FAIL {name}: {e}")
7474

7575
if not converted:
76-
return "No files could be converted to {}\n{}".format(
76+
return "FAIL: No files could be converted to {}\n{}".format(
7777
canonical, "\n".join(failures)
7878
)
7979

@@ -109,10 +109,18 @@ def check_directory(
109109
lines.append("")
110110
for m in mismatches:
111111
lines.append(m)
112-
lines.append("FAIL: Schema files are not equivalent")
112+
113+
# Deterministic exit-status lines. The CLI keys its process exit code off
114+
# these. A conversion failure must fail the check even when there is no
115+
# pairwise mismatch -- previously the "Mismatches: 0" report with no PASS
116+
# line let CI report green while a schema silently failed to parse.
117+
if mismatches or failures:
118+
if mismatches:
119+
lines.append("FAIL: Schema files are not equivalent")
120+
if failures:
121+
lines.append(f"FAIL: {len(failures)} file(s) failed to convert")
113122
else:
114123
lines.append(" Mismatches: 0")
115-
if not failures:
116-
lines.append("PASS: All schema files are equivalent")
124+
lines.append("PASS: All schema files are equivalent")
117125

118126
return "\n".join(lines)

src/schemaforge/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ def check(directory: str, canonical: str, type_map_path: str | None) -> None:
177177
try:
178178
result = check_directory(directory, canonical=canonical, type_map_path=type_map_path)
179179
click.echo(result)
180-
if "FAIL" in result and "PASS" not in result:
180+
if "FAIL:" in result:
181181
sys.exit(1)
182182
except (NotADirectoryError, ValueError, FileNotFoundError) as e:
183183
click.echo(f"Error: {e}", err=True)

tests/test_check.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,20 @@ def test_check_directory_canonical_format():
138138

139139
result = check_directory(tmpdir, canonical="prisma")
140140
assert "compared via prisma" in result
141+
142+
143+
def test_check_directory_conversion_failure_reports_fail():
144+
"""A file that fails to parse must produce a FAIL line (not a silent PASS).
145+
146+
Regression guard: previously a conversion failure with no pairwise mismatch
147+
yielded "Mismatches: 0" and no PASS/FAIL line, so the CLI exited 0 (green)
148+
while a schema silently failed to parse.
149+
"""
150+
with tempfile.TemporaryDirectory() as tmpdir:
151+
Path(tmpdir, "schema.sql").write_text(SAMPLE_SQL)
152+
Path(tmpdir, "broken.json").write_text("{ this is not valid json ,,, }")
153+
154+
result = check_directory(tmpdir)
155+
assert "Conversion failures: 1" in result
156+
assert "FAIL: 1 file(s) failed to convert" in result
157+
assert "PASS:" not in result

tests/test_cli.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,10 +509,35 @@ def test_check_invalid_directory(self):
509509
finally:
510510
Path(f_path).unlink(missing_ok=True)
511511

512+
def test_check_cli_exits_nonzero_on_conversion_failure(self):
513+
"""Regression: a schema that fails to parse must make `check` exit non-zero.
514+
515+
Previously the CLI only failed on mismatches, so a parse failure with no
516+
pairwise mismatch reported "Mismatches: 0" and exited 0 (silent green).
517+
"""
518+
runner = CliRunner()
519+
with tempfile.TemporaryDirectory() as tmpdir:
520+
Path(tmpdir, "schema.sql").write_text(SAMPLE_SQL)
521+
Path(tmpdir, "broken.json").write_text("{ this is not valid json ,,, }")
522+
523+
result = runner.invoke(main, ["check", "--dir", tmpdir])
524+
assert result.exit_code != 0
525+
assert "FAIL:" in result.output
526+
527+
def test_check_cli_exits_zero_when_all_equivalent(self):
528+
"""Two identical schema files are trivially equivalent -> exit 0 with PASS."""
529+
runner = CliRunner()
530+
with tempfile.TemporaryDirectory() as tmpdir:
531+
Path(tmpdir, "a.sql").write_text(SAMPLE_SQL)
532+
Path(tmpdir, "b.sql").write_text(SAMPLE_SQL)
533+
534+
result = runner.invoke(main, ["check", "--dir", tmpdir])
535+
assert result.exit_code == 0
536+
assert "PASS: All schema files are equivalent" in result.output
537+
512538

513539
# ═══════════════════════════════════════════════════════════════
514540
# mcp command
515-
# ═══════════════════════════════════════════════════════════════
516541

517542

518543
class TestMcpCommand:

0 commit comments

Comments
 (0)