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
10 changes: 4 additions & 6 deletions .github/workflows/generation.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: Generate sample targets

on:
pull_request:
branches: [main]
push:
branches: [main]
workflow_dispatch:
inputs:
target:
Expand All @@ -15,14 +19,8 @@ permissions:
jobs:
generate:
runs-on: ubuntu-24.04
env:
SAMPLE_REVIEW_COMMIT: ${{ vars.SAMPLE_REVIEW_COMMIT }}
steps:
- uses: actions/checkout@v6
- name: Require manual review before any checks
env:
APPROVED_COMMIT: ${{ vars.SAMPLE_REVIEW_COMMIT }}
run: '[[ "$APPROVED_COMMIT" == "$GITHUB_SHA" ]] || { echo "Manual review required"; exit 1; }'
- uses: actions/setup-node@v6
with:
node-version: 24
Expand Down
32 changes: 22 additions & 10 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
# DataM8 public sample
# Working in the DataM8 Public Sample

This repository owns a small AdventureWorks Base/Model example, business functions and the
classic Databricks, Docs and Power BI generation references. Large multi-source models, Lakeflow, Fabric and
all cloud deployment/integration belong to the private datam8-solutions repo.
This repository owns the small AdventureWorks Base/Model example, business
functions and classic Databricks, Docs and Power BI generation references.
It supports local generation; no cloud deployment or integration runner is included.

- Preserve unrelated local changes. Never commit installed plugins or credentials.
- Do not add live workspace names, IDs, hosts, catalog or principal bindings.
- The migration is awaiting manual review: do not run tests, CI checks, cloud
deployments or integration until the user explicitly approves the exact commit.
- Regeneration and manual inspection for the review are allowed.
- The maintainer merges feature branches manually; Solutions must merge first.
- Start with [getting started](docs/getting-started.md) and the
[local checks](docs/integration-tests.md). Read the affected target's reference
before changing its templates or payloads.
- Preserve the model's dependency closure, saved type mappings and three targets.
Schema and CLI APIs remain canonical upstream; do not patch them here.
- Use disposable complete copies for editing and generation. Output can be replaced.
Use local fixtures for SQL metadata tests; do not contact a live source.
- Continue authorized local edits, dependency setup, tests and generation without
a separate commit approval or mandatory model handoff.
- Never commit installed plugins, credentials or live workspace/source bindings.
Public entry points and dependencies must work without private repository access.
- With Node 24 and the Python version in `pyproject.toml`, run:
`uv sync --frozen`, `node --test scripts/check-docs.test.mjs`,
`node scripts/check-docs.mjs`, `uv run python -m unittest discover -s tests`
and `uv run python scripts/check_generation.py --target all`.
- Report passes, failures and skips separately. Local generation is not evidence
of live source, app or cloud acceptance. Live work requires separate authorization.
- Keep unrelated changes intact and propose feature PRs; the maintainer merges manually.
130 changes: 29 additions & 101 deletions Base/DataSourceTypes.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,164 +123,92 @@
"targetType": "string"
}
],
"pluginId": "sqlserver",
"pluginId": "builtin:SQLServer",
"connectionProperties": [
{
"name": "authMode",
"displayName": "authMode",
"required": true,
"type": "string",
"default": "sql_user"
"required": true
},
{
"name": "host",
"displayName": "host",
"required": false,
"type": "string"
"type": "string",
"required": true
},
{
"name": "database",
"displayName": "database",
"required": false,
"type": "string"
"type": "string",
"required": true
},
{
"name": "port",
"displayName": "port",
"required": false,
"type": "number",
"required": true,
"default": 1433
},
{
"name": "username",
"displayName": "username",
"required": false,
"type": "string"
"type": "string",
"required": false
},
{
"name": "password",
"displayName": "password",
"required": false,
"type": "secret"
"type": "secret",
"required": false
},
{
"name": "encrypt",
"displayName": "encrypt",
"name": "trust_server_certificate",
"required": false,
"description": "Enable encrypted transport",
"default": false,
"type": "boolean",
"default": true
"description": "Trust unverifyable certificates, e.g. self-signed"
},
{
"name": "trusted_connection",
"displayName": "trusted_connection",
"name": "trust_server_certificate_ca",
"required": false,
"description": "Use Windows authentication",
"type": "boolean",
"default": false
},
{
"name": "workspace_url",
"displayName": "workspace_url",
"required": false,
"type": "string"
},
{
"name": "warehouse_id",
"displayName": "warehouse_id",
"required": false,
"type": "string"
},
{
"name": "uc_connection_name",
"displayName": "uc_connection_name",
"required": false,
"type": "string"
"description": "Path to a root ca to verify the server certificate against"
},
{
"name": "token",
"displayName": "token",
"required": false,
"type": "secret"
},
{
"name": "client_id",
"displayName": "client_id",
"required": false,
"type": "string"
},
{
"name": "client_secret",
"displayName": "client_secret",
"name": "encrypt",
"required": false,
"type": "secret"
"default": true,
"type": "boolean",
"description": "Activate SSL encryption"
},
{
"name": "auth_scope",
"displayName": "auth_scope",
"name": "trusted_connection",
"required": false,
"type": "string",
"default": "all-apis"
"default": false,
"type": "boolean",
"description": "Enables Windows Authentication"
}
],
"authModes": [
{
"name": "sql_user",
"displayName": "Username / Password",
"required": [
"authMode",
"host",
"database",
"port",
"username",
"password"
],
"optional": [
"trust_server_certificate",
"trust_server_certificate_ca",
"encrypt"
]
},
{
"name": "windows",
"displayName": "Windows",
"displayName": "Windows Authentication",
"required": [
"authMode",
"host",
"database",
"port",
"trusted_connection"
],
"optional": [
"trust_server_certificate",
"trust_server_certificate_ca",
"encrypt"
]
},
{
"name": "databricks_pat",
"displayName": "Databricks (PAT)",
"required": [
"authMode",
"database",
"workspace_url",
"warehouse_id",
"uc_connection_name",
"token"
],
"optional": []
},
{
"name": "databricks_oauth",
"displayName": "Databricks (OAuth Client Credentials)",
"required": [
"authMode",
"database",
"workspace_url",
"warehouse_id",
"uc_connection_name",
"client_id",
"client_secret"
],
"optional": [
"auth_scope"
]
}
]
}
Expand Down
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Working rules

Read [AGENTS.md](AGENTS.md). This public sample is generate-only. The two migration branches await manual review before any tests or deployment work.
Read [AGENTS.md](AGENTS.md) for repository ownership, local verification commands
and cloud/source boundaries. This public sample supports local generation only.
16 changes: 10 additions & 6 deletions Generate/databricks-lake/DEPLOYMENT.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# Classic target: generation only
# Classic Target: Generation Only

This public target renders notebooks and resource definitions. Environment-bound
bundle entrypoints and cloud execution live in the private
[Solutions repository](https://github.com/oraylis/datam8-solutions).
The utilities retained under Output are neutral runtime source assets required
by generated references, not deployment configuration.
This target renders notebooks and resource definitions. It contains no
environment-bound bundle entrypoint or cloud execution workflow. Configure your
own deployment process after reviewing platform, source and identity prerequisites;
generated files are not deployment evidence.

The utilities retained under `Output/databricks-lake/utils` are neutral runtime
source assets required by generated references, not deployment configuration.
Keep them separate from cleaned output. See [local generation](../../docs/getting-started.md)
and [deployment boundaries](../../docs/quickstart.md).
16 changes: 7 additions & 9 deletions Generate/databricks-lake/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ beneath it:

```text
Output/databricks-lake/
databricks.yml # Maintained bundle entry point
utils/ # Shared runtime notebooks/frameworks
generated/
notebooks/<zone>/ddl/<product>/<module>/<entity>.py
Expand All @@ -104,19 +103,18 @@ The sample therefore generates `load_sales_daily.yml` and
assignments and the other target-specific properties.

The exact notebook subdirectories follow the model's folder hierarchy. Cluster
settings are emitted when cluster metadata is configured. The existing
[bundle entry point](https://github.com/oraylis/datam8-solutions/tree/main/deployment) includes the
generated resources and the shared `utils` directory. Maintain those deployment
files alongside the generated output. See [deployment and integration](DEPLOYMENT.md)
for the configured test environments and local run command.
settings are emitted when cluster metadata is configured. Generated notebooks
reference the authored `utils` directory. The sample contains no environment-bound
bundle entrypoint; review [deployment boundaries](DEPLOYMENT.md) before configuring
your own platform delivery process.

## Generate and use the result

Use **DataM8 app 2.0.0**, select **databricks** in the generator and choose
**Generate**. Or run **DataM8 CLI 2.0.0** from the solution root:
Use a compatible DataM8 app, select **databricks** in the generator and choose
**Generate**. Or use the pinned CLI from the solution root:

```sh
datam8 generate databricks --solution ./ORAYLISDatabricksSample.dm8s
uv run datam8 generate databricks --solution ./ORAYLISDatabricksSample.dm8s
```

Review the notebooks, job graphs and generated paths. Configure your workspace,
Expand Down
1 change: 1 addition & 0 deletions Generate/databricks-lake/__modules/metadata_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

TARGET_NAME = "databricks"


# Common aliases so source / canonical names converge to those defined in DataTypes.json.
TYPE_ALIASES: dict[str, str] = {
"integer": "int",
Expand Down
2 changes: 1 addition & 1 deletion Generate/databricks-lake/__modules/payload.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ def generate_raw_dml_notebooks(model: Model, cache: Cache) -> Sequence[IPayload]
)
source_type = next((item.entity for item in model.dataSourceTypes.values() if item.entity.name == data_source_entry.type), None)
plugin = getattr(source_type, "pluginId", None)
if plugin not in {"sqlserver", "oracle", "mysql", "postgresql", "http_api"}:
if plugin not in {"builtin:SQLServer", "oracle", "mysql", "postgresql", "http_api"}:
raise ValueError(f"Unsupported UC source plugin for {data_source_name}: {plugin}")
extended = data_source_entry.extendedProperties or {}
connection_name = extended.get("unityCatalogConnection", plugin)
Expand Down
4 changes: 2 additions & 2 deletions Generate/shared/uc_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def database_query(connection, location, database, plugin):
if match and not re.fullmatch(identifier + r'(?:\s*\.\s*' + identifier + r')*', table):
table, predicate = location.strip(), None
if not re.match(r"(?i)^select\b", table):
table = table.replace("[", "").replace("]", "") if plugin == "sqlserver" else table
table = table.replace("[", "").replace("]", "") if plugin == "builtin:SQLServer" else table
selection = "dbtable => " + sql_literal(table)
else:
selection = "query => " + sql_literal(table)
Expand All @@ -35,7 +35,7 @@ def read_database(spark, connection, location, database, plugin):
query, predicate = database_query(connection, location, database, plugin)
frame = spark.sql(query)
if predicate:
frame = frame.filter(predicate.replace("[", "`").replace("]", "`") if plugin == "sqlserver" else predicate)
frame = frame.filter(predicate.replace("[", "`").replace("]", "`") if plugin == "builtin:SQLServer" else predicate)
return frame


Expand Down
Loading
Loading