Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ name: CI

on:
pull_request:
push:
branches:
- main
workflow_dispatch:

jobs:
Expand All @@ -19,6 +22,21 @@ jobs:
run: python3 scripts/check-documentation.py --base "${{ github.event.pull_request.base.sha }}"
- name: Check generated workspace inventory
run: python3 scripts/generate-workspace-inventory.py --check
- name: Check Git-only release metadata
run: |
python3 scripts/check-release-state.py
python3 scripts/generate-release-manifest.py \
--release-id workspace-2000.01.01.1 \
--ref HEAD \
--output /tmp/workspace-release-a.json \
--notes-output /tmp/workspace-release-a.md
python3 scripts/generate-release-manifest.py \
--release-id workspace-2000.01.01.1 \
--ref HEAD \
--output /tmp/workspace-release-b.json \
--notes-output /tmp/workspace-release-b.md
cmp /tmp/workspace-release-a.json /tmp/workspace-release-b.json
cmp /tmp/workspace-release-a.md /tmp/workspace-release-b.md
- name: Check PR documentation impact
if: github.event_name == 'pull_request'
env:
Expand Down
214 changes: 214 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
name: Workspace release

on:
workflow_dispatch:
inputs:
release_id:
description: Immutable workspace release ID (workspace-YYYY.MM.DD.N)
required: true
type: string
target_ref:
description: Full commit SHA expected to equal current main
required: true
type: string
include_router_artifact:
description: Build and attach the reviewed Linux router artifact
required: true
default: false
type: boolean
router_distribution_approval:
description: Required approval/evidence reference when attaching the router binary
required: false
type: string
prerelease:
description: Mark the GitHub release as a prerelease
required: true
default: false
type: boolean

permissions:
contents: write
id-token: write
attestations: write

concurrency:
group: workspace-release
cancel-in-progress: false

jobs:
validate:
name: Validate exact release source
runs-on: ubuntu-latest
timeout-minutes: 90
environment: release
steps:
- uses: actions/checkout@v5
with:
ref: ${{ inputs.target_ref }}
fetch-depth: 0
- name: Prove the selected source is current main
env:
TARGET_REF: ${{ inputs.target_ref }}
RELEASE_ID: ${{ inputs.release_id }}
INCLUDE_ROUTER: ${{ inputs.include_router_artifact }}
ROUTER_APPROVAL: ${{ inputs.router_distribution_approval }}
run: |
set -euo pipefail
git fetch origin main --tags --force
test "$(git rev-parse HEAD)" = "${TARGET_REF}"
test "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)"
if git show-ref --verify --quiet "refs/tags/${RELEASE_ID}"; then
echo "release tag already exists: ${RELEASE_ID}" >&2
exit 1
fi
if [[ "${INCLUDE_ROUTER}" == "true" && -z "${ROUTER_APPROVAL}" ]]; then
echo "router_distribution_approval is required for a router binary" >&2
exit 1
fi
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy,rustfmt
- uses: Swatinem/rust-cache@v2
- name: Validate documentation and release metadata
run: |
python3 scripts/check-documentation.py
python3 scripts/generate-workspace-inventory.py --check
python3 scripts/check-release-state.py
scripts/check-workspace-dependencies.sh
cargo fmt --all -- --check
- name: Verify neutral packages
run: |
cargo test -p graphql-orm-operation-catalog -p graphql-orm-ai-tool-profiles --locked
cargo test -p graphql-orm-storage --locked
cargo test -p graphql-orm-backup --features orm-sqlite --locked
cargo clippy -p graphql-orm-operation-catalog -p graphql-orm-ai-tool-profiles -p graphql-orm-storage --all-targets --locked -- -D warnings
cargo clippy -p graphql-orm-backup --all-targets --features orm-sqlite --locked -- -D warnings
RUSTDOCFLAGS="-D warnings -D missing_docs" cargo doc -p graphql-orm-operation-catalog -p graphql-orm-ai-tool-profiles -p graphql-orm-storage --no-deps --locked
RUSTDOCFLAGS="-D warnings" cargo doc -p graphql-orm-backup --features orm-sqlite --no-deps --locked
- name: Verify ORM backend lanes
run: |
cargo test -p graphql-orm --locked
cargo check -p graphql-orm --no-default-features --features postgres --locked
cargo check -p graphql-orm --no-default-features --features mssql --locked
cargo clippy -p graphql-orm --all-targets --locked -- -D warnings
RUSTDOCFLAGS="-D warnings" cargo doc -p graphql-orm -p graphql-orm-macros --no-deps --locked
- name: Verify AI provider and backend lanes
run: |
cargo test -p graphql-orm-ai --features provider-openai,provider-anthropic,provider-xai,provider-ollama,provider-openai-compatible,local-harness --locked
cargo test -p graphql-orm-ai --features graphql-case-pascal --test graphql_naming --locked
cargo check -p graphql-orm-ai --no-default-features --features postgres --locked
cargo check -p graphql-orm-ai --no-default-features --features mssql --locked
cargo check -p graphql-orm-ai -p graphql-orm --no-default-features --features graphql-orm-ai/sqlite,graphql-orm/mssql --locked
cargo test -p graphql-orm-ai --no-default-features --features postgres,provider-openai --test postgres_parity --locked -- --test-threads=1
cargo clippy -p graphql-orm-ai --all-targets --features provider-openai,provider-anthropic,provider-xai,provider-ollama,provider-openai-compatible,local-harness --locked -- -D warnings
RUSTDOCFLAGS="-D warnings -D missing_docs" cargo doc -p graphql-orm-ai -p graphql-orm-operation-catalog -p graphql-orm-ai-tool-profiles --features graphql-orm-ai/provider-openai,graphql-orm-ai/provider-anthropic,graphql-orm-ai/provider-xai,graphql-orm-ai/provider-ollama,graphql-orm-ai/provider-openai-compatible,graphql-orm-ai/local-harness --no-deps --locked
- name: Verify alternate storage and backup lanes
run: |
cargo check -p graphql-orm-backup --no-default-features --features local,orm-postgres --locked
cargo check -p graphql-orm-storage --no-default-features --features s3,azure --locked
cargo check -p graphql-orm-storage --no-default-features --features smb --locked
- name: Verify router lanes
run: |
cargo test -p graphql-orm-router-protocol --locked
cargo test -p graphql-orm-router --locked
cargo test -p graphql-orm-router --features auth-agql --locked
cargo clippy -p graphql-orm-router-protocol --all-targets --locked -- -D warnings
cargo clippy -p graphql-orm-router --all-targets --features auth-agql --locked -- -D warnings
RUSTDOCFLAGS="-D warnings -D missing_docs" cargo doc -p graphql-orm-router-protocol --no-deps --locked
RUSTDOCFLAGS="-D warnings" cargo doc -p graphql-orm-router --no-deps --features auth-agql --locked
- name: Verify router minimum supported Rust version
run: |
rustup toolchain install 1.90.0 --profile minimal
cargo +1.90.0 test -p graphql-orm-router-protocol --locked
cargo +1.90.0 test -p graphql-orm-router --locked
- name: Generate deterministic release bundle
env:
RELEASE_ID: ${{ inputs.release_id }}
run: |
mkdir -p release-dist
python3 scripts/generate-release-manifest.py \
--release-id "${RELEASE_ID}" \
--ref HEAD \
--check-clean \
--verify-tags \
--output "release-dist/${RELEASE_ID}.json" \
--notes-output "release-dist/${RELEASE_ID}.md"
- name: Build approved router artifact
if: inputs.include_router_artifact
env:
RELEASE_ID: ${{ inputs.release_id }}
ROUTER_APPROVAL: ${{ inputs.router_distribution_approval }}
run: |
set -euo pipefail
test "$(rustc -vV | sed -n 's/^host: //p')" = "x86_64-unknown-linux-gnu"
SOURCE_DATE_EPOCH=$(git show -s --format=%ct HEAD)
export SOURCE_DATE_EPOCH
cargo install cargo-cyclonedx --version 0.5.9 --locked
cargo build -p graphql-orm-router --release --features auth-agql --locked
cargo cyclonedx \
--manifest-path crates/graphql-orm-router/Cargo.toml \
--format json \
--spec-version 1.5 \
--features auth-agql
install -m 0755 target/release/graphql-orm-router release-dist/graphql-orm-router
cp crates/graphql-orm-router/graphql-orm-router.cdx.json \
release-dist/graphql-orm-router.cdx.json
cp LICENSE release-dist/LICENSE
printf '%s\n' "${ROUTER_APPROVAL}" > release-dist/router-distribution-approval.txt
tar -C release-dist --sort=name --mtime="@${SOURCE_DATE_EPOCH}" \
--owner=0 --group=0 --numeric-owner \
-czf "release-dist/${RELEASE_ID}-graphql-orm-router-x86_64-unknown-linux-gnu.tar.gz" \
graphql-orm-router graphql-orm-router.cdx.json LICENSE \
router-distribution-approval.txt
rm release-dist/graphql-orm-router release-dist/graphql-orm-router.cdx.json \
release-dist/LICENSE release-dist/router-distribution-approval.txt
- name: Create checksums
run: |
cd release-dist
sha256sum -- * > SHA256SUMS
- name: Attest release assets
uses: actions/attest-build-provenance@v3
with:
subject-path: release-dist/*
- uses: actions/upload-artifact@v4
with:
name: ${{ inputs.release_id }}
path: release-dist/
if-no-files-found: error
retention-days: 30
- name: Create annotated release tags
env:
RELEASE_ID: ${{ inputs.release_id }}
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
tags_to_push=()
while IFS= read -r package_tag; do
if git show-ref --verify --quiet "refs/tags/${package_tag}"; then
continue
fi
git tag -a "${package_tag}" -m "${package_tag}"
tags_to_push+=("refs/tags/${package_tag}")
done < <(jq -r '.packages[].tag' "release-dist/${RELEASE_ID}.json")
git tag -a "${RELEASE_ID}" -m "${RELEASE_ID}"
tags_to_push+=("refs/tags/${RELEASE_ID}")
git push --atomic origin "${tags_to_push[@]}"
- name: Publish immutable workspace release
env:
RELEASE_ID: ${{ inputs.release_id }}
GH_TOKEN: ${{ github.token }}
PRERELEASE: ${{ inputs.prerelease }}
run: |
set -euo pipefail
prerelease_flag=()
if [[ "${PRERELEASE}" == "true" ]]; then
prerelease_flag=(--prerelease)
fi
gh release create "${RELEASE_ID}" \
--verify-tag \
--title "${RELEASE_ID}" \
--notes-file "release-dist/${RELEASE_ID}.md" \
"${prerelease_flag[@]}" \
release-dist/*
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
/target
/.handoff/
*.cdx.json
*.pyc
__pycache__/
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Dastari

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ It is designed for two related use cases:
per-parent keysets, and optional counts
- single and composite primary-key read support
- single and composite relation-key batching, including nested legacy shapes like
`JimCardFiles -> Contacts -> Details`
`LegacyCardFiles -> Contacts -> Details`
- managed compound foreign keys with ordered member introspection on SQLite and PostgreSQL
- stable named ordinary indexes with typed per-column ascending or descending order
- portable spatial fields and predicates with native PostGIS support and SQLite GeoJSON fallback
Expand Down Expand Up @@ -247,16 +247,16 @@ Composite relation keys use array syntax and batch efficiently across SQLite, Po
```rust
#[graphql(skip, name = "Details")]
#[relation(
target = "JimCardFileDetail",
target = "LegacyCardFileDetail",
from = ["card_no", "cont_no"],
to = ["CardNo", "ContNo"],
multiple,
emit_fk = false
)]
pub details: Vec<JimCardFileDetail>,
pub details: Vec<LegacyCardFileDetail>,
```

A nested query such as `JimCardFiles -> Contacts -> Details` executes as one parent query plus one
A nested query such as `LegacyCardFiles -> Contacts -> Details` executes as one parent query plus one
batched relation query per relation layer, not N+1 or nested N*N queries.

## Documentation
Expand All @@ -279,6 +279,7 @@ batched relation query per relation layer, not N+1 or nested N*N queries.
- [Schema modules and fenced leases](docs/architecture/schema-modules-and-leases.md)
- [Completed monorepo consolidation](docs/plans/completed/monorepo-consolidation/README.md)
- [Testing and verification](docs/development/testing.md)
- [Workspace versioning and releases](docs/operations/release/process.md)

## Status

Expand Down
Loading