From 7d045c4f1973b66ab17e4dacaa8b1879f0bd8821 Mon Sep 17 00:00:00 2001 From: Pawel Kosiec Date: Mon, 23 Mar 2026 11:37:38 +0100 Subject: [PATCH 1/3] chore: add .env.tmpl to generated app templates and document template system Copy .env.tmpl and .env.example.tmpl into each generated app template so that `databricks apps init` can render .env for end users. Add user-facing template documentation and update CONTRIBUTING.md. Signed-off-by: Pawel Kosiec --- CONTRIBUTING.md | 11 ++-- docs/docs/development/templates.md | 95 ++++++++++++++++++++++++++++++ tools/generate-app-templates.ts | 11 +++- 3 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 docs/docs/development/templates.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 010d7bea..ada5188a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -100,17 +100,18 @@ export DATABRICKS_WORKSPACE_DIR=your-workspace-dir # The source workspace direct ## Generating App templates -To generate app templates, run the following command: +The single source template (`template/`) is used to generate app variants for the [`app-templates`](https://github.com/databricks/app-templates) repository. The variants and post-processing steps are defined in `tools/generate-app-templates.ts`. ```bash pnpm generate:app-templates ``` -By default, the command will generate app templates in the `../app-templates` directory, assuming that you have the [`app-templates`](https://github.com/databricks/app-templates) repository cloned in the same parent directory as this one. +By default, this outputs to `../app-templates`, assuming the repo is cloned alongside this one. -You can override the output directory by setting the `APP_TEMPLATES_OUTPUT_DIR` environment variable. - -By default, the command will use the `databricks` CLI to generate the app templates. You can override the CLI by setting the `DATABRICKS_CLI` environment variable to provide a different binary name or path. +| Variable | Default | Description | +|----------|---------|-------------| +| `APP_TEMPLATES_OUTPUT_DIR` | `../app-templates` | Output directory | +| `DATABRICKS_CLI` | `databricks` | CLI binary name or path | ## Contributing to AppKit documentation diff --git a/docs/docs/development/templates.md b/docs/docs/development/templates.md new file mode 100644 index 00000000..50cbeba2 --- /dev/null +++ b/docs/docs/development/templates.md @@ -0,0 +1,95 @@ +--- +sidebar_position: 6 +--- + +# Templates + +AppKit uses a template system powered by the Databricks CLI's `databricks apps init` command. Templates define the project structure, and `.tmpl` files are processed with Go's `text/template` engine to generate customized output. + +## How `.tmpl` files work + +Any file ending in `.tmpl` is processed by the CLI during `databricks apps init`: + +1. The `.tmpl` suffix is stripped (e.g. `.env.tmpl` → `.env`) +2. Go template expressions are evaluated and substituted +3. The rendered file is written to the output directory + +Files named with a `_` prefix are renamed to `.` prefix (e.g. `_gitignore` → `.gitignore`). + +### Template variables + +| Variable | Description | +|----------|-------------| +| `.projectName` | Project name from `--name` or interactive prompt | +| `.workspaceHost` | Databricks workspace URL | +| `.profile` | Databricks CLI profile name (empty if using host-based auth) | +| `.appDescription` | App description | +| `.plugins.` | Non-nil for each selected plugin, enabling conditionals | +| `.dotEnv.content` | Generated `.env` content from plugin resources | +| `.dotEnv.example` | Generated `.env.example` content with placeholders | +| `.bundle.*` | Generated `databricks.yml` sections (variables, resources, target variables) | +| `.appEnv` | Generated `app.yaml` env entries | + +### Conditional content + +Use Go template conditionals to include/exclude code based on selected plugins: + +```go +{{- if .plugins.analytics}} +import { analytics } from '@databricks/appkit'; +{{- end}} +``` + +## `appkit.plugins.json` + +The plugin manifest drives the CLI's behavior during `databricks apps init`: + +- **Plugin selection UI** — selectable plugins shown in the interactive prompt +- **Resource prompts** — required/optional resources prompt the user for values (e.g. SQL Warehouse ID) +- **`.dotEnv` population** — resource fields with an `env` property are written to `.env` +- **`app.yaml` generation** — resource fields produce `env` + `valueFrom` entries +- **`databricks.yml` generation** — resource fields produce bundle variables and app resource entries + +### Resource field properties + +Each resource field in the manifest can have these properties: + +| Property | Description | +|----------|-------------| +| `env` | Environment variable name written to `.env` and `app.yaml` | +| `description` | Shown in the interactive prompt and bundle variable description | +| `localOnly` | Only written to `.env` for local dev; excluded from `app.yaml` and bundle variables | +| `bundleIgnore` | Excluded from `databricks.yml` variables (but still in `.env`) | +| `value` | Default value used when no user input is provided | +| `resolve` | Auto-populated by CLI from API calls instead of prompting (see below) | +| `examples` | Example values shown in field descriptions | + +### Resolvers + +Fields with a `resolve` property are auto-populated by the CLI from API calls rather than user prompts. The format is `:`. + +Currently only the `postgres` resource type has a resolver. Given the user-provided `branch` and `database` resource names, it derives: + +| Resolve key | Description | +|-------------|-------------| +| `postgres:host` | Postgres host from the branch's read-write endpoint | +| `postgres:databaseName` | Postgres database name from the database resource | +| `postgres:endpointPath` | Lakebase endpoint resource name from the branch's endpoints | + +Example field definition: + +```json +{ + "host": { + "env": "PGHOST", + "localOnly": true, + "resolve": "postgres:host", + "description": "Postgres host for local development." + } +} +``` + +## See also + +- [Plugin management](../plugins/plugin-management.md) — `appkit plugin sync`, `appkit plugin create` +- [Configuration](../configuration.mdx) — environment variables diff --git a/tools/generate-app-templates.ts b/tools/generate-app-templates.ts index d429ea59..ef90a116 100644 --- a/tools/generate-app-templates.ts +++ b/tools/generate-app-templates.ts @@ -18,6 +18,7 @@ import { spawnSync } from "node:child_process"; import { + copyFileSync, existsSync, mkdirSync, readFileSync, @@ -167,9 +168,15 @@ console.log( function postProcess(appDir: string, app: AppTemplate): void { console.log(` Post-processing ${app.name}...`); - // 1. Delete .env — end users get it from `databricks apps init`, but published - // templates should not ship credentials from the generator's environment. + // 1. Delete .env (contains resolved credentials from the generator's CLI profile) + // and copy .env.tmpl / .env.example.tmpl so that `databricks apps init` can + // render them for end users when they scaffold from the published template. rmSync(join(appDir, ".env"), { force: true }); + copyFileSync(join(TEMPLATE_PATH, ".env.tmpl"), join(appDir, ".env.tmpl")); + copyFileSync( + join(TEMPLATE_PATH, ".env.example.tmpl"), + join(appDir, ".env.example.tmpl"), + ); // 2. Sync appkit.plugins.json based on server imports (discovers available plugins // and marks the ones used in the plugins array as required). From b8ba4168f840556827554dce614a753a4730e8d8 Mon Sep 17 00:00:00 2001 From: Pawel Kosiec Date: Mon, 23 Mar 2026 11:57:43 +0100 Subject: [PATCH 2/3] chore: add comment header to .env.tmpl and drop .env.example.tmpl Add an explanatory comment to .env.tmpl in generated templates and stop copying .env.example.tmpl as it's not needed. Signed-off-by: Pawel Kosiec --- tools/generate-app-templates.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tools/generate-app-templates.ts b/tools/generate-app-templates.ts index ef90a116..55e7ffe8 100644 --- a/tools/generate-app-templates.ts +++ b/tools/generate-app-templates.ts @@ -18,7 +18,6 @@ import { spawnSync } from "node:child_process"; import { - copyFileSync, existsSync, mkdirSync, readFileSync, @@ -169,14 +168,18 @@ function postProcess(appDir: string, app: AppTemplate): void { console.log(` Post-processing ${app.name}...`); // 1. Delete .env (contains resolved credentials from the generator's CLI profile) - // and copy .env.tmpl / .env.example.tmpl so that `databricks apps init` can - // render them for end users when they scaffold from the published template. + // and write .env.tmpl with a header comment so that `databricks apps init` + // can render it for end users when they scaffold from the published template. rmSync(join(appDir, ".env"), { force: true }); - copyFileSync(join(TEMPLATE_PATH, ".env.tmpl"), join(appDir, ".env.tmpl")); - copyFileSync( - join(TEMPLATE_PATH, ".env.example.tmpl"), - join(appDir, ".env.example.tmpl"), - ); + + const envTmplHeader = [ + "# This file is a Go template processed by `databricks apps init --template `.", + "# When the command is run pointing to this template, variables like", + "# {{.workspaceHost}} are substituted and the result is written as .env.", + "", + ].join("\n"); + const envTmplBody = readFileSync(join(TEMPLATE_PATH, ".env.tmpl"), "utf-8"); + writeFileSync(join(appDir, ".env.tmpl"), envTmplHeader + envTmplBody); // 2. Sync appkit.plugins.json based on server imports (discovers available plugins // and marks the ones used in the plugins array as required). From e87c0828b16fbb01d53e6632cc5331bd0a3eb311 Mon Sep 17 00:00:00 2001 From: Pawel Kosiec Date: Mon, 23 Mar 2026 12:20:43 +0100 Subject: [PATCH 3/3] fix: remove template placeholders from .env.tmpl comment Signed-off-by: Pawel Kosiec --- tools/generate-app-templates.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/generate-app-templates.ts b/tools/generate-app-templates.ts index 55e7ffe8..4b029121 100644 --- a/tools/generate-app-templates.ts +++ b/tools/generate-app-templates.ts @@ -174,8 +174,7 @@ function postProcess(appDir: string, app: AppTemplate): void { const envTmplHeader = [ "# This file is a Go template processed by `databricks apps init --template `.", - "# When the command is run pointing to this template, variables like", - "# {{.workspaceHost}} are substituted and the result is written as .env.", + "# Template variables are substituted and the result is written as .env.", "", ].join("\n"); const envTmplBody = readFileSync(join(TEMPLATE_PATH, ".env.tmpl"), "utf-8");