diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 006d15838e..4fc7a0c1bc 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -23884,6 +23884,9 @@ const docTemplate = `{ "os": { "type": "string" }, + "prerequisites": { + "type": "string" + }, "variables": { "type": "array", "items": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 5483aed895..994cb2402a 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -21915,6 +21915,9 @@ "os": { "type": "string" }, + "prerequisites": { + "type": "string" + }, "variables": { "type": "array", "items": { diff --git a/coderd/templatebuilder/bases.go b/coderd/templatebuilder/bases.go index 5b5d79a60f..2d6a2406eb 100644 --- a/coderd/templatebuilder/bases.go +++ b/coderd/templatebuilder/bases.go @@ -52,9 +52,11 @@ type BaseDefaultContext struct { // parsedBase holds the result of loading and pre-parsing a single base // template directory. type parsedBase struct { - Manifest BaseManifest - Templates map[string]*template.Template - FS fs.FS + Manifest BaseManifest + Templates map[string]*template.Template + FS fs.FS + Readme string // full README.md content (including frontmatter) + Prerequisites string // content between prerequisite comment markers } var loadBases = sync.OnceValues(func() (map[string]*parsedBase, error) { @@ -114,10 +116,18 @@ func parseBasesFromFS(fsys fs.FS) (map[string]*parsedBase, error) { return nil, xerrors.Errorf("parse templates for base %q: %w", manifest.ID, err) } + readmeData, err := fs.ReadFile(baseFS, "README.md") + if err != nil { + return nil, xerrors.Errorf("read README.md for base %q: %w", manifest.ID, err) + } + readme := string(readmeData) + bases[manifest.ID] = &parsedBase{ - Manifest: manifest, - Templates: templates, - FS: baseFS, + Manifest: manifest, + Templates: templates, + FS: baseFS, + Readme: readme, + Prerequisites: ExtractPrerequisites(readme), } } @@ -233,3 +243,24 @@ func BaseTemplateFS(exampleID string) (fs.FS, error) { } return base.FS, nil } + +// BaseReadme returns the full README.md content for a base template. +// Returns an empty string if the base is unknown or has no README. +func BaseReadme(exampleID string) string { + bases, err := loadBases() + if err != nil || bases[exampleID] == nil { + return "" + } + return bases[exampleID].Readme +} + +// BasePrerequisites returns the prerequisites section extracted from +// the base template README. Returns an empty string if the base is +// unknown or has no prerequisites markers. +func BasePrerequisites(exampleID string) string { + bases, err := loadBases() + if err != nil || bases[exampleID] == nil { + return "" + } + return bases[exampleID].Prerequisites +} diff --git a/coderd/templatebuilder/bases/aws-linux/README.md b/coderd/templatebuilder/bases/aws-linux/README.md new file mode 100644 index 0000000000..3587221889 --- /dev/null +++ b/coderd/templatebuilder/bases/aws-linux/README.md @@ -0,0 +1,98 @@ +--- +display_name: AWS EC2 (Linux) +description: Provision AWS EC2 VMs as Coder workspaces +icon: ../../../site/static/icon/aws.svg +maintainer_github: coder +verified: true +tags: [vm, linux, aws, persistent-vm] +--- + +# Remote Development on AWS EC2 VMs (Linux) + +Provision AWS EC2 VMs as [Coder workspaces](https://coder.com/docs/user-guides/workspace-management) with this example template. + + + +## Prerequisites + +### Authentication + +By default, this template authenticates to AWS using the provider's default [authentication methods](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration). + +The simplest way (without making changes to the template) is via environment variables (e.g. `AWS_ACCESS_KEY_ID`) or a [credentials file](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html#cli-configure-files-format). If you are running Coder on a VM, this file must be in `/home/coder/aws/credentials`. + +To use another [authentication method](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication), edit the template. + +## Required permissions / policy + +The following sample policy allows Coder to create EC2 instances and modify +instances provisioned by Coder: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "VisualEditor0", + "Effect": "Allow", + "Action": [ + "ec2:GetDefaultCreditSpecification", + "ec2:DescribeIamInstanceProfileAssociations", + "ec2:DescribeTags", + "ec2:DescribeInstances", + "ec2:DescribeInstanceTypes", + "ec2:DescribeInstanceStatus", + "ec2:CreateTags", + "ec2:RunInstances", + "ec2:DescribeInstanceCreditSpecifications", + "ec2:DescribeImages", + "ec2:ModifyDefaultCreditSpecification", + "ec2:DescribeVolumes" + ], + "Resource": "*" + }, + { + "Sid": "CoderResources", + "Effect": "Allow", + "Action": [ + "ec2:DescribeInstanceAttribute", + "ec2:UnmonitorInstances", + "ec2:TerminateInstances", + "ec2:StartInstances", + "ec2:StopInstances", + "ec2:DeleteTags", + "ec2:MonitorInstances", + "ec2:CreateTags", + "ec2:RunInstances", + "ec2:ModifyInstanceAttribute", + "ec2:ModifyInstanceCreditSpecification" + ], + "Resource": "arn:aws:ec2:*:*:instance/*", + "Condition": { + "StringEquals": { + "aws:ResourceTag/Coder_Provisioned": "true" + } + } + } + ] +} +``` + + + +## Architecture + +This template provisions the following resources: + +- AWS Instance + +Coder uses `aws_ec2_instance_state` to start and stop the VM. This example template is fully persistent, meaning the full filesystem is preserved when the workspace restarts. See this [community example](https://github.com/bpmct/coder-templates/tree/main/aws-linux-ephemeral) of an ephemeral AWS instance. + +> **Note** +> This template is designed to be a starting point! Edit the Terraform to extend the template to support your use case. + +## code-server + +`code-server` is installed via the `startup_script` argument in the `coder_agent` +resource block. The `coder_app` resource is defined to access `code-server` through +the dashboard UI over `localhost:13337`. diff --git a/coderd/templatebuilder/bases/docker/README.md b/coderd/templatebuilder/bases/docker/README.md new file mode 100644 index 0000000000..6398547ef5 --- /dev/null +++ b/coderd/templatebuilder/bases/docker/README.md @@ -0,0 +1,52 @@ +--- +display_name: Docker Containers +description: Provision Docker containers as Coder workspaces +icon: ../../../site/static/icon/docker.png +maintainer_github: coder +verified: true +tags: [docker, container] +--- + +# Remote Development on Docker Containers + +Provision Docker containers as [Coder workspaces](https://coder.com/docs/user-guides/workspace-management) with this example template. + + + + + +## Prerequisites + +### Infrastructure + +The VM you run Coder on must have a running Docker socket and the `coder` user must be added to the Docker group: + +```sh +# Add coder user to Docker group +sudo adduser coder docker + +# Restart Coder server +sudo systemctl restart coder + +# Test Docker +sudo -u coder docker ps +``` + + + +## Architecture + +This template provisions the following resources: + +- Docker image (built by Docker socket and kept locally) +- Docker container pod (ephemeral) +- Docker volume (persistent on `/home/coder`) + +This means, when the workspace restarts, any tools or files outside of the home directory are not persisted. To pre-bake tools into the workspace (e.g. `python3`), modify the container image. Alternatively, individual developers can [personalize](https://coder.com/docs/user-guides/workspace-dotfiles) their workspaces with dotfiles. + +> **Note** +> This template is designed to be a starting point! Edit the Terraform to extend the template to support your use case. + +### Editing the image + +Edit the `Dockerfile` and run `coder templates push` to update workspaces. diff --git a/coderd/templatebuilder/bases/kubernetes/README.md b/coderd/templatebuilder/bases/kubernetes/README.md new file mode 100644 index 0000000000..26e7e07e38 --- /dev/null +++ b/coderd/templatebuilder/bases/kubernetes/README.md @@ -0,0 +1,42 @@ +--- +display_name: Kubernetes (Deployment) +description: Provision Kubernetes Deployments as Coder workspaces +icon: ../../../site/static/icon/k8s.png +maintainer_github: coder +verified: true +tags: [kubernetes, container] +--- + +# Remote Development on Kubernetes Pods + +Provision Kubernetes Pods as [Coder workspaces](https://coder.com/docs/user-guides/workspace-management) with this example template. + + + + + +## Prerequisites + +### Infrastructure + +**Cluster**: This template requires an existing Kubernetes cluster + +**Container Image**: This template uses the [codercom/enterprise-base:ubuntu image](https://github.com/coder/enterprise-images/tree/main/images/base) with some dev tools preinstalled. To add additional tools, extend this image or build it yourself. + +### Authentication + +This template authenticates using a `~/.kube/config`, if present on the server, or via built-in authentication if the Coder provisioner is running on Kubernetes with an authorized ServiceAccount. To use another [authentication method](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs#authentication), edit the template. + + + +## Architecture + +This template provisions the following resources: + +- Kubernetes pod (ephemeral) +- Kubernetes persistent volume claim (persistent on `/home/coder`) + +This means, when the workspace restarts, any tools or files outside of the home directory are not persisted. To pre-bake tools into the workspace (e.g. `python3`), modify the container image. Alternatively, individual developers can [personalize](https://coder.com/docs/user-guides/workspace-dotfiles) their workspaces with dotfiles. + +> **Note** +> This template is designed to be a starting point! Edit the Terraform to extend the template to support your use case. diff --git a/coderd/templatebuilder/bases_internal_test.go b/coderd/templatebuilder/bases_internal_test.go index 786dc3a523..19187dbf2e 100644 --- a/coderd/templatebuilder/bases_internal_test.go +++ b/coderd/templatebuilder/bases_internal_test.go @@ -27,6 +27,9 @@ func TestParseBasesFromFS(t *testing.T) { "bases/docker/main.tf.tmpl": &fstest.MapFile{ Data: []byte(`image = "{{ .ContainerImage }}"`), }, + "bases/docker/README.md": &fstest.MapFile{ + Data: []byte("# Docker\n"), + }, } bases, err := parseBasesFromFS(fsys) @@ -52,12 +55,18 @@ func TestParseBasesFromFS(t *testing.T) { "bases/alpha/main.tf.tmpl": &fstest.MapFile{ Data: []byte(`resource "alpha" {}`), }, + "bases/alpha/README.md": &fstest.MapFile{ + Data: []byte("# Alpha\n"), + }, "bases/beta/base.json": &fstest.MapFile{ Data: []byte(`{"id": "beta", "os": "linux"}`), }, "bases/beta/main.tf.tmpl": &fstest.MapFile{ Data: []byte(`resource "beta" {}`), }, + "bases/beta/README.md": &fstest.MapFile{ + Data: []byte("# Beta\n"), + }, } bases, err := parseBasesFromFS(fsys) @@ -93,6 +102,9 @@ func TestParseBasesFromFS(t *testing.T) { "bases/mybase/cloud-init/config.yaml.tftpl": &fstest.MapFile{ Data: []byte(`${some_terraform_var}`), }, + "bases/mybase/README.md": &fstest.MapFile{ + Data: []byte("# My Base\n"), + }, } bases, err := parseBasesFromFS(fsys) @@ -105,6 +117,22 @@ func TestParseBasesFromFS(t *testing.T) { require.NotContains(t, b.Templates, "cloud-init/config.yaml.tftpl") }) + t.Run("RejectsMissingReadme", func(t *testing.T) { + t.Parallel() + + fsys := fstest.MapFS{ + "bases/bad/base.json": &fstest.MapFile{ + Data: []byte(`{"id": "bad", "os": "linux"}`), + }, + "bases/bad/main.tf.tmpl": &fstest.MapFile{ + Data: []byte(`resource {}`), + }, + } + + _, err := parseBasesFromFS(fsys) + require.ErrorContains(t, err, "read README.md for base") + }) + t.Run("RejectsDirWithoutManifest", func(t *testing.T) { t.Parallel() @@ -136,9 +164,15 @@ func TestParseBasesFromFS(t *testing.T) { "bases/a/base.json": &fstest.MapFile{ Data: []byte(`{"id": "dupe", "os": "linux"}`), }, + "bases/a/README.md": &fstest.MapFile{ + Data: []byte("# A\n"), + }, "bases/b/base.json": &fstest.MapFile{ Data: []byte(`{"id": "dupe", "os": "linux"}`), }, + "bases/b/README.md": &fstest.MapFile{ + Data: []byte("# B\n"), + }, } _, err := parseBasesFromFS(fsys) @@ -207,6 +241,9 @@ func TestParseBasesFromFS(t *testing.T) { "bases/nospec/base.json": &fstest.MapFile{ Data: []byte(`{"id": "nospec"}`), }, + "bases/nospec/README.md": &fstest.MapFile{ + Data: []byte("# No Spec\n"), + }, } bases, err := parseBasesFromFS(fsys) diff --git a/coderd/templatebuilder/bases_test.go b/coderd/templatebuilder/bases_test.go index 70ed705cd3..c54a0db0c8 100644 --- a/coderd/templatebuilder/bases_test.go +++ b/coderd/templatebuilder/bases_test.go @@ -101,3 +101,46 @@ func TestBaseTemplateFS(t *testing.T) { require.Contains(t, err.Error(), "unknown base template") }) } + +func TestBaseReadme(t *testing.T) { + t.Parallel() + + t.Run("KnownBasesHaveReadme", func(t *testing.T) { + t.Parallel() + for _, id := range templatebuilder.BaseTemplateIDs() { + readme := templatebuilder.BaseReadme(id) + require.NotEmpty(t, readme, "base %q should have a README", id) + } + }) + + t.Run("UnknownReturnsEmpty", func(t *testing.T) { + t.Parallel() + require.Empty(t, templatebuilder.BaseReadme("nonexistent")) + }) +} + +func TestBasePrerequisites(t *testing.T) { + t.Parallel() + + t.Run("KnownBasesHavePrerequisites", func(t *testing.T) { + t.Parallel() + for _, id := range templatebuilder.BaseTemplateIDs() { + prereqs := templatebuilder.BasePrerequisites(id) + require.NotEmpty(t, prereqs, "base %q should have prerequisites", id) + require.Contains(t, prereqs, "## Prerequisites", + "base %q prerequisites should contain the heading", id) + } + }) + + t.Run("AWSLinuxIncludesPermissions", func(t *testing.T) { + t.Parallel() + prereqs := templatebuilder.BasePrerequisites("aws-linux") + require.Contains(t, prereqs, "## Required permissions / policy", + "AWS Linux prerequisites should include the permissions section") + }) + + t.Run("UnknownReturnsEmpty", func(t *testing.T) { + t.Parallel() + require.Empty(t, templatebuilder.BasePrerequisites("nonexistent")) + }) +} diff --git a/coderd/templatebuilder/compose.go b/coderd/templatebuilder/compose.go index 9a400bd00e..dc7bb0853d 100644 --- a/coderd/templatebuilder/compose.go +++ b/coderd/templatebuilder/compose.go @@ -47,6 +47,9 @@ type ComposeResult struct { // ModulesTF is the concatenated rendered module blocks. Empty when // no modules are selected. ModulesTF []byte + // Readme is the full README.md content from the base template. + // Empty when the base has no README. + Readme []byte } // Compose renders a base template and selected modules into Terraform @@ -59,7 +62,10 @@ func Compose(req ComposeRequest) (*ComposeResult, error) { } if len(req.Modules) == 0 { - return &ComposeResult{MainTF: formatHCL(mainTF)}, nil + return &ComposeResult{ + MainTF: formatHCL(mainTF), + Readme: []byte(BaseReadme(req.BaseTemplateID)), + }, nil } agentName, err := ExtractAgentResourceName(mainTF) @@ -82,10 +88,12 @@ func Compose(req ComposeRequest) (*ComposeResult, error) { return nil, err } - return &ComposeResult{ + result := &ComposeResult{ MainTF: formatHCL(mainTF), ModulesTF: formatHCL(modulesTF), - }, nil + Readme: []byte(BaseReadme(req.BaseTemplateID)), + } + return result, nil } // formatHCL applies canonical HCL formatting to src. If src is not valid @@ -448,6 +456,12 @@ func BundleTar(result *ComposeResult) ([]byte, error) { } } + if len(result.Readme) > 0 { + if err := writeTarFile(tw, "README.md", result.Readme); err != nil { + return nil, xerrors.Errorf("write README.md to tar: %w", err) + } + } + if err := tw.Close(); err != nil { return nil, xerrors.Errorf("close tar writer: %w", err) } diff --git a/coderd/templatebuilder/compose_test.go b/coderd/templatebuilder/compose_test.go index 9eae66e326..0bf1eb851a 100644 --- a/coderd/templatebuilder/compose_test.go +++ b/coderd/templatebuilder/compose_test.go @@ -25,6 +25,7 @@ func TestCompose(t *testing.T) { require.NotEmpty(t, result.MainTF) require.Contains(t, string(result.MainTF), `resource "coder_agent" "main"`) require.Empty(t, result.ModulesTF) + require.NotEmpty(t, result.Readme, "compose should include base README") }) t.Run("BaseWithModuleAndVariableOverride", func(t *testing.T) { @@ -263,6 +264,7 @@ func TestBundleTar(t *testing.T) { files := extractTar(t, data) require.Contains(t, files, "main.tf") require.NotContains(t, files, "modules.tf") + require.NotContains(t, files, "README.md") require.Equal(t, "resource {}", files["main.tf"]) }) @@ -278,10 +280,26 @@ func TestBundleTar(t *testing.T) { files := extractTar(t, data) require.Contains(t, files, "main.tf") require.Contains(t, files, "modules.tf") + require.NotContains(t, files, "README.md") require.Equal(t, "resource {}", files["main.tf"]) require.Equal(t, "module {}", files["modules.tf"]) }) + t.Run("IncludesReadme", func(t *testing.T) { + t.Parallel() + result := &templatebuilder.ComposeResult{ + MainTF: []byte("resource {}"), + Readme: []byte("# My Template\n"), + } + data, err := templatebuilder.BundleTar(result) + require.NoError(t, err) + + files := extractTar(t, data) + require.Contains(t, files, "main.tf") + require.Contains(t, files, "README.md") + require.Equal(t, "# My Template\n", files["README.md"]) + }) + t.Run("RoundTrip", func(t *testing.T) { t.Parallel() result, err := templatebuilder.Compose(templatebuilder.ComposeRequest{ @@ -299,6 +317,7 @@ func TestBundleTar(t *testing.T) { files := extractTar(t, data) require.Equal(t, string(result.MainTF), files["main.tf"]) require.Equal(t, string(result.ModulesTF), files["modules.tf"]) + require.Equal(t, string(result.Readme), files["README.md"]) }) t.Run("ReproducibleArchive", func(t *testing.T) { diff --git a/coderd/templatebuilder/prerequisites.go b/coderd/templatebuilder/prerequisites.go new file mode 100644 index 0000000000..52658d02bc --- /dev/null +++ b/coderd/templatebuilder/prerequisites.go @@ -0,0 +1,27 @@ +package templatebuilder + +import "strings" + +const ( + // prerequisitesStartMarker delimits the beginning of the prerequisites + // section inside a base template README.md. + prerequisitesStartMarker = "" + // prerequisitesEndMarker delimits the end of the prerequisites section. + prerequisitesEndMarker = "" +) + +// ExtractPrerequisites returns the content between the prerequisites +// comment markers in a README body. Returns an empty string when either +// marker is absent. +func ExtractPrerequisites(readme string) string { + startIdx := strings.Index(readme, prerequisitesStartMarker) + if startIdx < 0 { + return "" + } + after := readme[startIdx+len(prerequisitesStartMarker):] + endIdx := strings.Index(after, prerequisitesEndMarker) + if endIdx < 0 { + return "" + } + return strings.TrimSpace(after[:endIdx]) +} diff --git a/coderd/templatebuilder/prerequisites_test.go b/coderd/templatebuilder/prerequisites_test.go new file mode 100644 index 0000000000..65c99d5a0c --- /dev/null +++ b/coderd/templatebuilder/prerequisites_test.go @@ -0,0 +1,86 @@ +package templatebuilder_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/coder/coder/v2/coderd/templatebuilder" +) + +func TestExtractPrerequisites(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + readme string + expected string + }{ + { + name: "BothMarkers", + readme: "# Title\n\n" + + "\n" + + "## Prerequisites\n\n" + + "Install Docker.\n" + + "\n\n" + + "## Architecture\n", + expected: "## Prerequisites\n\nInstall Docker.", + }, + { + name: "MultipleH2Sections", + readme: "# Title\n\n" + + "\n" + + "## Prerequisites\n\n" + + "Auth stuff.\n\n" + + "## Required permissions\n\n" + + "Policy JSON.\n" + + "\n\n" + + "## Architecture\n", + expected: "## Prerequisites\n\nAuth stuff.\n\n## Required permissions\n\nPolicy JSON.", + }, + { + name: "NoMarkers", + readme: "# Title\n\n## Prerequisites\n\nSome content.\n\n## Architecture\n", + expected: "", + }, + { + name: "StartMarkerOnly", + readme: "# Title\n\n" + + "\n" + + "## Prerequisites\n\nContent.\n", + expected: "", + }, + { + name: "EndMarkerOnly", + readme: "# Title\n\n" + + "## Prerequisites\n\nContent.\n" + + "\n", + expected: "", + }, + { + name: "EmptyBetweenMarkers", + readme: "\n" + + "\n", + expected: "", + }, + { + name: "NestedH3Headings", + readme: "\n" + + "## Prerequisites\n\n" + + "### Infrastructure\n\n" + + "Docker socket required.\n\n" + + "### Authentication\n\n" + + "Use kubeconfig.\n" + + "\n", + expected: "## Prerequisites\n\n### Infrastructure\n\nDocker socket required.\n\n### Authentication\n\nUse kubeconfig.", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + result := templatebuilder.ExtractPrerequisites(tt.readme) + require.Equal(t, tt.expected, result) + }) + } +} diff --git a/coderd/templatebuilder_handler.go b/coderd/templatebuilder_handler.go index 3c18e19bee..5d4e522ee4 100644 --- a/coderd/templatebuilder_handler.go +++ b/coderd/templatebuilder_handler.go @@ -74,12 +74,13 @@ func (api *API) templateBuilderBases(rw http.ResponseWriter, r *http.Request) { } vars := baseVariablesToSDK(templatebuilder.BaseVariables(id)) bases = append(bases, codersdk.TemplateBuilderBase{ - ID: ex.ID, - Name: ex.Name, - Description: ex.Description, - Icon: ex.Icon, - OS: string(templatebuilder.BaseTemplateOS(id)), - Variables: vars, + ID: ex.ID, + Name: ex.Name, + Description: ex.Description, + Icon: ex.Icon, + OS: string(templatebuilder.BaseTemplateOS(id)), + Variables: vars, + Prerequisites: templatebuilder.BasePrerequisites(id), }) } @@ -422,7 +423,7 @@ func (api *API) templateBuilderCreateTemplate(rw http.ResponseWriter, r *http.Re UpdatedAt: dbtime.Now(), Name: versionName, Message: "", - Readme: "", + Readme: string(result.Readme), JobID: provisionerJob.ID, CreatedBy: apiKey.UserID, SourceExampleID: sql.NullString{}, diff --git a/codersdk/templatebuilder.go b/codersdk/templatebuilder.go index 32406752b6..0bcb36ca05 100644 --- a/codersdk/templatebuilder.go +++ b/codersdk/templatebuilder.go @@ -52,12 +52,13 @@ type TemplateBuilderModulesResponse struct { // TemplateBuilderBase is the API response type for a base template // returned by GET /api/v2/templatebuilder/bases. type TemplateBuilderBase struct { - ID string `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - Icon string `json:"icon"` - OS string `json:"os"` - Variables []TemplateBuilderModuleVariable `json:"variables"` + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Icon string `json:"icon"` + OS string `json:"os"` + Variables []TemplateBuilderModuleVariable `json:"variables"` + Prerequisites string `json:"prerequisites"` } // TemplateBuilderBasesResponse is the response body for listing template builder bases. diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index 12c7d03bab..054c8bd71c 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -11924,6 +11924,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W "id": "string", "name": "string", "os": "string", + "prerequisites": "string", "variables": [ { "default": [ @@ -11941,14 +11942,15 @@ Restarts will only happen on weekdays in this list on weeks which line up with W ### Properties -| Name | Type | Required | Restrictions | Description | -|---------------|-------------------------------------------------------------------------------------------|----------|--------------|-------------| -| `description` | string | false | | | -| `icon` | string | false | | | -| `id` | string | false | | | -| `name` | string | false | | | -| `os` | string | false | | | -| `variables` | array of [codersdk.TemplateBuilderModuleVariable](#codersdktemplatebuildermodulevariable) | false | | | +| Name | Type | Required | Restrictions | Description | +|-----------------|-------------------------------------------------------------------------------------------|----------|--------------|-------------| +| `description` | string | false | | | +| `icon` | string | false | | | +| `id` | string | false | | | +| `name` | string | false | | | +| `os` | string | false | | | +| `prerequisites` | string | false | | | +| `variables` | array of [codersdk.TemplateBuilderModuleVariable](#codersdktemplatebuildermodulevariable) | false | | | ## codersdk.TemplateBuilderBasesResponse @@ -11961,6 +11963,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W "id": "string", "name": "string", "os": "string", + "prerequisites": "string", "variables": [ { "default": [ diff --git a/docs/reference/api/templatebuilder.md b/docs/reference/api/templatebuilder.md index 05ba6cc720..f1333ca897 100644 --- a/docs/reference/api/templatebuilder.md +++ b/docs/reference/api/templatebuilder.md @@ -26,6 +26,7 @@ curl -X GET http://coder-server:8080/api/v2/templatebuilder/bases \ "id": "string", "name": "string", "os": "string", + "prerequisites": "string", "variables": [ { "default": [ diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 03f9b3e27e..72a042a884 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -8282,6 +8282,7 @@ export interface TemplateBuilderBase { readonly icon: string; readonly os: string; readonly variables: readonly TemplateBuilderModuleVariable[]; + readonly prerequisites: string; } // From codersdk/templatebuilder.go