feat: add GET /api/v2/templatebuilder/modules endpoint (#26117)

Implement `GET /api/v2/templatebuilder/modules`, which returns the
filtered list of modules available for a given base template. Reads from
the bundled catalog via `LoadModules()` and applies OS-compatibility
filtering based on the `base` query param.

Computed variables (e.g. `agent_id`) are excluded from the API response
at the `ToSDK()` conversion boundary since they are wired automatically
by the builder. The `Computed` field is removed from the SDK type. Adds
`CompatibleWithOS()` to `ModuleManifest` for OS filtering.

Returns 400 for unknown base IDs and 404 when the template builder is
disabled.

Depends on #26116

> [!NOTE]
> This PR was authored by Coder Agents on behalf of @jeremyruppel.
This commit is contained in:
Jeremy Ruppel
2026-06-12 17:53:48 -04:00
committed by GitHub
parent 776fbfa748
commit 9a6e348f5d
11 changed files with 664 additions and 17 deletions
+22 -1
View File
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"net/http"
"net/url"
)
// TemplateBuilderVariableType enumerates the variable types
@@ -23,7 +24,6 @@ type TemplateBuilderModuleVariable struct {
Default json.RawMessage `json:"default,omitempty"`
Required bool `json:"required"`
Sensitive bool `json:"sensitive"`
Computed bool `json:"computed"`
}
// TemplateBuilderModule is the API response type returned by
@@ -41,6 +41,7 @@ type TemplateBuilderModule struct {
Variables []TemplateBuilderModuleVariable `json:"variables"`
}
// TemplateBuilderModulesResponse is the response body for listing template builder modules.
type TemplateBuilderModulesResponse struct {
Modules []TemplateBuilderModule `json:"modules"`
}
@@ -74,3 +75,23 @@ func (c *Client) TemplateBuilderBases(ctx context.Context) (TemplateBuilderBases
var resp TemplateBuilderBasesResponse
return resp, json.NewDecoder(res.Body).Decode(&resp)
}
// TemplateBuilderModules returns the list of modules available for a given
// base template. If base is empty, all modules are returned.
func (c *Client) TemplateBuilderModules(ctx context.Context, base string) (TemplateBuilderModulesResponse, error) {
path := "/api/v2/templatebuilder/modules"
if base != "" {
q := url.Values{"base": {base}}
path += "?" + q.Encode()
}
res, err := c.Request(ctx, http.MethodGet, path, nil)
if err != nil {
return TemplateBuilderModulesResponse{}, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return TemplateBuilderModulesResponse{}, ReadBodyAsError(res)
}
var resp TemplateBuilderModulesResponse
return resp, json.NewDecoder(res.Body).Decode(&resp)
}