Skip to content

feat(app): add settings support for app registration - #216

Merged
jpage-godaddy merged 26 commits into
godaddy:mainfrom
nmolham-godaddy:devex-1021/settings-support-for-app-registration
Aug 20, 2026
Merged

feat(app): add settings support for app registration#216
jpage-godaddy merged 26 commits into
godaddy:mainfrom
nmolham-godaddy:devex-1021/settings-support-for-app-registration

Conversation

@nmolham-godaddy

@nmolham-godaddy nmolham-godaddy commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add [[settings]] support to godaddy.toml and wire it through gddy platform app add settings / gddy platform app release — closes the gap where app-registry-api's createRelease.settings capability had no CLI support at all (config, add command, and release payload all silently dropped it).
  • New gddy platform app add settings command writes placement metadata only (group/slug/entryPath/order/capabilities/icon) — matches the flag shape of add action/add subscription/add extension.
  • Full typed settings-form-v1 presentation model (text/textarea/number/boolean/select/multi-select/list-group, recursive nesting) authored inline in godaddy.toml — no JSON file, no opaque passthrough. presentation is hand-added after add settings; release rejects a settings entry with no presentation instead of Config::validate(), so a placement-only entry still works fine for every other command.
  • Structural client-side validation only (slug/entryPath shape, capability/icon-library enum membership, entry-path overlap, field-key uniqueness/pattern, non-empty options) — bounds/default-consistency/nesting-depth stay server-validated, consistent with how the rest of Config::validate() already treats every other section.
  • New rust/scripts/build-and-verify.sh — check/clippy/fmt/module-size, then build and run gddy (args forwarded, defaults to --help).
  • New docs/application-settings.md — end-user guide: workflow, full field-type reference, worked nested list-group example, gotchas (no release inheritance, no auto-backfill to already-enabled stores).

Affects: https://github.com/gdcorp-commerce/app-registry-api/pull/131

Changes

  • rust/src/config/settings_form.rs (new) — SettingsFormV1Presentation/Section/Field enum/ListGroupItem/ChoiceOption/SelectValue, structural validation.
  • rust/src/config/settings.rs (new) — SettingConfig/SettingIcon, slug/entryPath/capability/icon-library validation, entry-path-overlap check.
  • rust/src/config/mod.rssettings: Vec<SettingConfig> field, wired into Config::validate().
  • rust/src/application/commands/release.rssetting_entry/build_settings map config to ApplicationSettingCreateInput, enforce presentation required here (not in Config::validate()).
  • rust/src/application/commands/add.rsadd settings command.
  • rust/src/application/commands/schemas.rsConfigSetting output schema.
  • rust/src/application/commands/init.rs — add missing settings: vec![] to a Config literal.
  • rust/scripts/build-and-verify.sh (new).
  • docs/application-settings.md (new).

QA

  • cargo check
  • cargo clippy -- -D warnings
  • cargo test (19 new tests: config validation, settings_form structural checks + TOML round-trip, release::setting_entry mapping incl. missing-presentation error path)
  • cargo fmt --check
  • ./rust/scripts/check-module-size.sh
  • Manual: built binary, ran add settings against a scratch godaddy.toml, hand-added [settings.presentation] (incl. nested list-group with multiple options), confirmed round-trip through read_config/validate/write_config preserves defaultValue and every nested field; confirmed --icon-name/--icon-library pairing and entry-path-overlap rejections fire before any write.

After merge

Copilot AI lite review requested due to automatic review settings August 18, 2026 04:36
@nmolham-godaddy nmolham-godaddy changed the title Devex 1021/settings support for app registration feat(app): settings support for app registration Aug 18, 2026
@nmolham-godaddy nmolham-godaddy changed the title feat(app): settings support for app registration feat(app): add settings support for app registration Aug 18, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds first-class support for application “settings” registrations in the CLI by extending godaddy.toml ([[settings]] placement + typed settings-form-v1 presentation), wiring settings into gddy platform app add settings and the release payload, and documenting the workflow.

Changes:

  • Introduces new config models + structural validation for [[settings]] placement metadata and settings-form-v1 presentation.
  • Adds gddy platform app add settings and includes settings in gddy platform app release payload mapping (with presentation required at release-time).
  • Adds a build/verify helper script and end-user documentation for authoring settings.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
rust/src/config/settings.rs Defines SettingConfig/SettingIcon and validates placement metadata (slug, entryPath, capabilities, icon library, overlap).
rust/src/config/settings_form.rs Defines typed settings-form-v1 presentation model plus structural validation (keys/options/uniqueness).
rust/src/config/mod.rs Wires settings: Vec<SettingConfig> into Config + Config::validate(), and updates tests/config literals.
rust/src/application/commands/release.rs Maps config settings into the createRelease.settings payload and enforces presentation required at release-time.
rust/src/application/commands/add.rs Adds gddy platform app add settings to write placement metadata into godaddy.toml.
rust/src/application/commands/schemas.rs Adds ConfigSetting output schema for the new add settings command.
rust/src/application/commands/init.rs Ensures generated config includes settings: vec![].
rust/scripts/build-and-verify.sh Adds a helper script to run local verification + a debug build smoke run.
docs/application-settings.md Documents the settings workflow and the settings-form-v1 TOML authoring shape.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread rust/src/application/commands/release.rs Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Suppressed comments (3)

rust/src/config/settings_form.rs:265

  • Nested list-group fields are only validated individually, so sibling fields may reuse the same key or reuse the reserved idField. Both cases produce ambiguous object properties and contradict the documented guarantees that field keys are unique and idField cannot be editable. Track keys within each item and reject both collisions.
            for (k, inner) in item.fields.iter().enumerate() {
                validate_field(inner, errors, &format!("{path}.item.fields[{k}]"));
            }

rust/scripts/build-and-verify.sh:20

  • This verification script omits the repository's required cargo test check, so it can report success despite test failures. Add the test suite to the verification sequence.
step "cargo clippy -- -D warnings"
cargo clippy -- -D warnings

rust/src/application/client.rs:191

  • The release response now includes settings, but ApplicationRelease still omits that field. Consequently release --help and release --schema do not advertise the newly emitted JSON member, contrary to the synchronization requirement in rust/src/output_schema.rs:15-17. Add settings as an optional []object field to the release output schema.
            "query": "mutation CreateRelease($input: MutationCreateReleaseInput!) { createRelease(input: $input) { id version description createdAt uiExtensions { id name handle type source target } settings { id groupSlug appSettingSlug entryPath capabilities order title } } }",

Comment thread rust/src/application/commands/release.rs Outdated
@nmolham-godaddy
nmolham-godaddy marked this pull request as ready for review August 18, 2026 06:50
@smukherjee-godaddy

Copy link
Copy Markdown
Contributor

@nmolham-godaddy thanks for driving this end-to-end — I validated the implementation against the live App Registry settings schema, the #131 registration plan, and DEVEX-1021.

I found two blockers before this can merge:

  1. cargo clippy -- -D warnings currently fails on clippy::collapsible_match in rust/src/config/settings_form.rs (the select/multi-select options match arm).

  2. platform app release treats any manifest read/parse/validation failure as non-fatal and sends empty actions/subscriptions/uiExtensions/settings arrays. With hand-authored settings presentations, a TOML typo or validation error could silently create a release without settings. Please preserve the empty fallback only for a missing manifest; parse and validation errors should fail the release.

Follow-up: the docs say local validation enforces key uniqueness, but nested list-group fields are not checked for duplicate keys, idField collisions, or an invalid titleField target. The App Registry rejects these, so either add the checks or narrow the documentation claim.

The core settings mapping and targeted GraphQL test otherwise align with App Registry.

@wcole1-godaddy

Copy link
Copy Markdown
Contributor

The API mapping here looks right, but we should support both presentation authoring modes before merging: inline TOML and a referenced JSON file.

Suggested manifest shape:

[[settings]]
group = "tax-center"
slug = "manual-tax"
entryPath = "/settings/manual-tax"
presentationFile = "fixtures/manual-tax-registry-presentation.json"

The referenced JSON should contain the complete API presentation object (type, schemaVersion, and sections), which lets existing GPA presentation fixtures be reused directly. Inline TOML can remain the current shorthand, with the CLI injecting type = "form" and schemaVersion = "settings-form-v1".

Expected behavior:

  • presentation and presentationFile are mutually exclusive.
  • Either form is acceptable, but one is required at release time.
  • Relative file paths resolve from the directory containing the selected godaddy.toml, not the caller's working directory.
  • Missing, unreadable, malformed, or invalid JSON stops the release.
  • Both forms go through the same typed validation and produce identical createRelease.settings[].presentation payloads.
  • gddy platform app add settings should accept an optional --presentation-file <path>.
  • Config rewrites preserve the file reference rather than embedding its contents.

This is especially useful for the existing GPA examples, which already keep substantial registry presentations in JSON fixtures; requiring inline-only TOML would create a second source of truth.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It'd be better if this was embedded in a guide so that LLMs can discover these instructions without needing to do a web search. I think the whole gddy platform module probably needs a holistic guide with application settings included (or I guess multiple guides is also fine).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I agree, sounds like a good idea, I will do my best effort to implement it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

b298b7a what do you think? CC @wcole1-godaddy

label = "Canada"
value = "CA"
```
- Optional: `defaultValue` must match one option's `value`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks like the Markdown parser hit a snag starting on this line. You probably need to fix indentation or some other kind of white space.

@nmolham-godaddy nmolham-godaddy Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@jpage-godaddy jpage-godaddy Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I mean in the GitHub UI diff view. But if it renders fine, that's ok.

"Register the placement metadata for an application-settings \
capability in the godaddy.toml manifest in the current directory. \
This command only writes group/slug/entryPath/order/capabilities/icon \
— it cannot author the settings-form-v1 form itself. After running \

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is the meaning of "settings-form-v1" something that's clear to users?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

initially yes, but according to Wes's comment here, I should also add presentation authoring modes in this PR, so this description will change

error = %e,
path = %config_path.display(),
"failed to read config; releasing with empty actions, subscriptions, and uiExtensions"
"failed to read config; releasing with empty actions, subscriptions, uiExtensions, and settings"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I know this isn't new behavior, but if someone doesn't notice this warning, it could cause a lot of frustration, if they're releasing but it doesn't reflect their config. As a user, I'd prefer the release failed instead.

(non-blocking)

@nmolham-godaddy nmolham-godaddy Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed, fixed c4c0115 what do you think?

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated no new comments.

Suppressed comments (8)

rust/src/config/settings_form.rs:249

  • Because both discriminators are optional and only checked when present, a JSON file that omits type and/or schemaVersion is accepted and silently normalized by setting_entry. The documented presentationFile contract requires the complete API object, so missing discriminators should fail just like incorrect ones.
    if let Some(t) = &doc.r#type
        && t != "form"

rust/src/platform/guides/platform-overview.md:26

  • config validate does not check every rule the API enforces: the settings guide explicitly leaves bounds/default consistency and nesting depth to release-time server validation. This overstatement can lead users to treat a successful local check as proof that release will succeed.
Run `gddy platform app config validate` any time to check the manifest against every rule the API would otherwise enforce (required fields, URL/UUID/semver shapes, settings placement rules) without a network call — it reports every violation found, not just the first.

rust/src/config/settings_form.rs:207

  • An empty sections array, or a section with an empty fields array, currently passes local validation because these loops simply do nothing. Both user guides define the form as one or more sections with one or more fields, so config validate can report success for a presentation that will be rejected at release time. Validate both cardinalities here.

This issue also appears on line 248 of the same file.

    let mut seen_section_keys = HashSet::new();
    let mut seen_top_level_field_keys = HashSet::new();

    for (i, section) in presentation.sections.iter().enumerate() {
        let section_path = format!("{path}.sections[{i}]");

rust/src/config/settings_form.rs:296

  • Nested list-group fields are recursively shape-checked but never uniqueness-checked. Two item fields with the same key therefore pass config validate, despite the documented rule that field keys are unique, and would map to the same property in each saved item. Track keys within each item just as top-level field keys are tracked.
            for (k, inner) in item.fields.iter().enumerate() {
                validate_field(inner, errors, &format!("{path}.item.fields[{k}]"));
            }

rust/src/application/client.rs:191

  • The real GraphQL response cannot contain the setting fields omitted from this selection (presentation, description, icon fields, and metadata), even though the new smoke test asserts that release echoes them. That test passes only because the mock copies the entire request input without honoring the selection set. Select the fields the command promises to return, or change the smoke contract to test only selected fields.
            "query": "mutation CreateRelease($input: MutationCreateReleaseInput!) { createRelease(input: $input) { id version description createdAt uiExtensions { id name handle type source target } settings { id groupSlug appSettingSlug entryPath capabilities order title } } }",

rust/src/platform/guides/platform-overview.md:24

  • This says the form must be hand-authored, but add settings now supports --presentation-file. Mention both supported workflows so the lifecycle overview does not contradict the dedicated settings guide.

This issue also appears on line 26 of the same file.

- `add settings --group <group> --slug <slug> --entry-path <path> ...` — placement metadata for a merchant-facing settings form. This only writes placement fields (group/slug/entryPath/order/capabilities/icon); the form itself (`[settings.presentation]`) has to be hand-authored in `godaddy.toml` afterward. See the `platform-settings` guide (`gddy guide platform-settings`) for the full presentation shape.

rust/src/platform/guides/platform-overview.md:34

  • A setting backed by presentationFile is valid without a [settings.presentation] block, so this release description incorrectly says that such an entry fails. State that release fails only when both presentation sources are absent.
Resends every action, subscription, UI extension, and settings entry currently in `godaddy.toml` as one versioned release — omitting an entry from the manifest doesn't archive it globally, but a store enabled against a *newer* release won't have it. A settings entry with no `[settings.presentation]` block fails the release with a `VALIDATION_ERROR`; a manifest that fails to parse or validate fails the release outright (only a genuinely missing manifest falls back to an empty release). Version must be semver.

rust/src/application/commands/add.rs:187

  • The long help omits the newly supported --presentation-file path and says this command writes only placement fields, although it also writes presentationFile. This directs users exclusively to hand-edit TOML despite the available flag.
            This command only writes group/slug/entryPath/order/capabilities/icon \
            — it cannot author the settings-form-v1 form itself. After running \
            it, hand-add a [settings.presentation] block (sections and fields) \
            to the written entry; `gddy platform app release` rejects a \
            settings entry with no presentation.",

Comment thread rust/src/application/commands/config.rs Outdated
Comment thread rust/src/application/commands/release.rs Outdated
Comment thread rust/src/application/commands/release.rs Outdated
Comment thread rust/src/application/commands/release.rs Outdated
Comment thread rust/src/application/commands/release.rs Outdated
Comment thread rust/src/application/commands/release.rs Outdated

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Well done on the guide

@jpage-godaddy jpage-godaddy left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Short of help text tweaks, the rest looks good to me.

@nmolham-godaddy

Copy link
Copy Markdown
Contributor Author

@jpage-godaddy all requested changes implemented

@jpage-godaddy
jpage-godaddy merged commit 74934c2 into godaddy:main Aug 20, 2026
5 checks passed
This was referenced Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants