Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
b3cd713
test(05.1-01): migrate test6/7/13 to type:boolean schema (RED)
derks May 30, 2026
db2c417
feat(05.1-01): unify variables+features into one typed resolver
derks May 30, 2026
e9677e2
docs(05.1-01): changelog entry for #782 type:boolean fix
derks May 30, 2026
fcbfe4f
test(05.1-02): migrate select fixtures to type:choice + RED tests
derks May 30, 2026
b0d0ae7
feat(05.1-02): add type:choice + object-form bool prompt resolution
derks May 30, 2026
0a1f030
docs(05.1-02): changelog for type:choice + object-form bool prompt
derks May 30, 2026
5c50802
test(05.1-03): migrate requires/nesting fixtures + RED tests
derks May 30, 2026
8d7855e
feat(05.1-03): extend.when list/regex, nesting, requires:; drop bridge
derks May 30, 2026
f01e540
refactor(05.1-04): migrate generate-features demo to typed schema
derks May 30, 2026
c230103
docs(changelog): note generate-features demo schema migration
derks May 30, 2026
6d52b2e
test(05.1-05): cover choice picker label->value mapping
derks May 30, 2026
e9bd529
docs(05.1-05): finalize ext.generate #782 changelog entries
derks May 30, 2026
a7597c5
fix(05.1): default bool string-prompt label to Enable <name>
derks May 30, 2026
d60766e
docs(05.1): fix requires: syntax + document bool prompt forms
derks May 30, 2026
1f0987e
fix(ext.generate): reject requires-gated var with no default
derks Jun 24, 2026
e594f90
fix(ext.generate): detect cyclic variable dependencies
derks Jun 24, 2026
7700043
test(ext.generate): strengthen silent-bool test to catch stringify
derks Jun 24, 2026
533ca5b
docs(demo): fix MD028 blockquote and drop unused #779 ref
derks Jun 24, 2026
fb142bf
test(ext.generate): cover gated-no-default and cycle guards
derks Jun 24, 2026
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
50 changes: 50 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ Bugs:
with a `name`-match guard, so transitive `ModuleNotFoundError`s
raised inside the user's template module propagate normally
instead of being silently swallowed as "module not found"
- `[ext.generate]` `type: boolean` template variables now emit a real
Python bool at the top level of the render context (`data[name]`),
so `{% if feature_x %}` works in jinja2/mustache; the boolean prompt
uses a vars-style `[(Y)es/(N)o] [default]:` format and all variables
prompt in a single declaration-order pass — resolves #782 (the
former `features:` namespace and pre-pass are removed)
Comment on lines +160 to +165

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Consolidate to a single-line CHANGELOG entry.

CHANGELOG entries must be one line per the coding guidelines. This entry spans 6 lines. Condense the description or move detail to issue/PR discussions.

As per coding guidelines: "Each CHANGELOG.md entry must be one line, prefixed with [area]".

Example consolidation
-- `[ext.generate]` `type: boolean` template variables now emit a real
-  Python bool at the top level of the render context (`data[name]`),
-  so `{% if feature_x %}` works in jinja2/mustache; the boolean prompt
-  uses a vars-style `[(Y)es/(N)o] [default]:` format and all variables
-  prompt in a single declaration-order pass — resolves `#782` (the
-  former `features:` namespace and pre-pass are removed)
+- `[ext.generate]` `type: boolean` variables emit real Python bools at top level for direct Jinja2/mustache conditionals; unified prompt pass — resolves `#782`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- `[ext.generate]` `type: boolean` template variables now emit a real
Python bool at the top level of the render context (`data[name]`),
so `{% if feature_x %}` works in jinja2/mustache; the boolean prompt
uses a vars-style `[(Y)es/(N)o] [default]:` format and all variables
prompt in a single declaration-order pass — resolves #782 (the
former `features:` namespace and pre-pass are removed)
- `[ext.generate]` `type: boolean` variables emit real Python bools at top level for direct Jinja2/mustache conditionals; unified prompt pass — resolves `#782`
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` around lines 160 - 165, The CHANGELOG entry for [ext.generate]
spans multiple lines; collapse it into a single-line entry prefixed with
[ext.generate] that briefly states the change (e.g. "type: boolean template
variables now render as Python bools so jinja2/mustache conditionals work;
boolean prompt format and single-pass prompting; resolves `#782`") and move the
detailed explanation about `data[name]`, `{% if feature_x %}`, the `[(Y)es/(N)o]
[default]:` prompt format, and the removal of the former `features:`
namespace/pre-pass into the associated PR/issue description.


Features:

Expand All @@ -181,9 +187,53 @@ Features:
variables). `prompt_mode` defaults to `boolean` (legacy behavior,
byte-identical when key absent).
- [Issue #779](https://github.com/datafolklabs/cement/issues/779)
- `[ext.generate]` Add `type: choice` template variables — a numbered
`cement.utils.shell.Prompt` picker that emits the chosen option string
at the top level of the render context. `options:` accepts a scalar
list or per-option `{value, prompt}` objects; per-option effects live
in `extend:` rules keyed by `when: <value>`. Misconfig (empty options,
option missing `value`, default not in options, duplicate labels) is
fail-fast `ValueError`.
Comment on lines +190 to +196

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Consolidate to a single-line CHANGELOG entry.

This feature entry spans 7 lines. Per coding guidelines, each CHANGELOG entry must be one line.

As per coding guidelines: "Each CHANGELOG.md entry must be one line, prefixed with [area]".

Example consolidation
-- `[ext.generate]` Add `type: choice` template variables — a numbered
-  `cement.utils.shell.Prompt` picker that emits the chosen option string
-  at the top level of the render context. `options:` accepts a scalar
-  list or per-option `{value, prompt}` objects; per-option effects live
-  in `extend:` rules keyed by `when: <value>`. Misconfig (empty options,
-  option missing `value`, default not in options, duplicate labels) is
-  fail-fast `ValueError`.
+- `[ext.generate]` Add `type: choice` variables with numbered picker; emits string at top level; `extend:` rules per option; fail-fast validation
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- `[ext.generate]` Add `type: choice` template variables — a numbered
`cement.utils.shell.Prompt` picker that emits the chosen option string
at the top level of the render context. `options:` accepts a scalar
list or per-option `{value, prompt}` objects; per-option effects live
in `extend:` rules keyed by `when: <value>`. Misconfig (empty options,
option missing `value`, default not in options, duplicate labels) is
fail-fast `ValueError`.
- `[ext.generate]` Add `type: choice` variables with numbered picker; emits string at top level; `extend:` rules per option; fail-fast validation
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` around lines 190 - 196, The CHANGELOG entry for [ext.generate]
describing the `type: choice` template variables spans multiple lines; collapse
it into a single-line entry prefixed with `[ext.generate]` that summarizes the
feature (mentioning `type: choice`, `cement.utils.shell.Prompt`, and key
behaviors like `options:` format and fail-fast validation) so it follows the
one-line-per-entry guideline.

- `[ext.generate]` `type: boolean` `prompt:` is now polymorphic —
in addition to the framework-owned string form and the silent
`prompt: false` form, an object form `{text, accept, reject}` lets the
template author own the full prompt text and supply case-insensitive
`accept:`/`reject:` token lists that map input to a real bool. Input
matching neither asserts and aborts (`Invalid Response`), mirroring
`validate:`. A bool-like `accept:`/`reject:` token that YAML 1.1
coerced to a Python bool raises `ValueError` telling the author to
quote it.
Comment on lines +197 to +205

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Consolidate to a single-line CHANGELOG entry.

This feature entry spans 9 lines. Per coding guidelines, each CHANGELOG entry must be one line.

As per coding guidelines: "Each CHANGELOG.md entry must be one line, prefixed with [area]".

Example consolidation
-- `[ext.generate]` `type: boolean` `prompt:` is now polymorphic —
-  in addition to the framework-owned string form and the silent
-  `prompt: false` form, an object form `{text, accept, reject}` lets the
-  template author own the full prompt text and supply case-insensitive
-  `accept:`/`reject:` token lists that map input to a real bool. Input
-  matching neither asserts and aborts (`Invalid Response`), mirroring
-  `validate:`. A bool-like `accept:`/`reject:` token that YAML 1.1
-  coerced to a Python bool raises `ValueError` telling the author to
-  quote it.
+- `[ext.generate]` `type: boolean` `prompt:` supports object form `{text, accept, reject}` for custom tokens; YAML 1.1 bool-coercion guard
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- `[ext.generate]` `type: boolean` `prompt:` is now polymorphic —
in addition to the framework-owned string form and the silent
`prompt: false` form, an object form `{text, accept, reject}` lets the
template author own the full prompt text and supply case-insensitive
`accept:`/`reject:` token lists that map input to a real bool. Input
matching neither asserts and aborts (`Invalid Response`), mirroring
`validate:`. A bool-like `accept:`/`reject:` token that YAML 1.1
coerced to a Python bool raises `ValueError` telling the author to
quote it.
- `[ext.generate]` `type: boolean` `prompt:` supports object form `{text, accept, reject}` for custom tokens; YAML 1.1 bool-coercion guard
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` around lines 197 - 205, Consolidate the multi-line CHANGELOG
entry for [ext.generate] into a single line: rewrite the paragraph as one line
starting with [ext.generate] and briefly state that `type: boolean` `prompt:` is
now polymorphic — supports framework string, `prompt: false`, or an object form
`{text, accept, reject}` where case-insensitive `accept`/`reject` tokens map
input to a bool (unmatched input errors as `Invalid Response` mirroring
`validate:`) and YAML 1.1 bool-like `accept`/`reject` tokens raise `ValueError`
instructing authors to quote them; ensure no line breaks so the entire entry is
one line.

- `[ext.generate]` `extend.when` now composes three match forms — a
scalar value (equality), an in-list membership (`when: [a, b]`), and a
string-type regex (`re.match`, string variables only) — and multiple
matching rules all fire, accumulating their `variables`/`exclude`/
`ignore`. `extend.variables` are nested and prompted depth-first in
place only when their parent rule fires. A new top-level `requires:`
key gates a variable using the same match vocabulary (`[name]` →
truthy, `{name: value}` → equality, `{name: [v1, v2]}` → in-list),
AND-ed across keys and resolved order-independently via lazy
recursion. A requires-gated-out variable is set to its `default` (so
templates never `KeyError`) and its `extend` rules do not fire. The
unified schema also addresses the PR #780 review feedback: features
prompt after vars in declaration order, with custom per-feature
prompt text and vars-style input.
- [Issue #782](https://github.com/datafolklabs/cement/issues/782)
- [PR #780](https://github.com/datafolklabs/cement/pull/780)
Comment on lines +206 to +221

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Consolidate to a single-line CHANGELOG entry.

This feature entry spans 16 lines. Per coding guidelines, each CHANGELOG entry must be one line.

As per coding guidelines: "Each CHANGELOG.md entry must be one line, prefixed with [area]".

Example consolidation
-- `[ext.generate]` `extend.when` now composes three match forms — a
-  scalar value (equality), an in-list membership (`when: [a, b]`), and a
-  string-type regex (`re.match`, string variables only) — and multiple
-  matching rules all fire, accumulating their `variables`/`exclude`/
-  `ignore`. `extend.variables` are nested and prompted depth-first in
-  place only when their parent rule fires. A new top-level `requires:`
-  key gates a variable using the same match vocabulary (`[name]` →
-  truthy, `{name: value}` → equality, `{name: [v1, v2]}` → in-list),
-  AND-ed across keys and resolved order-independently via lazy
-  recursion. A requires-gated-out variable is set to its `default` (so
-  templates never `KeyError`) and its `extend` rules do not fire. The
-  unified schema also addresses the PR `#780` review feedback: features
-  prompt after vars in declaration order, with custom per-feature
-  prompt text and vars-style input.
-  - [Issue `#782`](https://github.com/datafolklabs/cement/issues/782)
-  - [PR `#780`](https://github.com/datafolklabs/cement/pull/780)
+- `[ext.generate]` `extend.when` supports scalar/list/regex matching; multiple rules compose; new `requires:` gates variables with default fallback — `#782`, PR `#780`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- `[ext.generate]` `extend.when` now composes three match forms — a
scalar value (equality), an in-list membership (`when: [a, b]`), and a
string-type regex (`re.match`, string variables only) — and multiple
matching rules all fire, accumulating their `variables`/`exclude`/
`ignore`. `extend.variables` are nested and prompted depth-first in
place only when their parent rule fires. A new top-level `requires:`
key gates a variable using the same match vocabulary (`[name]`
truthy, `{name: value}` → equality, `{name: [v1, v2]}` → in-list),
AND-ed across keys and resolved order-independently via lazy
recursion. A requires-gated-out variable is set to its `default` (so
templates never `KeyError`) and its `extend` rules do not fire. The
unified schema also addresses the PR #780 review feedback: features
prompt after vars in declaration order, with custom per-feature
prompt text and vars-style input.
- [Issue #782](https://github.com/datafolklabs/cement/issues/782)
- [PR #780](https://github.com/datafolklabs/cement/pull/780)
- `[ext.generate]` `extend.when` supports scalar/list/regex matching; multiple rules compose; new `requires:` gates variables with default fallback — `#782`, PR `#780`
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` around lines 206 - 221, The changelog entry for the
`[ext.generate]` feature is currently multi-line; collapse it into a single-line
entry starting with the `[ext.generate]` prefix that summarizes the change
(mention compose three match forms, requires gating, and PR/Issue references)
and keep the links `(Issue `#782`, PR `#780`)` inline; ensure the line is one
continuous line (no line breaks) and follows the "Each CHANGELOG.md entry must
be one line, prefixed with [area]" rule so the existing multi-line block is
replaced with that single consolidated line.


Refactoring:

- `[ext.generate]` Remove the unreleased `features:` schema
(`prompt_mode`, `enabled:`/`disabled:` blocks, select `options:`
effects) wholesale — everything it expressed is now a `type:
boolean`/`type: choice` variable carrying `extend:`/`requires:`. The
legacy compatibility bridge is deleted; `features:` is no longer read
by the engine (#782).
Comment on lines +225 to +230

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Consolidate to a single-line CHANGELOG entry.

This refactoring entry spans 6 lines. Per coding guidelines, each CHANGELOG entry must be one line.

As per coding guidelines: "Each CHANGELOG.md entry must be one line, prefixed with [area]".

Example consolidation
-- `[ext.generate]` Remove the unreleased `features:` schema
-  (`prompt_mode`, `enabled:`/`disabled:` blocks, select `options:`
-  effects) wholesale — everything it expressed is now a `type:
-  boolean`/`type: choice` variable carrying `extend:`/`requires:`. The
-  legacy compatibility bridge is deleted; `features:` is no longer read
-  by the engine (`#782`).
+- `[ext.generate]` Remove unreleased `features:` schema; replaced by typed variables with `extend:`/`requires:` — `#782`
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` around lines 225 - 230, The CHANGELOG entry for
`[ext.generate]` spans multiple lines; collapse it to a single-line entry
prefixed with `[ext.generate]` that summarizes the change succinctly (mention
removal of the unreleased `features:` schema and deletion of the legacy
compatibility bridge, and reference issue `#782` if needed) so the entire note
fits on one line in CHANGELOG.md.


- `[dev]` Migrate the `demo/generate-features/` webapp template to the
unified `type:`/`extend:`/`requires:` schema (off the removed
`features:` schema) and demonstrate the #782 fix — `{% if docker %}`
and `{% if web_framework == ... %}` now render against the top-level
bool/choice exposure
Comment on lines +232 to +236

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Consolidate to a single-line CHANGELOG entry.

This refactoring entry spans 5 lines. Per coding guidelines, each CHANGELOG entry must be one line.

As per coding guidelines: "Each CHANGELOG.md entry must be one line, prefixed with [area]".

Example consolidation
-- `[dev]` Migrate the `demo/generate-features/` webapp template to the
-  unified `type:`/`extend:`/`requires:` schema (off the removed
-  `features:` schema) and demonstrate the `#782` fix — `{% if docker %}`
-  and `{% if web_framework == ... %}` now render against the top-level
-  bool/choice exposure
+- `[dev]` Migrate `demo/generate-features/` to unified typed variable schema; demonstrates `#782` top-level bool/choice exposure
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- `[dev]` Migrate the `demo/generate-features/` webapp template to the
unified `type:`/`extend:`/`requires:` schema (off the removed
`features:` schema) and demonstrate the #782 fix — `{% if docker %}`
and `{% if web_framework == ... %}` now render against the top-level
bool/choice exposure
- `[dev]` Migrate `demo/generate-features/` to unified typed variable schema; demonstrates `#782` top-level bool/choice exposure
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` around lines 232 - 236, Consolidate the multi-line CHANGELOG
entry into a single-line entry prefixed with [dev]; replace the 5-line block
mentioning `demo/generate-features/`, the migration from `features:` to
`type:`/`extend:`/`requires:`, and the `#782` rendering note into one concise line
(e.g. "[dev] Migrate demo/generate-features/ template to unified
type/extend/requires schema; demonstrate `#782` fix where `{% if docker %}` and
`{% if web_framework == ... %}` now render against top-level bool/choice
exposure").

- `[ext.smtp]` PEP 8 naming, idiomatic string methods, and cleaner type validation
- `[ext.smtp]` Refactor `_make_message` into focused private methods
- `[ext.smtp]` Simplify X-header normalization and preserve original casing
Expand Down
572 changes: 356 additions & 216 deletions cement/ext/ext_generate.py

Large diffs are not rendered by default.

Loading
Loading