mirror of https://github.com/coder/coder.git
feat: Build framework for generating API docs (#5383)
* WIP * Gen * WIP * chi swagger * WIP * WIP * WIP * GetWorkspaces * GetWorkspaces * Markdown * Use widdershins * WIP * WIP * WIP * Markdown template * Fix: makefile * fmt * Fix: comment * Enable swagger conditionally * fix: site * Default false * Flag tests * fix * fix * template fixes * Fix * Fix * Fix * WIP * Formatted * Cleanup * Templates * BEGIN END SECTION * subshell exit code * Fix * Fix merge * WIP * Fix * Fix fmt * Fix * Generic api.md page * Fix merge * Link pages * Fix * Fix * Fix: links * Add icon * Write manifest file * Fix fmt * Fix: enterprise * Fix: Swagger.Enable * Fix: rename apidocs to apidoc * Fix: find -not -prune * Fix: json not available * Fix: rename Coderd API to Coder API * Fix: npm exec * Fix: api dir * Fix: by ID * Fix: string uuid * Fix: include deleted * Fix: indirect go.mod * Fix: source lib.sh * Fix: shellcheck * Fix: pushd popd * Fix: fmt * Fix: improve workspaces * Fix: swagger-enable * Fix * Fix: mention only HTTP 200 * Fix: IDs * Fix: https * Fix: icon * More APis * Fix: format swagger.json * Fix: SwaggerEndpoint * Fix: SCRIPT_DIR * Fix: PROJECT_ROOT * Fix: use code tags in schemas.md * Fix: examples * Fix: examples * Fix: improve format * Fix: date-time,enums * Fix: include_deleted * Fix: array of * Fix: parameter, response * Fix: string time or null * Workspaces: more docs * Workspaces: more docs * Fix: renderDisplayName * Fix: ActiveUserCount * Fix * Fix: typo * Templates: docs * Notice: incomplete
This commit is contained in:
parent
f239ca7ee3
commit
dc6d271293
10
Makefile
10
Makefile
|
@ -410,13 +410,14 @@ gen: \
|
|||
provisionersdk/proto/provisioner.pb.go \
|
||||
provisionerd/proto/provisionerd.pb.go \
|
||||
site/src/api/typesGenerated.ts \
|
||||
docs/admin/prometheus.md
|
||||
docs/admin/prometheus.md \
|
||||
coderd/apidoc/swagger.json
|
||||
.PHONY: gen
|
||||
|
||||
# Mark all generated files as fresh so make thinks they're up-to-date. This is
|
||||
# used during releases so we don't run generation scripts.
|
||||
gen/mark-fresh:
|
||||
files="coderd/database/dump.sql coderd/database/querier.go provisionersdk/proto/provisioner.pb.go provisionerd/proto/provisionerd.pb.go site/src/api/typesGenerated.ts docs/admin/prometheus.md"
|
||||
files="coderd/database/dump.sql coderd/database/querier.go provisionersdk/proto/provisioner.pb.go provisionerd/proto/provisionerd.pb.go site/src/api/typesGenerated.ts docs/admin/prometheus.md coderd/apidoc/swagger.json"
|
||||
for file in $$files; do
|
||||
echo "$$file"
|
||||
if [ ! -f "$$file" ]; then
|
||||
|
@ -464,6 +465,11 @@ docs/admin/prometheus.md: scripts/metricsdocgen/main.go scripts/metricsdocgen/me
|
|||
cd site
|
||||
yarn run format:write ../docs/admin/prometheus.md
|
||||
|
||||
coderd/apidoc/swagger.json: $(shell find ./scripts/apidocgen -not \( -path './scripts/apidocgen/node_modules' -prune \) -type f) $(wildcard coderd/*.go) $(wildcard codersdk/*.go)
|
||||
./scripts/apidocgen/generate.sh
|
||||
cd site
|
||||
yarn run format:write ../docs/api ../docs/manifest.json ../coderd/apidoc/swagger.json
|
||||
|
||||
update-golden-files: cli/testdata/.gen-golden
|
||||
.PHONY: update-golden-files
|
||||
|
||||
|
|
|
@ -452,6 +452,14 @@ func newConfig() *codersdk.DeploymentConfig {
|
|||
Flag: "max-token-lifetime",
|
||||
Default: 24 * 30 * time.Hour,
|
||||
},
|
||||
Swagger: &codersdk.SwaggerConfig{
|
||||
Enable: &codersdk.DeploymentConfigField[bool]{
|
||||
Name: "Enable swagger endpoint",
|
||||
Usage: "Expose the swagger endpoint via /swagger.",
|
||||
Flag: "swagger-enable",
|
||||
Default: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -678,6 +678,10 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co
|
|||
), cfg.Prometheus.Address.Value, "prometheus")()
|
||||
}
|
||||
|
||||
if cfg.Swagger.Enable.Value {
|
||||
options.SwaggerEndpoint = cfg.Swagger.Enable.Value
|
||||
}
|
||||
|
||||
// We use a separate coderAPICloser so the Enterprise API
|
||||
// can have it's own close functions. This is cleaner
|
||||
// than abstracting the Coder API itself.
|
||||
|
|
|
@ -169,6 +169,8 @@ Flags:
|
|||
"ecdsa", or "rsa4096".
|
||||
Consumes $CODER_SSH_KEYGEN_ALGORITHM
|
||||
(default "ed25519")
|
||||
--swagger-enable Expose the swagger endpoint via /swagger.
|
||||
Consumes $CODER_SWAGGER_ENABLE
|
||||
--telemetry Whether telemetry is enabled or not.
|
||||
Coder collects anonymized usage data to
|
||||
help improve our product.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/klauspost/compress/zstd"
|
||||
"github.com/moby/moby/pkg/namesgenerator"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
httpSwagger "github.com/swaggo/http-swagger"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"golang.org/x/xerrors"
|
||||
"google.golang.org/api/idtoken"
|
||||
|
@ -34,6 +35,9 @@ import (
|
|||
|
||||
"cdr.dev/slog"
|
||||
"github.com/coder/coder/buildinfo"
|
||||
|
||||
// Used to serve the Swagger endpoint
|
||||
_ "github.com/coder/coder/coderd/apidoc"
|
||||
"github.com/coder/coder/coderd/audit"
|
||||
"github.com/coder/coder/coderd/awsidentity"
|
||||
"github.com/coder/coder/coderd/database"
|
||||
|
@ -102,15 +106,34 @@ type Options struct {
|
|||
TailnetCoordinator tailnet.Coordinator
|
||||
DERPServer *derp.Server
|
||||
DERPMap *tailcfg.DERPMap
|
||||
SwaggerEndpoint bool
|
||||
|
||||
MetricsCacheRefreshInterval time.Duration
|
||||
AgentStatsRefreshInterval time.Duration
|
||||
Experimental bool
|
||||
DeploymentConfig *codersdk.DeploymentConfig
|
||||
UpdateCheckOptions *updatecheck.Options // Set non-nil to enable update checking.
|
||||
HTTPClient *http.Client
|
||||
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// @title Coder API
|
||||
// @version 2.0
|
||||
// @description Coderd is the service created by running coder server. It is a thin API that connects workspaces, provisioners and users. coderd stores its state in Postgres and is the only service that communicates with Postgres.
|
||||
// @termsOfService https://coder.com/legal/terms-of-service
|
||||
|
||||
// @contact.name API Support
|
||||
// @contact.url https://coder.com
|
||||
// @contact.email support@coder.com
|
||||
|
||||
// @license.name AGPL-3.0
|
||||
// @license.url https://github.com/coder/coder/blob/main/LICENSE
|
||||
|
||||
// @BasePath /api/v2
|
||||
|
||||
// @securitydefinitions.apiKey CoderSessionToken
|
||||
// @in header
|
||||
// @name Coder-Session-Token
|
||||
// New constructs a Coder API handler.
|
||||
func New(options *Options) *API {
|
||||
if options == nil {
|
||||
|
@ -578,6 +601,13 @@ func New(options *Options) *API {
|
|||
})
|
||||
})
|
||||
|
||||
if options.SwaggerEndpoint {
|
||||
// Swagger UI requires the URL trailing slash. Otherwise, the browser tries to load /assets
|
||||
// from http://localhost:8080/assets instead of http://localhost:8080/swagger/assets.
|
||||
r.Get("/swagger", http.RedirectHandler("/swagger/", http.StatusTemporaryRedirect).ServeHTTP)
|
||||
r.Get("/swagger/*", httpSwagger.Handler(httpSwagger.URL("/swagger/doc.json")))
|
||||
}
|
||||
|
||||
r.NotFound(compressHandler(http.HandlerFunc(api.siteHandler.ServeHTTP)).ServeHTTP)
|
||||
return api
|
||||
}
|
||||
|
|
|
@ -129,3 +129,81 @@ func TestHealthz(t *testing.T) {
|
|||
|
||||
assert.Equal(t, "OK", string(body))
|
||||
}
|
||||
|
||||
func TestSwagger(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const swaggerEndpoint = "/swagger"
|
||||
t.Run("endpoint enabled", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
SwaggerEndpoint: true,
|
||||
})
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitMedium)
|
||||
defer cancel()
|
||||
|
||||
resp, err := requestWithRetries(ctx, t, client, http.MethodGet, swaggerEndpoint, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Contains(t, string(body), "Swagger UI")
|
||||
})
|
||||
t.Run("doc.json exposed", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
SwaggerEndpoint: true,
|
||||
})
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitMedium)
|
||||
defer cancel()
|
||||
|
||||
resp, err := requestWithRetries(ctx, t, client, http.MethodGet, swaggerEndpoint+"/doc.json", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Contains(t, string(body), `"swagger": "2.0"`)
|
||||
})
|
||||
t.Run("endpoint disabled by default", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := coderdtest.New(t, nil)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitMedium)
|
||||
defer cancel()
|
||||
|
||||
resp, err := requestWithRetries(ctx, t, client, http.MethodGet, swaggerEndpoint, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, "<pre>\n</pre>\n", string(body))
|
||||
})
|
||||
t.Run("doc.json disabled by default", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := coderdtest.New(t, nil)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitMedium)
|
||||
defer cancel()
|
||||
|
||||
resp, err := requestWithRetries(ctx, t, client, http.MethodGet, swaggerEndpoint+"/doc.json", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
require.Equal(t, "<pre>\n</pre>\n", string(body))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -115,6 +115,8 @@ type Options struct {
|
|||
// test instances are running against the same database.
|
||||
Database database.Store
|
||||
Pubsub database.Pubsub
|
||||
|
||||
SwaggerEndpoint bool
|
||||
}
|
||||
|
||||
// New constructs a codersdk client connected to an in-memory API instance.
|
||||
|
@ -297,6 +299,7 @@ func NewOptions(t *testing.T, options *Options) (func(http.Handler), context.Can
|
|||
AgentStatsRefreshInterval: options.AgentStatsRefreshInterval,
|
||||
DeploymentConfig: options.DeploymentConfig,
|
||||
UpdateCheckOptions: options.UpdateCheckOptions,
|
||||
SwaggerEndpoint: options.SwaggerEndpoint,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,14 @@ const (
|
|||
AutoImportTemplateKubernetes AutoImportTemplate = "kubernetes"
|
||||
)
|
||||
|
||||
// @Summary Get template metadata by ID
|
||||
// @ID get-template-metadata-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param id path string true "Template ID" format(uuid)
|
||||
// @Success 200 {object} codersdk.Template
|
||||
// @Router /templates/{id} [get]
|
||||
// Returns a single template.
|
||||
func (api *API) template(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
@ -73,6 +81,14 @@ func (api *API) template(rw http.ResponseWriter, r *http.Request) {
|
|||
httpapi.Write(ctx, rw, http.StatusOK, api.convertTemplate(template, count, createdByNameMap[template.ID.String()]))
|
||||
}
|
||||
|
||||
// @Summary Delete template by ID
|
||||
// @ID delete-template-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param id path string true "Template ID" format(uuid)
|
||||
// @Success 200 {object} codersdk.Response
|
||||
// @Router /templates/{id} [delete]
|
||||
func (api *API) deleteTemplate(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
|
@ -126,6 +142,17 @@ func (api *API) deleteTemplate(rw http.ResponseWriter, r *http.Request) {
|
|||
})
|
||||
}
|
||||
|
||||
// @Summary Create template by organization
|
||||
// @ID create-template-by-organization
|
||||
// @Security CoderSessionToken
|
||||
// @Consume json
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param request body codersdk.CreateTemplateRequest true "Request body"
|
||||
// @Param organization-id path string true "Organization ID"
|
||||
// @Success 200 {object} codersdk.Template
|
||||
// @Router /organizations/{organization-id}/templates/ [post]
|
||||
// Returns a single template.
|
||||
// Create a new template in an organization.
|
||||
func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
|
@ -314,6 +341,14 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
|||
httpapi.Write(ctx, rw, http.StatusCreated, template)
|
||||
}
|
||||
|
||||
// @Summary Get templates by organization
|
||||
// @ID get-templates-by-organization
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param organization path string true "Organization ID" format(uuid)
|
||||
// @Success 200 {object} []codersdk.Template
|
||||
// @Router /organizations/{organization}/templates [get]
|
||||
func (api *API) templatesByOrganization(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
organization := httpmw.OrganizationParam(r)
|
||||
|
@ -372,6 +407,15 @@ func (api *API) templatesByOrganization(rw http.ResponseWriter, r *http.Request)
|
|||
httpapi.Write(ctx, rw, http.StatusOK, api.convertTemplates(templates, workspaceCounts, createdByNameMap))
|
||||
}
|
||||
|
||||
// @Summary Get templates by organization and template name
|
||||
// @ID get-templates-by-organization-and-template-name
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param organization path string true "Organization ID" format(uuid)
|
||||
// @Param template-name path string true "Template name"
|
||||
// @Success 200 {object} codersdk.Template
|
||||
// @Router /organizations/{organization}/templates/{template-name} [get]
|
||||
func (api *API) templateByOrganizationAndName(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
organization := httpmw.OrganizationParam(r)
|
||||
|
@ -427,6 +471,14 @@ func (api *API) templateByOrganizationAndName(rw http.ResponseWriter, r *http.Re
|
|||
httpapi.Write(ctx, rw, http.StatusOK, api.convertTemplate(template, count, createdByNameMap[template.ID.String()]))
|
||||
}
|
||||
|
||||
// @Summary Update template metadata by ID
|
||||
// @ID update-template-metadata
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param id path string true "Template ID" format(uuid)
|
||||
// @Success 200 {object} codersdk.Template
|
||||
// @Router /templates/{id} [get]
|
||||
func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
|
|
|
@ -43,6 +43,15 @@ var (
|
|||
errDeadlineBeforeStart = xerrors.New("new deadline must be before workspace start time")
|
||||
)
|
||||
|
||||
// @Summary Get workspace metadata by ID
|
||||
// @ID get-workspace-metadata-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Workspaces
|
||||
// @Param id path string true "Workspace ID" format(uuid)
|
||||
// @Param include_deleted query bool false "Return data instead of HTTP 404 if the workspace is deleted"
|
||||
// @Success 200 {object} codersdk.Workspace
|
||||
// @Router /workspaces/{id} [get]
|
||||
func (api *API) workspace(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
workspace := httpmw.WorkspaceParam(r)
|
||||
|
@ -92,6 +101,19 @@ func (api *API) workspace(rw http.ResponseWriter, r *http.Request) {
|
|||
))
|
||||
}
|
||||
|
||||
// @Summary List workspaces
|
||||
// @ID get-workspaces
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Workspaces
|
||||
// @Param owner query string false "Filter by owner username"
|
||||
// @Param template query string false "Filter by template name"
|
||||
// @Param name query string false "Filter with partial-match by workspace name"
|
||||
// @Param status query string false "Filter by workspace status" Enums(pending,running,stopping,stopped,failed,canceling,canceled,deleted,deleting)
|
||||
// @Param has_agent query string false "Filter by agent status" Enums(connected,connecting,disconnected,timeout)
|
||||
// @Success 200 {object} codersdk.WorkspacesResponse
|
||||
// @Router /workspaces [get]
|
||||
//
|
||||
// workspaces returns all workspaces a user can read.
|
||||
// Optional filters with query params
|
||||
func (api *API) workspaces(rw http.ResponseWriter, r *http.Request) {
|
||||
|
@ -170,6 +192,16 @@ func (api *API) workspaces(rw http.ResponseWriter, r *http.Request) {
|
|||
})
|
||||
}
|
||||
|
||||
// @Summary Get workspace metadata by owner and workspace name
|
||||
// @ID get-workspace-metadata-by-owner-and-workspace-name
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Workspaces
|
||||
// @Param user path string true "Owner username"
|
||||
// @Param workspacename path string true "Workspace name"
|
||||
// @Param include_deleted query bool false "Return data instead of HTTP 404 if the workspace is deleted"
|
||||
// @Success 200 {object} codersdk.Workspace
|
||||
// @Router /users/{user}/workspace/{workspacename} [get]
|
||||
func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
owner := httpmw.UserParam(r)
|
||||
|
@ -234,6 +266,15 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request)
|
|||
))
|
||||
}
|
||||
|
||||
// @Summary Create workspace by organization
|
||||
// @ID create-workspace-by-organization
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Workspaces
|
||||
// @Param organization path string true "Organization ID" format(uuid)
|
||||
// @Param user path string true "Username"
|
||||
// @Success 200 {object} codersdk.Workspace
|
||||
// @Router /organizations/{organization}/members/{user}/workspaces [post]
|
||||
// Create a new workspace for the currently authenticated user.
|
||||
func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
|
@ -520,6 +561,16 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
|
|||
))
|
||||
}
|
||||
|
||||
// @Summary Update workspace metadata by ID
|
||||
// @ID update-workspace-metadata-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Consume json
|
||||
// @Produce json
|
||||
// @Tags Workspaces
|
||||
// @Param workspace path string true "Workspace ID" format(uuid)
|
||||
// @Param request body codersdk.UpdateWorkspaceRequest true "Metadata update request"
|
||||
// @Success 204
|
||||
// @Router /workspaces/{workspace} [patch]
|
||||
func (api *API) patchWorkspace(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
|
@ -600,6 +651,16 @@ func (api *API) patchWorkspace(rw http.ResponseWriter, r *http.Request) {
|
|||
rw.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// @Summary Update workspace autostart schedule by ID
|
||||
// @ID update-workspace-autostart-schedule-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Consume json
|
||||
// @Produce json
|
||||
// @Tags Workspaces
|
||||
// @Param workspace path string true "Workspace ID" format(uuid)
|
||||
// @Param request body codersdk.UpdateWorkspaceAutostartRequest true "Schedule update request"
|
||||
// @Success 204
|
||||
// @Router /workspaces/{workspace}/autostart [put]
|
||||
func (api *API) putWorkspaceAutostart(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
|
@ -653,6 +714,16 @@ func (api *API) putWorkspaceAutostart(rw http.ResponseWriter, r *http.Request) {
|
|||
rw.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// @Summary Update workspace TTL by ID
|
||||
// @ID update-workspace-ttl-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Consume json
|
||||
// @Produce json
|
||||
// @Tags Workspaces
|
||||
// @Param workspace path string true "Workspace ID" format(uuid)
|
||||
// @Param request body codersdk.UpdateWorkspaceTTLRequest true "Workspace TTL update request"
|
||||
// @Success 204
|
||||
// @Router /workspaces/{workspace}/ttl [put]
|
||||
func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
|
@ -719,6 +790,16 @@ func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) {
|
|||
rw.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// @Summary Extend workspace deadline by ID
|
||||
// @ID extend-workspace-deadline-by-id
|
||||
// @Security CoderSessionToken
|
||||
// @Consume json
|
||||
// @Produce json
|
||||
// @Tags Workspaces
|
||||
// @Param workspace path string true "Workspace ID" format(uuid)
|
||||
// @Param request body codersdk.PutExtendWorkspaceRequest true "Extend deadline update request"
|
||||
// @Success 200 {object} codersdk.Response
|
||||
// @Router /workspaces/{workspace}/extend [put]
|
||||
func (api *API) putExtendWorkspace(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
workspace := httpmw.WorkspaceParam(r)
|
||||
|
@ -800,6 +881,14 @@ func (api *API) putExtendWorkspace(rw http.ResponseWriter, r *http.Request) {
|
|||
httpapi.Write(ctx, rw, code, resp)
|
||||
}
|
||||
|
||||
// @Summary Watch workspace by ID
|
||||
// @ID watch-workspace-id
|
||||
// @Security CoderSessionToken
|
||||
// @Produce text/event-stream
|
||||
// @Tags Workspaces
|
||||
// @Param workspace path string true "Workspace ID" format(uuid)
|
||||
// @Success 200 {object} codersdk.Response
|
||||
// @Router /workspaces/{workspace}/watch [get]
|
||||
func (api *API) watchWorkspace(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
workspace := httpmw.WorkspaceParam(r)
|
||||
|
|
|
@ -45,6 +45,7 @@ type DeploymentConfig struct {
|
|||
Experimental *DeploymentConfigField[bool] `json:"experimental" typescript:",notnull"`
|
||||
UpdateCheck *DeploymentConfigField[bool] `json:"update_check" typescript:",notnull"`
|
||||
MaxTokenLifetime *DeploymentConfigField[time.Duration] `json:"max_token_lifetime" typescript:",notnull"`
|
||||
Swagger *SwaggerConfig `json:"swagger" typescript:",notnull"`
|
||||
}
|
||||
|
||||
type DERP struct {
|
||||
|
@ -145,6 +146,10 @@ type ProvisionerConfig struct {
|
|||
ForceCancelInterval *DeploymentConfigField[time.Duration] `json:"force_cancel_interval" typescript:",notnull"`
|
||||
}
|
||||
|
||||
type SwaggerConfig struct {
|
||||
Enable *DeploymentConfigField[bool] `json:"enable" typescript:",notnull"`
|
||||
}
|
||||
|
||||
type Flaggable interface {
|
||||
string | time.Duration | bool | int | []string | []GitAuthConfig
|
||||
}
|
||||
|
|
|
@ -14,10 +14,10 @@ import (
|
|||
// Template is the JSON representation of a Coder template. This type matches the
|
||||
// database object for now, but is abstracted for ease of change later on.
|
||||
type Template struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
ID uuid.UUID `json:"id" format:"uuid"`
|
||||
CreatedAt time.Time `json:"created_at" format:"date-time"`
|
||||
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
|
||||
OrganizationID uuid.UUID `json:"organization_id" format:"uuid"`
|
||||
Name string `json:"name"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Provisioner ProvisionerType `json:"provisioner"`
|
||||
|
@ -29,15 +29,15 @@ type Template struct {
|
|||
Description string `json:"description"`
|
||||
Icon string `json:"icon"`
|
||||
DefaultTTLMillis int64 `json:"default_ttl_ms"`
|
||||
CreatedByID uuid.UUID `json:"created_by_id"`
|
||||
CreatedByID uuid.UUID `json:"created_by_id" format:"uuid"`
|
||||
CreatedByName string `json:"created_by_name"`
|
||||
|
||||
AllowUserCancelWorkspaceJobs bool `json:"allow_user_cancel_workspace_jobs"`
|
||||
}
|
||||
|
||||
type TransitionStats struct {
|
||||
P50 *int64
|
||||
P95 *int64
|
||||
P50 *int64 `example:"123"`
|
||||
P95 *int64 `example:"146"`
|
||||
}
|
||||
|
||||
type TemplateBuildTimeStats map[WorkspaceTransition]TransitionStats
|
||||
|
|
|
@ -51,32 +51,32 @@ const (
|
|||
// WorkspaceBuild is an at-point representation of a workspace state.
|
||||
// BuildNumbers start at 1 and increase by 1 for each subsequent build
|
||||
type WorkspaceBuild struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
WorkspaceID uuid.UUID `json:"workspace_id"`
|
||||
ID uuid.UUID `json:"id" format:"uuid"`
|
||||
CreatedAt time.Time `json:"created_at" format:"date-time"`
|
||||
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
|
||||
WorkspaceID uuid.UUID `json:"workspace_id" format:"uuid"`
|
||||
WorkspaceName string `json:"workspace_name"`
|
||||
WorkspaceOwnerID uuid.UUID `json:"workspace_owner_id"`
|
||||
WorkspaceOwnerID uuid.UUID `json:"workspace_owner_id" format:"uuid"`
|
||||
WorkspaceOwnerName string `json:"workspace_owner_name"`
|
||||
TemplateVersionID uuid.UUID `json:"template_version_id"`
|
||||
TemplateVersionID uuid.UUID `json:"template_version_id" format:"uuid"`
|
||||
TemplateVersionName string `json:"template_version_name"`
|
||||
BuildNumber int32 `json:"build_number"`
|
||||
Transition WorkspaceTransition `json:"transition"`
|
||||
InitiatorID uuid.UUID `json:"initiator_id"`
|
||||
Transition WorkspaceTransition `json:"transition" enums:"start,stop,delete"`
|
||||
InitiatorID uuid.UUID `json:"initiator_id" format:"uuid"`
|
||||
InitiatorUsername string `json:"initiator_name"`
|
||||
Job ProvisionerJob `json:"job"`
|
||||
Reason BuildReason `db:"reason" json:"reason"`
|
||||
Resources []WorkspaceResource `json:"resources"`
|
||||
Deadline NullTime `json:"deadline,omitempty"`
|
||||
Status WorkspaceStatus `json:"status"`
|
||||
Status WorkspaceStatus `json:"status" enums:"pending,starting,running,stopping,stopped,failed,canceling,canceled,deleting,deleted"`
|
||||
DailyCost int32 `json:"daily_cost"`
|
||||
}
|
||||
|
||||
type WorkspaceResource struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
JobID uuid.UUID `json:"job_id"`
|
||||
Transition WorkspaceTransition `json:"workspace_transition"`
|
||||
ID uuid.UUID `json:"id" format:"uuid"`
|
||||
CreatedAt time.Time `json:"created_at" format:"date-time"`
|
||||
JobID uuid.UUID `json:"job_id" format:"uuid"`
|
||||
Transition WorkspaceTransition `json:"workspace_transition" enums:"start,stop,delete"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Hide bool `json:"hide"`
|
||||
|
|
|
@ -17,12 +17,12 @@ import (
|
|||
// Workspace is a deployment of a template. It references a specific
|
||||
// version and can be updated.
|
||||
type Workspace struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
OwnerID uuid.UUID `json:"owner_id"`
|
||||
ID uuid.UUID `json:"id" format:"uuid"`
|
||||
CreatedAt time.Time `json:"created_at" format:"date-time"`
|
||||
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
|
||||
OwnerID uuid.UUID `json:"owner_id" format:"uuid"`
|
||||
OwnerName string `json:"owner_name"`
|
||||
TemplateID uuid.UUID `json:"template_id"`
|
||||
TemplateID uuid.UUID `json:"template_id" format:"uuid"`
|
||||
TemplateName string `json:"template_name"`
|
||||
TemplateDisplayName string `json:"template_display_name"`
|
||||
TemplateIcon string `json:"template_icon"`
|
||||
|
@ -32,7 +32,7 @@ type Workspace struct {
|
|||
Name string `json:"name"`
|
||||
AutostartSchedule *string `json:"autostart_schedule,omitempty"`
|
||||
TTLMillis *int64 `json:"ttl_ms,omitempty"`
|
||||
LastUsedAt time.Time `json:"last_used_at"`
|
||||
LastUsedAt time.Time `json:"last_used_at" format:"date-time"`
|
||||
}
|
||||
|
||||
type WorkspacesRequest struct {
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# Authentication
|
||||
|
||||
- API Key (CoderSessionToken)
|
||||
- Parameter Name: **Coder-Session-Token**, in: header.
|
|
@ -0,0 +1,5 @@
|
|||
Get started with Coder API:
|
||||
|
||||
<children>
|
||||
This page is rendered on https://coder.com/docs/coder-oss/api. Refer to the other documents in the `api/` directory.
|
||||
</children>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,356 @@
|
|||
# Templates
|
||||
|
||||
> This page is incomplete, stay tuned.
|
||||
|
||||
## Create template by organization
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X POST http://coder-server:8080/api/v2/organizations/{organization-id}/templates/ \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
|
||||
```
|
||||
|
||||
`POST /organizations/{organization-id}/templates/`
|
||||
|
||||
> Body parameter
|
||||
|
||||
```json
|
||||
{
|
||||
"allow_user_cancel_workspace_jobs": true,
|
||||
"default_ttl_ms": 0,
|
||||
"description": "string",
|
||||
"display_name": "string",
|
||||
"icon": "string",
|
||||
"name": "string",
|
||||
"parameter_values": [
|
||||
{
|
||||
"copy_from_parameter": "string",
|
||||
"destination_scheme": "environment_variable",
|
||||
"name": "string",
|
||||
"source_scheme": "data",
|
||||
"source_value": "string"
|
||||
}
|
||||
],
|
||||
"template_version_id": "string"
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| --------------- | ---- | -------------------------------------------------------------------------- | -------- | --------------- |
|
||||
| organization-id | path | string | true | Organization ID |
|
||||
| body | body | [codersdk.CreateTemplateRequest](schemas.md#codersdkcreatetemplaterequest) | true | Request body |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"active_user_count": 0,
|
||||
"active_version_id": "string",
|
||||
"allow_user_cancel_workspace_jobs": true,
|
||||
"build_time_stats": {
|
||||
"property1": {
|
||||
"p50": 123,
|
||||
"p95": 146
|
||||
},
|
||||
"property2": {
|
||||
"p50": 123,
|
||||
"p95": 146
|
||||
}
|
||||
},
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"created_by_id": "9377d689-01fb-4abf-8450-3368d2c1924f",
|
||||
"created_by_name": "string",
|
||||
"default_ttl_ms": 0,
|
||||
"description": "string",
|
||||
"display_name": "string",
|
||||
"icon": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"provisioner": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"workspace_owner_count": 0
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------ |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Template](schemas.md#codersdktemplate) |
|
||||
|
||||
To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**.
|
||||
|
||||
## Get templates by organization
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templates \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
|
||||
```
|
||||
|
||||
`GET /organizations/{organization}/templates`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ------------ | ---- | ------------ | -------- | --------------- |
|
||||
| organization | path | string(uuid) | true | Organization ID |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"active_user_count": 0,
|
||||
"active_version_id": "string",
|
||||
"allow_user_cancel_workspace_jobs": true,
|
||||
"build_time_stats": {
|
||||
"property1": {
|
||||
"p50": 123,
|
||||
"p95": 146
|
||||
},
|
||||
"property2": {
|
||||
"p50": 123,
|
||||
"p95": 146
|
||||
}
|
||||
},
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"created_by_id": "9377d689-01fb-4abf-8450-3368d2c1924f",
|
||||
"created_by_name": "string",
|
||||
"default_ttl_ms": 0,
|
||||
"description": "string",
|
||||
"display_name": "string",
|
||||
"icon": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"provisioner": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"workspace_owner_count": 0
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | --------------------------------------------------------- |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | array of [codersdk.Template](schemas.md#codersdktemplate) |
|
||||
|
||||
<h3 id="get-templates-by-organization-responseschema">Response Schema</h3>
|
||||
|
||||
Status Code **200**
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ---------------------------------- | --------------------------------- | -------- | ------------ | ------------------------------------------ |
|
||||
| _anonymous_ | array | false | none | none |
|
||||
| » active_user_count | integer | false | none | ActiveUserCount is set to -1 when loading. |
|
||||
| » active_version_id | string | false | none | none |
|
||||
| » allow_user_cancel_workspace_jobs | boolean | false | none | none |
|
||||
| » build_time_stats | `codersdk.TemplateBuildTimeStats` | false | none | none |
|
||||
| »» **additionalProperties** | `codersdk.TransitionStats` | false | none | none |
|
||||
| »»» p50 | integer | false | none | none |
|
||||
| »»» p95 | integer | false | none | none |
|
||||
| » created_at | string | false | none | none |
|
||||
| » created_by_id | string | false | none | none |
|
||||
| » created_by_name | string | false | none | none |
|
||||
| » default_ttl_ms | integer | false | none | none |
|
||||
| » description | string | false | none | none |
|
||||
| » display_name | string | false | none | none |
|
||||
| » icon | string | false | none | none |
|
||||
| » id | string | false | none | none |
|
||||
| » name | string | false | none | none |
|
||||
| » organization_id | string | false | none | none |
|
||||
| » provisioner | string | false | none | none |
|
||||
| » updated_at | string | false | none | none |
|
||||
| » workspace_owner_count | integer | false | none | none |
|
||||
|
||||
To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**.
|
||||
|
||||
## Get templates by organization and template name
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templates/{template-name} \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
|
||||
```
|
||||
|
||||
`GET /organizations/{organization}/templates/{template-name}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ------------- | ---- | ------------ | -------- | --------------- |
|
||||
| organization | path | string(uuid) | true | Organization ID |
|
||||
| template-name | path | string | true | Template name |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"active_user_count": 0,
|
||||
"active_version_id": "string",
|
||||
"allow_user_cancel_workspace_jobs": true,
|
||||
"build_time_stats": {
|
||||
"property1": {
|
||||
"p50": 123,
|
||||
"p95": 146
|
||||
},
|
||||
"property2": {
|
||||
"p50": 123,
|
||||
"p95": 146
|
||||
}
|
||||
},
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"created_by_id": "9377d689-01fb-4abf-8450-3368d2c1924f",
|
||||
"created_by_name": "string",
|
||||
"default_ttl_ms": 0,
|
||||
"description": "string",
|
||||
"display_name": "string",
|
||||
"icon": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"provisioner": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"workspace_owner_count": 0
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------ |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Template](schemas.md#codersdktemplate) |
|
||||
|
||||
To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**.
|
||||
|
||||
## Update template metadata by ID
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/templates/{id} \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
|
||||
```
|
||||
|
||||
`GET /templates/{id}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---- | ---- | ------------ | -------- | ----------- |
|
||||
| id | path | string(uuid) | true | Template ID |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"active_user_count": 0,
|
||||
"active_version_id": "string",
|
||||
"allow_user_cancel_workspace_jobs": true,
|
||||
"build_time_stats": {
|
||||
"property1": {
|
||||
"p50": 123,
|
||||
"p95": 146
|
||||
},
|
||||
"property2": {
|
||||
"p50": 123,
|
||||
"p95": 146
|
||||
}
|
||||
},
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"created_by_id": "9377d689-01fb-4abf-8450-3368d2c1924f",
|
||||
"created_by_name": "string",
|
||||
"default_ttl_ms": 0,
|
||||
"description": "string",
|
||||
"display_name": "string",
|
||||
"icon": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"provisioner": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"workspace_owner_count": 0
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------ |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Template](schemas.md#codersdktemplate) |
|
||||
|
||||
To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**.
|
||||
|
||||
## Delete template by ID
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X DELETE http://coder-server:8080/api/v2/templates/{id} \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
|
||||
```
|
||||
|
||||
`DELETE /templates/{id}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ---- | ---- | ------------ | -------- | ----------- |
|
||||
| id | path | string(uuid) | true | Template ID |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "string",
|
||||
"message": "string",
|
||||
"validations": [
|
||||
{
|
||||
"detail": "string",
|
||||
"field": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------ |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Response](schemas.md#codersdkresponse) |
|
||||
|
||||
To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**.
|
|
@ -0,0 +1,880 @@
|
|||
# Workspaces
|
||||
|
||||
> This page is incomplete, stay tuned.
|
||||
|
||||
## Create workspace by organization
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/members/{user}/workspaces \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
|
||||
```
|
||||
|
||||
`POST /organizations/{organization}/members/{user}/workspaces`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| ------------ | ---- | ------------ | -------- | --------------- |
|
||||
| organization | path | string(uuid) | true | Organization ID |
|
||||
| user | path | string | true | Username |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"autostart_schedule": "string",
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"last_used_at": "2019-08-24T14:15:22Z",
|
||||
"latest_build": {
|
||||
"build_number": 0,
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"daily_cost": 0,
|
||||
"deadline": {
|
||||
"time": "string",
|
||||
"valid": true
|
||||
},
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
|
||||
"initiator_name": "string",
|
||||
"job": {
|
||||
"canceled_at": "string",
|
||||
"completed_at": "string",
|
||||
"created_at": "string",
|
||||
"error": "string",
|
||||
"file_id": "string",
|
||||
"id": "string",
|
||||
"started_at": "string",
|
||||
"status": "string",
|
||||
"tags": {
|
||||
"property1": "string",
|
||||
"property2": "string"
|
||||
},
|
||||
"worker_id": "string"
|
||||
},
|
||||
"reason": "string",
|
||||
"resources": [
|
||||
{
|
||||
"agents": [
|
||||
{
|
||||
"apps": [
|
||||
{
|
||||
"command": "string",
|
||||
"display_name": "string",
|
||||
"external": true,
|
||||
"health": "string",
|
||||
"healthcheck": {
|
||||
"interval": 0,
|
||||
"threshold": 0,
|
||||
"url": "string"
|
||||
},
|
||||
"icon": "string",
|
||||
"id": "string",
|
||||
"sharing_level": "string",
|
||||
"slug": "string",
|
||||
"subdomain": true,
|
||||
"url": "string"
|
||||
}
|
||||
],
|
||||
"architecture": "string",
|
||||
"connection_timeout_seconds": 0,
|
||||
"created_at": "string",
|
||||
"directory": "string",
|
||||
"disconnected_at": "string",
|
||||
"environment_variables": {
|
||||
"property1": "string",
|
||||
"property2": "string"
|
||||
},
|
||||
"first_connected_at": "string",
|
||||
"id": "string",
|
||||
"instance_id": "string",
|
||||
"last_connected_at": "string",
|
||||
"latency": {
|
||||
"property1": {
|
||||
"latency_ms": 0,
|
||||
"preferred": true
|
||||
},
|
||||
"property2": {
|
||||
"latency_ms": 0,
|
||||
"preferred": true
|
||||
}
|
||||
},
|
||||
"name": "string",
|
||||
"operating_system": "string",
|
||||
"resource_id": "string",
|
||||
"startup_script": "string",
|
||||
"status": "string",
|
||||
"troubleshooting_url": "string",
|
||||
"updated_at": "string",
|
||||
"version": "string"
|
||||
}
|
||||
],
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"daily_cost": 0,
|
||||
"hide": true,
|
||||
"icon": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"job_id": "453bd7d7-5355-4d6d-a38e-d9e7eb218c3f",
|
||||
"metadata": [
|
||||
{
|
||||
"key": "string",
|
||||
"sensitive": true,
|
||||
"value": "string"
|
||||
}
|
||||
],
|
||||
"name": "string",
|
||||
"type": "string",
|
||||
"workspace_transition": "start"
|
||||
}
|
||||
],
|
||||
"status": "pending",
|
||||
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
|
||||
"template_version_name": "string",
|
||||
"transition": "start",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"workspace_id": "0967198e-ec7b-4c6b-b4d3-f71244cadbe9",
|
||||
"workspace_name": "string",
|
||||
"workspace_owner_id": "e7078695-5279-4c86-8774-3ac2367a2fc7",
|
||||
"workspace_owner_name": "string"
|
||||
},
|
||||
"name": "string",
|
||||
"outdated": true,
|
||||
"owner_id": "8826ee2e-7933-4665-aef2-2393f84a0d05",
|
||||
"owner_name": "string",
|
||||
"template_allow_user_cancel_workspace_jobs": true,
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_id": "c6d67e98-83ea-49f0-8812-e4abae2b68bc",
|
||||
"template_name": "string",
|
||||
"ttl_ms": 0,
|
||||
"updated_at": "2019-08-24T14:15:22Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | -------------------------------------------------- |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Workspace](schemas.md#codersdkworkspace) |
|
||||
|
||||
To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**.
|
||||
|
||||
## Get workspace metadata by owner and workspace name
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacename} \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
|
||||
```
|
||||
|
||||
`GET /users/{user}/workspace/{workspacename}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| --------------- | ----- | ------- | -------- | ----------------------------------------------------------- |
|
||||
| user | path | string | true | Owner username |
|
||||
| workspacename | path | string | true | Workspace name |
|
||||
| include_deleted | query | boolean | false | Return data instead of HTTP 404 if the workspace is deleted |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"autostart_schedule": "string",
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"last_used_at": "2019-08-24T14:15:22Z",
|
||||
"latest_build": {
|
||||
"build_number": 0,
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"daily_cost": 0,
|
||||
"deadline": {
|
||||
"time": "string",
|
||||
"valid": true
|
||||
},
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
|
||||
"initiator_name": "string",
|
||||
"job": {
|
||||
"canceled_at": "string",
|
||||
"completed_at": "string",
|
||||
"created_at": "string",
|
||||
"error": "string",
|
||||
"file_id": "string",
|
||||
"id": "string",
|
||||
"started_at": "string",
|
||||
"status": "string",
|
||||
"tags": {
|
||||
"property1": "string",
|
||||
"property2": "string"
|
||||
},
|
||||
"worker_id": "string"
|
||||
},
|
||||
"reason": "string",
|
||||
"resources": [
|
||||
{
|
||||
"agents": [
|
||||
{
|
||||
"apps": [
|
||||
{
|
||||
"command": "string",
|
||||
"display_name": "string",
|
||||
"external": true,
|
||||
"health": "string",
|
||||
"healthcheck": {
|
||||
"interval": 0,
|
||||
"threshold": 0,
|
||||
"url": "string"
|
||||
},
|
||||
"icon": "string",
|
||||
"id": "string",
|
||||
"sharing_level": "string",
|
||||
"slug": "string",
|
||||
"subdomain": true,
|
||||
"url": "string"
|
||||
}
|
||||
],
|
||||
"architecture": "string",
|
||||
"connection_timeout_seconds": 0,
|
||||
"created_at": "string",
|
||||
"directory": "string",
|
||||
"disconnected_at": "string",
|
||||
"environment_variables": {
|
||||
"property1": "string",
|
||||
"property2": "string"
|
||||
},
|
||||
"first_connected_at": "string",
|
||||
"id": "string",
|
||||
"instance_id": "string",
|
||||
"last_connected_at": "string",
|
||||
"latency": {
|
||||
"property1": {
|
||||
"latency_ms": 0,
|
||||
"preferred": true
|
||||
},
|
||||
"property2": {
|
||||
"latency_ms": 0,
|
||||
"preferred": true
|
||||
}
|
||||
},
|
||||
"name": "string",
|
||||
"operating_system": "string",
|
||||
"resource_id": "string",
|
||||
"startup_script": "string",
|
||||
"status": "string",
|
||||
"troubleshooting_url": "string",
|
||||
"updated_at": "string",
|
||||
"version": "string"
|
||||
}
|
||||
],
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"daily_cost": 0,
|
||||
"hide": true,
|
||||
"icon": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"job_id": "453bd7d7-5355-4d6d-a38e-d9e7eb218c3f",
|
||||
"metadata": [
|
||||
{
|
||||
"key": "string",
|
||||
"sensitive": true,
|
||||
"value": "string"
|
||||
}
|
||||
],
|
||||
"name": "string",
|
||||
"type": "string",
|
||||
"workspace_transition": "start"
|
||||
}
|
||||
],
|
||||
"status": "pending",
|
||||
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
|
||||
"template_version_name": "string",
|
||||
"transition": "start",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"workspace_id": "0967198e-ec7b-4c6b-b4d3-f71244cadbe9",
|
||||
"workspace_name": "string",
|
||||
"workspace_owner_id": "e7078695-5279-4c86-8774-3ac2367a2fc7",
|
||||
"workspace_owner_name": "string"
|
||||
},
|
||||
"name": "string",
|
||||
"outdated": true,
|
||||
"owner_id": "8826ee2e-7933-4665-aef2-2393f84a0d05",
|
||||
"owner_name": "string",
|
||||
"template_allow_user_cancel_workspace_jobs": true,
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_id": "c6d67e98-83ea-49f0-8812-e4abae2b68bc",
|
||||
"template_name": "string",
|
||||
"ttl_ms": 0,
|
||||
"updated_at": "2019-08-24T14:15:22Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | -------------------------------------------------- |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Workspace](schemas.md#codersdkworkspace) |
|
||||
|
||||
To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**.
|
||||
|
||||
## List workspaces
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/workspaces \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
|
||||
```
|
||||
|
||||
`GET /workspaces`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| --------- | ----- | ------ | -------- | ------------------------------------------- |
|
||||
| owner | query | string | false | Filter by owner username |
|
||||
| template | query | string | false | Filter by template name |
|
||||
| name | query | string | false | Filter with partial-match by workspace name |
|
||||
| status | query | string | false | Filter by workspace status |
|
||||
| has_agent | query | string | false | Filter by agent status |
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
| Parameter | Value |
|
||||
| --------- | ------------ |
|
||||
| status | pending |
|
||||
| status | running |
|
||||
| status | stopping |
|
||||
| status | stopped |
|
||||
| status | failed |
|
||||
| status | canceling |
|
||||
| status | canceled |
|
||||
| status | deleted |
|
||||
| status | deleting |
|
||||
| has_agent | connected |
|
||||
| has_agent | connecting |
|
||||
| has_agent | disconnected |
|
||||
| has_agent | timeout |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"count": 0,
|
||||
"workspaces": [
|
||||
{
|
||||
"autostart_schedule": "string",
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"last_used_at": "2019-08-24T14:15:22Z",
|
||||
"latest_build": {
|
||||
"build_number": 0,
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"daily_cost": 0,
|
||||
"deadline": {
|
||||
"time": "string",
|
||||
"valid": true
|
||||
},
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
|
||||
"initiator_name": "string",
|
||||
"job": {
|
||||
"canceled_at": "string",
|
||||
"completed_at": "string",
|
||||
"created_at": "string",
|
||||
"error": "string",
|
||||
"file_id": "string",
|
||||
"id": "string",
|
||||
"started_at": "string",
|
||||
"status": "string",
|
||||
"tags": {
|
||||
"property1": "string",
|
||||
"property2": "string"
|
||||
},
|
||||
"worker_id": "string"
|
||||
},
|
||||
"reason": "string",
|
||||
"resources": [
|
||||
{
|
||||
"agents": [
|
||||
{
|
||||
"apps": [
|
||||
{
|
||||
"command": "string",
|
||||
"display_name": "string",
|
||||
"external": true,
|
||||
"health": "string",
|
||||
"healthcheck": {},
|
||||
"icon": "string",
|
||||
"id": "string",
|
||||
"sharing_level": "string",
|
||||
"slug": "string",
|
||||
"subdomain": true,
|
||||
"url": "string"
|
||||
}
|
||||
],
|
||||
"architecture": "string",
|
||||
"connection_timeout_seconds": 0,
|
||||
"created_at": "string",
|
||||
"directory": "string",
|
||||
"disconnected_at": "string",
|
||||
"environment_variables": {
|
||||
"property1": "string",
|
||||
"property2": "string"
|
||||
},
|
||||
"first_connected_at": "string",
|
||||
"id": "string",
|
||||
"instance_id": "string",
|
||||
"last_connected_at": "string",
|
||||
"latency": {
|
||||
"property1": {
|
||||
"latency_ms": 0,
|
||||
"preferred": true
|
||||
},
|
||||
"property2": {
|
||||
"latency_ms": 0,
|
||||
"preferred": true
|
||||
}
|
||||
},
|
||||
"name": "string",
|
||||
"operating_system": "string",
|
||||
"resource_id": "string",
|
||||
"startup_script": "string",
|
||||
"status": "string",
|
||||
"troubleshooting_url": "string",
|
||||
"updated_at": "string",
|
||||
"version": "string"
|
||||
}
|
||||
],
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"daily_cost": 0,
|
||||
"hide": true,
|
||||
"icon": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"job_id": "453bd7d7-5355-4d6d-a38e-d9e7eb218c3f",
|
||||
"metadata": [
|
||||
{
|
||||
"key": "string",
|
||||
"sensitive": true,
|
||||
"value": "string"
|
||||
}
|
||||
],
|
||||
"name": "string",
|
||||
"type": "string",
|
||||
"workspace_transition": "start"
|
||||
}
|
||||
],
|
||||
"status": "pending",
|
||||
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
|
||||
"template_version_name": "string",
|
||||
"transition": "start",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"workspace_id": "0967198e-ec7b-4c6b-b4d3-f71244cadbe9",
|
||||
"workspace_name": "string",
|
||||
"workspace_owner_id": "e7078695-5279-4c86-8774-3ac2367a2fc7",
|
||||
"workspace_owner_name": "string"
|
||||
},
|
||||
"name": "string",
|
||||
"outdated": true,
|
||||
"owner_id": "8826ee2e-7933-4665-aef2-2393f84a0d05",
|
||||
"owner_name": "string",
|
||||
"template_allow_user_cancel_workspace_jobs": true,
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_id": "c6d67e98-83ea-49f0-8812-e4abae2b68bc",
|
||||
"template_name": "string",
|
||||
"ttl_ms": 0,
|
||||
"updated_at": "2019-08-24T14:15:22Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | -------------------------------------------------------------------- |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.WorkspacesResponse](schemas.md#codersdkworkspacesresponse) |
|
||||
|
||||
To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**.
|
||||
|
||||
## Get workspace metadata by ID
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/workspaces/{id} \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
|
||||
```
|
||||
|
||||
`GET /workspaces/{id}`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| --------------- | ----- | ------------ | -------- | ----------------------------------------------------------- |
|
||||
| id | path | string(uuid) | true | Workspace ID |
|
||||
| include_deleted | query | boolean | false | Return data instead of HTTP 404 if the workspace is deleted |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"autostart_schedule": "string",
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"last_used_at": "2019-08-24T14:15:22Z",
|
||||
"latest_build": {
|
||||
"build_number": 0,
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"daily_cost": 0,
|
||||
"deadline": {
|
||||
"time": "string",
|
||||
"valid": true
|
||||
},
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
|
||||
"initiator_name": "string",
|
||||
"job": {
|
||||
"canceled_at": "string",
|
||||
"completed_at": "string",
|
||||
"created_at": "string",
|
||||
"error": "string",
|
||||
"file_id": "string",
|
||||
"id": "string",
|
||||
"started_at": "string",
|
||||
"status": "string",
|
||||
"tags": {
|
||||
"property1": "string",
|
||||
"property2": "string"
|
||||
},
|
||||
"worker_id": "string"
|
||||
},
|
||||
"reason": "string",
|
||||
"resources": [
|
||||
{
|
||||
"agents": [
|
||||
{
|
||||
"apps": [
|
||||
{
|
||||
"command": "string",
|
||||
"display_name": "string",
|
||||
"external": true,
|
||||
"health": "string",
|
||||
"healthcheck": {
|
||||
"interval": 0,
|
||||
"threshold": 0,
|
||||
"url": "string"
|
||||
},
|
||||
"icon": "string",
|
||||
"id": "string",
|
||||
"sharing_level": "string",
|
||||
"slug": "string",
|
||||
"subdomain": true,
|
||||
"url": "string"
|
||||
}
|
||||
],
|
||||
"architecture": "string",
|
||||
"connection_timeout_seconds": 0,
|
||||
"created_at": "string",
|
||||
"directory": "string",
|
||||
"disconnected_at": "string",
|
||||
"environment_variables": {
|
||||
"property1": "string",
|
||||
"property2": "string"
|
||||
},
|
||||
"first_connected_at": "string",
|
||||
"id": "string",
|
||||
"instance_id": "string",
|
||||
"last_connected_at": "string",
|
||||
"latency": {
|
||||
"property1": {
|
||||
"latency_ms": 0,
|
||||
"preferred": true
|
||||
},
|
||||
"property2": {
|
||||
"latency_ms": 0,
|
||||
"preferred": true
|
||||
}
|
||||
},
|
||||
"name": "string",
|
||||
"operating_system": "string",
|
||||
"resource_id": "string",
|
||||
"startup_script": "string",
|
||||
"status": "string",
|
||||
"troubleshooting_url": "string",
|
||||
"updated_at": "string",
|
||||
"version": "string"
|
||||
}
|
||||
],
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"daily_cost": 0,
|
||||
"hide": true,
|
||||
"icon": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"job_id": "453bd7d7-5355-4d6d-a38e-d9e7eb218c3f",
|
||||
"metadata": [
|
||||
{
|
||||
"key": "string",
|
||||
"sensitive": true,
|
||||
"value": "string"
|
||||
}
|
||||
],
|
||||
"name": "string",
|
||||
"type": "string",
|
||||
"workspace_transition": "start"
|
||||
}
|
||||
],
|
||||
"status": "pending",
|
||||
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
|
||||
"template_version_name": "string",
|
||||
"transition": "start",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"workspace_id": "0967198e-ec7b-4c6b-b4d3-f71244cadbe9",
|
||||
"workspace_name": "string",
|
||||
"workspace_owner_id": "e7078695-5279-4c86-8774-3ac2367a2fc7",
|
||||
"workspace_owner_name": "string"
|
||||
},
|
||||
"name": "string",
|
||||
"outdated": true,
|
||||
"owner_id": "8826ee2e-7933-4665-aef2-2393f84a0d05",
|
||||
"owner_name": "string",
|
||||
"template_allow_user_cancel_workspace_jobs": true,
|
||||
"template_display_name": "string",
|
||||
"template_icon": "string",
|
||||
"template_id": "c6d67e98-83ea-49f0-8812-e4abae2b68bc",
|
||||
"template_name": "string",
|
||||
"ttl_ms": 0,
|
||||
"updated_at": "2019-08-24T14:15:22Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | -------------------------------------------------- |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Workspace](schemas.md#codersdkworkspace) |
|
||||
|
||||
To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**.
|
||||
|
||||
## Update workspace metadata by ID
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X PATCH http://coder-server:8080/api/v2/workspaces/{workspace} \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
|
||||
```
|
||||
|
||||
`PATCH /workspaces/{workspace}`
|
||||
|
||||
> Body parameter
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "string"
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| --------- | ---- | ---------------------------------------------------------------------------- | -------- | ----------------------- |
|
||||
| workspace | path | string(uuid) | true | Workspace ID |
|
||||
| body | body | [codersdk.UpdateWorkspaceRequest](schemas.md#codersdkupdateworkspacerequest) | true | Metadata update request |
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | --------------------------------------------------------------- | ----------- | --------- |
|
||||
| 204 | [No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5) | No Content | no schema |
|
||||
|
||||
To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**.
|
||||
|
||||
## Update workspace autostart schedule by ID
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X PUT http://coder-server:8080/api/v2/workspaces/{workspace}/autostart \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
|
||||
```
|
||||
|
||||
`PUT /workspaces/{workspace}/autostart`
|
||||
|
||||
> Body parameter
|
||||
|
||||
```json
|
||||
{
|
||||
"schedule": "string"
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| --------- | ---- | ---------------------------------------------------------------------------------------------- | -------- | ----------------------- |
|
||||
| workspace | path | string(uuid) | true | Workspace ID |
|
||||
| body | body | [codersdk.UpdateWorkspaceAutostartRequest](schemas.md#codersdkupdateworkspaceautostartrequest) | true | Schedule update request |
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | --------------------------------------------------------------- | ----------- | --------- |
|
||||
| 204 | [No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5) | No Content | no schema |
|
||||
|
||||
To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**.
|
||||
|
||||
## Extend workspace deadline by ID
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X PUT http://coder-server:8080/api/v2/workspaces/{workspace}/extend \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
|
||||
```
|
||||
|
||||
`PUT /workspaces/{workspace}/extend`
|
||||
|
||||
> Body parameter
|
||||
|
||||
```json
|
||||
{
|
||||
"deadline": "string"
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| --------- | ---- | ---------------------------------------------------------------------------------- | -------- | ------------------------------ |
|
||||
| workspace | path | string(uuid) | true | Workspace ID |
|
||||
| body | body | [codersdk.PutExtendWorkspaceRequest](schemas.md#codersdkputextendworkspacerequest) | true | Extend deadline update request |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "string",
|
||||
"message": "string",
|
||||
"validations": [
|
||||
{
|
||||
"detail": "string",
|
||||
"field": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------ |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Response](schemas.md#codersdkresponse) |
|
||||
|
||||
To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**.
|
||||
|
||||
## Update workspace TTL by ID
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X PUT http://coder-server:8080/api/v2/workspaces/{workspace}/ttl \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
|
||||
```
|
||||
|
||||
`PUT /workspaces/{workspace}/ttl`
|
||||
|
||||
> Body parameter
|
||||
|
||||
```json
|
||||
{
|
||||
"ttl_ms": 0
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| --------- | ---- | ---------------------------------------------------------------------------------- | -------- | ---------------------------- |
|
||||
| workspace | path | string(uuid) | true | Workspace ID |
|
||||
| body | body | [codersdk.UpdateWorkspaceTTLRequest](schemas.md#codersdkupdateworkspacettlrequest) | true | Workspace TTL update request |
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | --------------------------------------------------------------- | ----------- | --------- |
|
||||
| 204 | [No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5) | No Content | no schema |
|
||||
|
||||
To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**.
|
||||
|
||||
## Watch workspace by ID
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace}/watch \
|
||||
-H 'Accept: text/event-stream' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
|
||||
```
|
||||
|
||||
`GET /workspaces/{workspace}/watch`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
| --------- | ---- | ------------ | -------- | ------------ |
|
||||
| workspace | path | string(uuid) | true | Workspace ID |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
| ------ | ------------------------------------------------------- | ----------- | ------------------------------------------------ |
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Response](schemas.md#codersdkresponse) |
|
||||
|
||||
To perform this operation, you must be authenticated by means of one of the following methods: **CoderSessionToken**.
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="20" width="20"><path d="m10 12-2-2 2-2 2 2ZM8.208 6.792l-2-2L10 1l3.792 3.792-2 2L10 5Zm-3.416 7L1 10l3.792-3.792 2 2L5 10l1.792 1.792Zm10.416 0-2-2L15 10l-1.792-1.792 2-2L19 10ZM10 19l-3.792-3.792 2-2L10 15l1.792-1.792 2 2Z"/></svg>
|
After Width: | Height: | Size: 281 B |
|
@ -10,16 +10,16 @@
|
|||
{
|
||||
"title": "Architecture",
|
||||
"description": "Learn how Coder works",
|
||||
"icon_path": "./images/icons/protractor.svg",
|
||||
"path": "./about/architecture.md"
|
||||
"path": "./about/architecture.md",
|
||||
"icon_path": "./images/icons/protractor.svg"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Installation",
|
||||
"description": "How to install and deploy Coder",
|
||||
"icon_path": "./images/icons/download.svg",
|
||||
"path": "./install/index.md",
|
||||
"icon_path": "./images/icons/download.svg",
|
||||
"children": [
|
||||
{
|
||||
"title": "Install script",
|
||||
|
@ -66,32 +66,32 @@
|
|||
{
|
||||
"title": "Quickstart",
|
||||
"description": "Create your first template and workspace",
|
||||
"icon_path": "./images/icons/star.svg",
|
||||
"path": "./quickstart.md",
|
||||
"icon_path": "./images/icons/star.svg",
|
||||
"children": [
|
||||
{
|
||||
"title": "Docker",
|
||||
"description": "Setup Coder with Docker",
|
||||
"icon_path": "./images/icons/docker.svg",
|
||||
"path": "./quickstart/docker.md"
|
||||
"path": "./quickstart/docker.md",
|
||||
"icon_path": "./images/icons/docker.svg"
|
||||
},
|
||||
{
|
||||
"title": "Google Cloud Platform",
|
||||
"description": "Setup Coder on a GCP Compute Engine VM",
|
||||
"icon_path": "./images/google-cloud.svg",
|
||||
"path": "./quickstart/google-cloud-platform.md"
|
||||
"path": "./quickstart/google-cloud-platform.md",
|
||||
"icon_path": "./images/google-cloud.svg"
|
||||
},
|
||||
{
|
||||
"title": "AWS",
|
||||
"description": "Setup Coder on an AWS EC2 VM",
|
||||
"icon_path": "./images/aws.svg",
|
||||
"path": "./quickstart/aws.md"
|
||||
"path": "./quickstart/aws.md",
|
||||
"icon_path": "./images/aws.svg"
|
||||
},
|
||||
{
|
||||
"title": "Azure",
|
||||
"description": "Setup Coder on an Azure VM",
|
||||
"icon_path": "./images/azure.svg",
|
||||
"path": "./quickstart/azure.md"
|
||||
"path": "./quickstart/azure.md",
|
||||
"icon_path": "./images/azure.svg"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -105,8 +105,7 @@
|
|||
"title": "Resource Persistence",
|
||||
"description": "Learn how resource persistence works in Coder",
|
||||
"path": "./templates/resource-persistence.md",
|
||||
"icon_path": "./images/icons/infinity.svg",
|
||||
"last_updated": "2022-10-23"
|
||||
"icon_path": "./images/icons/infinity.svg"
|
||||
},
|
||||
{
|
||||
"title": "Provider Authentication",
|
||||
|
@ -137,8 +136,8 @@
|
|||
{
|
||||
"title": "Workspaces",
|
||||
"description": "Learn about Coder workspaces.",
|
||||
"icon_path": "./images/icons/layers.svg",
|
||||
"path": "./workspaces.md"
|
||||
"path": "./workspaces.md",
|
||||
"icon_path": "./images/icons/layers.svg"
|
||||
},
|
||||
{
|
||||
"title": "IDEs",
|
||||
|
@ -184,45 +183,45 @@
|
|||
{
|
||||
"title": "Dotfiles",
|
||||
"description": "Learn how to personalize your workspace",
|
||||
"icon_path": "./images/icons/art-pad.svg",
|
||||
"path": "./dotfiles.md"
|
||||
"path": "./dotfiles.md",
|
||||
"icon_path": "./images/icons/art-pad.svg"
|
||||
},
|
||||
{
|
||||
"title": "Secrets",
|
||||
"description": "Learn how to use secrets in your worskpace",
|
||||
"icon_path": "./images/icons/secrets.svg",
|
||||
"path": "./secrets.md"
|
||||
"description": "Learn how to use secrets in your workspace",
|
||||
"path": "./secrets.md",
|
||||
"icon_path": "./images/icons/secrets.svg"
|
||||
},
|
||||
{
|
||||
"title": "Administration",
|
||||
"description": "How to install and deploy Coder",
|
||||
"icon_path": "./images/icons/wrench.svg",
|
||||
"path": "./admin/index.md",
|
||||
"icon_path": "./images/icons/wrench.svg",
|
||||
"children": [
|
||||
{
|
||||
"title": "Authentication",
|
||||
"description": "Learn how to set up authentication using GitHub or OpenID Connect",
|
||||
"icon_path": "./images/icons/key.svg",
|
||||
"path": "./admin/auth.md"
|
||||
"path": "./admin/auth.md",
|
||||
"icon_path": "./images/icons/key.svg"
|
||||
},
|
||||
{
|
||||
"title": "Users",
|
||||
"description": "Learn about user roles available in Coder and how to create and manage users",
|
||||
"icon_path": "./images/icons/users.svg",
|
||||
"path": "./admin/users.md"
|
||||
"path": "./admin/users.md",
|
||||
"icon_path": "./images/icons/users.svg"
|
||||
},
|
||||
{
|
||||
"title": "Groups",
|
||||
"description": "Learn how to manage user groups",
|
||||
"icon_path": "./images/icons/group.svg",
|
||||
"path": "./admin/groups.md",
|
||||
"icon_path": "./images/icons/group.svg",
|
||||
"state": "enterprise"
|
||||
},
|
||||
{
|
||||
"title": "RBAC",
|
||||
"description": "Learn how to use the role based access control",
|
||||
"icon_path": "./images/icons/rbac.svg",
|
||||
"path": "./admin/rbac.md",
|
||||
"icon_path": "./images/icons/rbac.svg",
|
||||
"state": "enterprise"
|
||||
},
|
||||
{
|
||||
|
@ -234,74 +233,74 @@
|
|||
{
|
||||
"title": "Git Providers",
|
||||
"description": "Learn how connect Coder with external git providers",
|
||||
"icon_path": "./images/icons/git.svg",
|
||||
"path": "./admin/git-providers.md"
|
||||
"path": "./admin/git-providers.md",
|
||||
"icon_path": "./images/icons/git.svg"
|
||||
},
|
||||
{
|
||||
"title": "Upgrading",
|
||||
"description": "Learn how to upgrade Coder",
|
||||
"icon_path": "./images/icons/upgrade.svg",
|
||||
"path": "./admin/upgrade.md"
|
||||
"path": "./admin/upgrade.md",
|
||||
"icon_path": "./images/icons/upgrade.svg"
|
||||
},
|
||||
{
|
||||
"title": "Automation",
|
||||
"description": "Learn how to automate Coder with the CLI and API",
|
||||
"icon_path": "./images/icons/plug.svg",
|
||||
"path": "./admin/automation.md"
|
||||
"path": "./admin/automation.md",
|
||||
"icon_path": "./images/icons/plug.svg"
|
||||
},
|
||||
{
|
||||
"title": "Audit Logs",
|
||||
"description": "Learn how to use Audit Logs in your Coder deployment",
|
||||
"icon_path": "./images/icons/radar.svg",
|
||||
"path": "./admin/audit-logs.md",
|
||||
"icon_path": "./images/icons/radar.svg",
|
||||
"state": "enterprise"
|
||||
},
|
||||
{
|
||||
"title": "Quotas",
|
||||
"description": "Learn how to use Workspace Quotas in Coder",
|
||||
"icon_path": "./images/icons/dollar.svg",
|
||||
"path": "./admin/quotas.md",
|
||||
"icon_path": "./images/icons/dollar.svg",
|
||||
"state": "enterprise"
|
||||
},
|
||||
{
|
||||
"title": "High Availability",
|
||||
"description": "Learn how to configure Coder for High Availability",
|
||||
"icon_path": "./images/icons/hydra.svg",
|
||||
"path": "./admin/high-availability.md",
|
||||
"icon_path": "./images/icons/hydra.svg",
|
||||
"state": "enterprise"
|
||||
},
|
||||
{
|
||||
"title": "Prometheus",
|
||||
"description": "Learn how to collect Prometheus metrics",
|
||||
"icon_path": "./images/icons/speed.svg",
|
||||
"path": "./admin/prometheus.md"
|
||||
"path": "./admin/prometheus.md",
|
||||
"icon_path": "./images/icons/speed.svg"
|
||||
},
|
||||
{
|
||||
"title": "Service Banners",
|
||||
"description": "Learn how to configure Service Banners",
|
||||
"icon_path": "./images/icons/info.svg",
|
||||
"path": "./admin/service-banners.md",
|
||||
"icon_path": "./images/icons/info.svg",
|
||||
"state": "enterprise"
|
||||
},
|
||||
{
|
||||
"title": "Telemetry",
|
||||
"description": "Learn what usage telemetry Coder collects",
|
||||
"icon_path": "./images/icons/science.svg",
|
||||
"path": "./admin/telemetry.md"
|
||||
"path": "./admin/telemetry.md",
|
||||
"icon_path": "./images/icons/science.svg"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Enterprise",
|
||||
"description": "Learn how to enable Enterprise features",
|
||||
"icon_path": "./images/icons/group.svg",
|
||||
"path": "./enterprise.md"
|
||||
"path": "./enterprise.md",
|
||||
"icon_path": "./images/icons/group.svg"
|
||||
},
|
||||
{
|
||||
"title": "Contributing",
|
||||
"description": "Learn how to contribute to Coder",
|
||||
"icon_path": "./images/icons/contributing.svg",
|
||||
"path": "./CONTRIBUTING.md",
|
||||
"icon_path": "./images/icons/contributing.svg",
|
||||
"children": [
|
||||
{
|
||||
"title": "Code of Conduct",
|
||||
|
@ -319,6 +318,30 @@
|
|||
"path": "./contributing/SECURITY.md"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "API",
|
||||
"description": "Learn how to use Coderd API",
|
||||
"path": "./api/index.md",
|
||||
"icon_path": "./images/icons/api.svg",
|
||||
"children": [
|
||||
{
|
||||
"title": "Authentication",
|
||||
"path": "./api/authentication.md"
|
||||
},
|
||||
{
|
||||
"title": "Templates",
|
||||
"path": "./api/templates.md"
|
||||
},
|
||||
{
|
||||
"title": "Workspaces",
|
||||
"path": "./api/workspaces.md"
|
||||
},
|
||||
{
|
||||
"title": "Schemas",
|
||||
"path": "./api/schemas.md"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
10
go.mod
10
go.mod
|
@ -125,6 +125,8 @@ require (
|
|||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.14.0
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/swaggo/http-swagger v1.3.3
|
||||
github.com/swaggo/swag v1.8.6
|
||||
github.com/tabbed/pqtype v0.1.1
|
||||
github.com/u-root/u-root v0.10.0
|
||||
github.com/unrolled/secure v1.13.0
|
||||
|
@ -169,6 +171,7 @@ require (
|
|||
cloud.google.com/go/compute v1.12.1 // indirect
|
||||
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
||||
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
||||
|
@ -203,6 +206,10 @@ require (
|
|||
github.com/gin-gonic/gin v1.7.0 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
||||
github.com/go-openapi/spec v0.20.6 // indirect
|
||||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/go-playground/locales v0.14.0 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 // indirect
|
||||
|
@ -226,6 +233,7 @@ require (
|
|||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||
github.com/insomniacslk/dhcp v0.0.0-20211209223715-7d93572ebe8e // indirect
|
||||
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/josharian/native v1.0.0 // indirect
|
||||
github.com/jsimonetti/rtnetlink v1.1.2-0.20220408201609-d380b505068b // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
|
@ -234,6 +242,7 @@ require (
|
|||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
|
@ -268,6 +277,7 @@ require (
|
|||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/subosito/gotenv v1.4.1 // indirect
|
||||
github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe // indirect
|
||||
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect
|
||||
github.com/tailscale/certstore v0.1.1-0.20220316223106-78d6e1c49d8d // indirect
|
||||
github.com/tailscale/golang-x-crypto v0.0.0-20221102133106-bc99ab8c2d17 // indirect
|
||||
|
|
17
go.sum
17
go.sum
|
@ -114,6 +114,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
|
|||
github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
|
@ -674,17 +676,24 @@ github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiU
|
|||
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
|
||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
|
||||
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
|
||||
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
|
||||
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||
github.com/go-openapi/spec v0.20.6 h1:ich1RQ3WDbfoeTqTAb+5EIxNmpKVJZWBNah9RAT0jIQ=
|
||||
github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
|
||||
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
|
||||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw=
|
||||
github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
|
@ -1121,6 +1130,7 @@ github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqx
|
|||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk=
|
||||
github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
|
@ -1246,6 +1256,7 @@ github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN
|
|||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU=
|
||||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
||||
|
@ -1722,6 +1733,12 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69
|
|||
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
|
||||
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
github.com/swaggest/assertjson v1.7.0 h1:SKw5Rn0LQs6UvmGrIdaKQbMR1R3ncXm5KNon+QJ7jtw=
|
||||
github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe h1:K8pHPVoTgxFJt1lXuIzzOX7zZhZFldJQK/CgKx9BFIc=
|
||||
github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w=
|
||||
github.com/swaggo/http-swagger v1.3.3 h1:Hu5Z0L9ssyBLofaama21iYaF2VbWyA8jdohaaCGpHsc=
|
||||
github.com/swaggo/http-swagger v1.3.3/go.mod h1:sE+4PjD89IxMPm77FnkDz0sdO+p5lbXzrVWT6OTVVGo=
|
||||
github.com/swaggo/swag v1.8.6 h1:2rgOaLbonWu1PLP6G+/rYjSvPg0jQE0HtrEKuE380eg=
|
||||
github.com/swaggo/swag v1.8.6/go.mod h1:jMLeXOOmYyjk8PvHTsXBdrubsNd9gUJTTCzL5iBnseg=
|
||||
github.com/sylvia7788/contextcheck v1.0.4/go.mod h1:vuPKJMQ7MQ91ZTqfdyreNKwZjyUg6KO+IebVyQDedZQ=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# This script generates swagger description file and required Go docs files
|
||||
# from the coderd API.
|
||||
|
||||
set -euo pipefail
|
||||
# shellcheck source=scripts/lib.sh
|
||||
source "$(dirname "$(dirname "${BASH_SOURCE[0]}")")/lib.sh"
|
||||
|
||||
APIDOCGEN_DIR=$(dirname "${BASH_SOURCE[0]}")
|
||||
API_MD_TMP_FILE=$(mktemp /tmp/coder-apidocgen.XXXXXX)
|
||||
|
||||
cleanup() {
|
||||
rm -f "${API_MD_TMP_FILE}"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
log "Use temporary file: ${API_MD_TMP_FILE}"
|
||||
|
||||
pushd "${PROJECT_ROOT}"
|
||||
go run github.com/swaggo/swag/cmd/swag@v1.8.6 init \
|
||||
--generalInfo="coderd.go" \
|
||||
--dir="./coderd,./codersdk" \
|
||||
--output="./coderd/apidoc" \
|
||||
--outputTypes="go,json" \
|
||||
--parseDependency=true
|
||||
popd
|
||||
|
||||
pushd "${APIDOCGEN_DIR}"
|
||||
npm ci
|
||||
|
||||
# Make sure that widdershins is installed correctly.
|
||||
npm exec -- widdershins --version
|
||||
# Render the Markdown file.
|
||||
npm exec -- widdershins \
|
||||
--user_templates "./markdown-template" \
|
||||
--search false \
|
||||
--omitHeader true \
|
||||
--language_tabs "shell:curl" \
|
||||
--summary "../../coderd/apidoc/swagger.json" \
|
||||
--outfile "${API_MD_TMP_FILE}"
|
||||
# Perform the postprocessing
|
||||
go run postprocess/main.go -in-md-file-single "${API_MD_TMP_FILE}"
|
||||
popd
|
|
@ -0,0 +1,64 @@
|
|||
## Swagger / OpenAPI 2 and OpenAPI 3 template parameters
|
||||
|
||||
Note that properties of OpenAPI objects will be in OpenAPI 3.0 form, as
|
||||
Swagger / OpenAPI 2.0 definitions are converted automatically.
|
||||
|
||||
### Code templates
|
||||
|
||||
* `method` - the HTTP method of the operation (in lower-case)
|
||||
* `methodUpper` - the HTTP method of the operation (in upper-case)
|
||||
* `url` - the full URL of the operation (including protocol and host)
|
||||
* `consumes[]` - an array of MIME-types the operation consumes
|
||||
* `produces[]` - an array of MIME-types the operation produces
|
||||
* `operation` - the current operation object
|
||||
* `operationId` - the current operation id
|
||||
* `opName` - the operationId if set, otherwise the method + path
|
||||
* `tags[]` - the full list of tags applying to the operation
|
||||
* `security` - the security definitions applying to the operation
|
||||
* `resource` - the current tag/path object
|
||||
* `parameters[]` - an array of parameters for the operation (see below)
|
||||
* `queryString` - an example queryString, urlEncoded
|
||||
* `requiredQueryString` - an example queryString for `required:true` parameters
|
||||
* `queryParameters[]` - a subset of `parameters` that are `in:query`
|
||||
* `requiredParameters[]` - a subset of `queryParameters` that are `required:true`
|
||||
* `headerParameters[]` - a subset of `parameters` that are `in:header`
|
||||
* `allHeaders[]` - a concatenation of `headerParameters` and pseudo-parameters `Accept` and `Content-Type`, and optionally `Authorization` (the latter has an `isAuth` boolean property set true so it can be omitted in templates if desired
|
||||
|
||||
### Parameter template
|
||||
|
||||
* `parameters[]` - an array of [parameters](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#parameterObject), including the following pseudo-properties
|
||||
* `shortDesc` - a truncated version of the parameter description
|
||||
* `safeType` - a computed version of the parameter type, including Body and schema names
|
||||
* `originalType` - the original type of the parameter
|
||||
* `exampleValues` - an object containing examples for use in code-templates
|
||||
* `json` - example values in JSON compatible syntax
|
||||
* `object` - example values in raw object form (unquoted strings etc)
|
||||
* `depth` - a zero-based indicator of the depth of expanded request body parameters
|
||||
* `enums[]` - an array of (parameter)name/value pairs
|
||||
|
||||
### Responses template
|
||||
|
||||
* `responses[]` - an array of [responses](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#responseObject), including `status` and `meaning` properties
|
||||
|
||||
### Authentication template
|
||||
|
||||
* `authenticationStr` - a simple string of methods (and scopes where appropriate)
|
||||
* `securityDefinitions[]` - an array of applicable [securityDefinitions](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#securityRequirementObject)
|
||||
|
||||
### Schema Property template
|
||||
|
||||
* `schemaProperties[]` - an array of
|
||||
* `name`
|
||||
* `type`
|
||||
* `required`
|
||||
* `description`
|
||||
* `enums[]` - an array of (schema property)name/value pairs
|
||||
|
||||
### Common to all templates
|
||||
|
||||
* `openapi` - the top-level OpenAPI / Swagger document
|
||||
* `header` - the front-matter of the Slate/Shins markdown document
|
||||
* `host` - the (computed) host of the API
|
||||
* `protocol` - the default/first protocol of the API
|
||||
* `baseUrl` - the (computed) baseUrl of the API (including protocol and host)
|
||||
* `widdershins` - the contents of widdershins `package.json`
|
|
@ -0,0 +1 @@
|
|||
To perform this operation, you must be authenticated by means of one of the following methods: **{{= data.utils.getAuthenticationStr(data) }}**.
|
|
@ -0,0 +1,4 @@
|
|||
# Example request using curl
|
||||
curl -X {{=data.methodUpper}} http://coder-server:8080{{=data.url}}{{=data.requiredQueryString}}{{?data.allHeaders.length}} \{{?}}
|
||||
{{~data.allHeaders :p:index}} -H '{{=p.name}}: {{=p.exampleValues.object}}'{{?index < data.allHeaders.length-1}} \{{?}}
|
||||
{{~}}
|
|
@ -0,0 +1 @@
|
|||
{{= data.utils.inspect(data) }}
|
|
@ -0,0 +1,157 @@
|
|||
{{
|
||||
function renderSinglePropertyType(p) {
|
||||
if (!p.$ref) {
|
||||
return p.type;
|
||||
}
|
||||
|
||||
const pRef = p.$ref.replace("#/components/schemas/","");
|
||||
if (pRef == "codersdk.NullTime") {
|
||||
return "string(time) or `null`";
|
||||
}
|
||||
return "[" + pRef + "](#" + pRef.replace(".","").toLowerCase() + ")";
|
||||
}
|
||||
|
||||
function renderPropertyType(p) {
|
||||
if (p.type == "array") {
|
||||
return "array of " + renderSinglePropertyType(p.schema.items);
|
||||
}
|
||||
return renderSinglePropertyType(p);
|
||||
}
|
||||
|
||||
function renderDisplayName(p) {
|
||||
if (p.displayName == "» **additionalProperties**") {
|
||||
return "» `[any property]`";
|
||||
}
|
||||
if (p.displayName == "**additionalProperties**") {
|
||||
return "`[any property]`";
|
||||
}
|
||||
return "`" + p.displayName + "`";
|
||||
}
|
||||
|
||||
function renderDescription(p) {
|
||||
if (!p.description) {
|
||||
return "none";
|
||||
}
|
||||
|
||||
const toSnakeCase = str =>
|
||||
str
|
||||
.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
|
||||
.map(x => x.toLowerCase())
|
||||
.join('_');
|
||||
|
||||
const words = p.description.split(' ');
|
||||
if (words.length == 0) {
|
||||
return "none";
|
||||
}
|
||||
|
||||
const countUppercase = words[0].length - words[0].replace(/[A-Z]/g, '').length;
|
||||
if (countUppercase > 1) {
|
||||
const displayName = p.displayName.charAt(0).toUpperCase() + p.displayName.replaceAll("_", " ").toLowerCase().slice(1);
|
||||
return displayName + " " + words.slice(1).join(' ');
|
||||
}
|
||||
return p.description;
|
||||
}
|
||||
}}
|
||||
|
||||
{{? data.api.components && data.api.components.securitySchemes }}{{#def.security}}{{?}}
|
||||
|
||||
{{ for (var r in data.resources) { }}
|
||||
{{ data.resource = data.resources[r]; }}
|
||||
|
||||
<!-- APIDOCGEN: BEGIN SECTION -->
|
||||
{{= data.tags.section }}# {{= r}}
|
||||
|
||||
> This page is incomplete, stay tuned.
|
||||
|
||||
{{? data.resource.description }}{{= data.resource.description}}{{?}}
|
||||
|
||||
{{ for (var m in data.resource.methods) { }}
|
||||
{{ data.operationUniqueName = m; }}
|
||||
{{ data.method = data.resource.methods[m]; }}
|
||||
{{ data.operationUniqueSlug = data.method.slug; }}
|
||||
{{ data.operation = data.method.operation; }}
|
||||
{{= data.templates.operation(data) }}
|
||||
{{ } /* of methods */ }}
|
||||
|
||||
{{= data.tags.endSection }}
|
||||
{{ } /* of resources */ }}
|
||||
|
||||
{{? data.api.components && data.api.components.schemas }}
|
||||
{{= data.tags.section }}
|
||||
|
||||
<!-- APIDOCGEN: BEGIN SECTION -->
|
||||
# Schemas
|
||||
|
||||
> This page is incomplete, stay tuned.
|
||||
|
||||
{{ for (var s in data.components.schemas) {
|
||||
if (s == "codersdk.NullTime") {
|
||||
continue;
|
||||
}
|
||||
}}
|
||||
{{ var origSchema = data.components.schemas[s]; }}
|
||||
{{ var schema = data.api.components.schemas[s]; }}
|
||||
|
||||
{{= data.tags.section }}
|
||||
## {{=s}}
|
||||
|
||||
{{? data.options.yaml }}
|
||||
```yaml
|
||||
{{=data.utils.yaml.stringify(data.utils.getSample(schema,data.options,{quiet:true},data.api))}}
|
||||
{{??}}
|
||||
```json
|
||||
{{=data.utils.safejson(data.utils.getSample(schema,data.options,{quiet:true},data.api),null,2)}}
|
||||
{{?}}```
|
||||
|
||||
{{ var enums = []; }}
|
||||
{{ var blocks = data.utils.schemaToArray(origSchema,-1,{trim:true,join:true},data); }}
|
||||
{{ for (var block of blocks) {
|
||||
for (var p of block.rows) {
|
||||
if (p.schema && p.schema.enum) {
|
||||
for (var e of p.schema.enum) {
|
||||
enums.push({name:p.name,value:e});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
{{~ blocks :block}}
|
||||
{{? block.title }}{{= block.title}}{{= '\n\n'}}{{?}}
|
||||
{{? block.externalDocs}}
|
||||
<a href="{{=block.externalDocs.url}}">{{=block.externalDocs.description||'External documentation'}}</a>
|
||||
{{?}}
|
||||
|
||||
{{? block===blocks[0] }}
|
||||
{{= data.tags.section }}
|
||||
|
||||
### Properties
|
||||
{{?}}
|
||||
|
||||
{{? block.rows.length}}|Name|Type|Required|Restrictions|Description|
|
||||
|---|---|---|---|---|{{?}}
|
||||
{{~ block.rows :p}}|{{= renderDisplayName(p)}}|{{= renderPropertyType(p)}}|{{=p.required}}|{{=p.restrictions||'none'}}|{{= renderDescription(p)}}|
|
||||
{{~}}
|
||||
{{~}}
|
||||
{{? (blocks[0].rows.length === 0) && (blocks.length === 1) }}
|
||||
*None*
|
||||
{{?}}
|
||||
|
||||
{{? enums.length > 0 }}
|
||||
{{= data.tags.section }}
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
|Property|Value|
|
||||
|---|---|
|
||||
{{~ enums :e}}|{{=e.name}}|{{=data.utils.toPrimitive(e.value)}}|
|
||||
{{~}}
|
||||
|
||||
{{= data.tags.endSection }}
|
||||
{{?}}
|
||||
|
||||
{{= data.tags.endSection }}
|
||||
{{= data.tags.endSection }}
|
||||
{{ } /* of schemas */ }}
|
||||
|
||||
{{?}}
|
|
@ -0,0 +1,48 @@
|
|||
{{= data.tags.section }}
|
||||
|
||||
## {{= data.operationUniqueName}}
|
||||
|
||||
{{ data.methodUpper = data.method.verb.toUpperCase(); }}
|
||||
{{ data.url = data.utils.slashes(data.baseUrl + data.method.path); }}
|
||||
{{ data.parameters = data.operation.parameters; }}
|
||||
{{ data.enums = []; }}
|
||||
{{ data.utils.fakeProdCons(data); }}
|
||||
{{ data.utils.fakeBodyParameter(data); }}
|
||||
{{ data.utils.mergePathParameters(data); }}
|
||||
{{ data.utils.getParameters(data); }}
|
||||
|
||||
{{? data.options.codeSamples || data.operation["x-code-samples"] }}
|
||||
### Code samples
|
||||
|
||||
{{= data.utils.getCodeSamples(data)}}
|
||||
{{?}}
|
||||
|
||||
`{{= data.methodUpper}} {{=data.method.path}}`
|
||||
|
||||
{{? data.operation.summary && !data.options.tocSummary}}*{{= data.operation.summary }}*{{?}}
|
||||
|
||||
{{? data.operation.description}}{{= data.operation.description }}{{?}}
|
||||
|
||||
{{? data.operation.requestBody}}
|
||||
> Body parameter
|
||||
|
||||
{{? data.bodyParameter.exampleValues.description }}
|
||||
> {{= data.bodyParameter.exampleValues.description }}
|
||||
{{?}}
|
||||
|
||||
{{= data.utils.getBodyParameterExamples(data) }}
|
||||
{{?}}
|
||||
|
||||
{{? data.parameters && data.parameters.length }}
|
||||
{{#def.parameters}}
|
||||
{{?}}
|
||||
|
||||
{{#def.responses}}
|
||||
|
||||
{{ data.security = data.operation.security ? data.operation.security : data.api.security; }}
|
||||
{{? data.security && data.security.length }}
|
||||
{{#def.authentication}}
|
||||
{{??}}
|
||||
{{#def.authentication_none}}
|
||||
{{?}}
|
||||
{{= data.tags.endSection }}
|
|
@ -0,0 +1,50 @@
|
|||
{{
|
||||
function renderParameterType(p) {
|
||||
if (p.schema['x-widdershins-oldRef']) {
|
||||
const aType = p.schema['x-widdershins-oldRef'].replace("#/components/schemas/","");
|
||||
const href = aType.replace(".","").toLowerCase();
|
||||
return "[" + aType + "](schemas.md#" + href + ")";
|
||||
}
|
||||
return p.safeType;
|
||||
}
|
||||
}}
|
||||
{{= data.tags.section }}
|
||||
### Parameters
|
||||
|
||||
|Name|In|Type|Required|Description|
|
||||
|---|---|---|---|---|
|
||||
{{~ data.parameters :p}}|{{=p.name}}|{{=p.in}}|{{= renderParameterType(p)}}|{{=p.required}}|{{=p.shortDesc || 'none'}}|
|
||||
{{~}}
|
||||
|
||||
{{? data.longDescs }}
|
||||
#### Detailed descriptions
|
||||
{{~ data.parameters :p}}{{? p.shortDesc !== p.description}}
|
||||
**{{=p.name}}**: {{=p.description}}{{?}}
|
||||
{{~}}
|
||||
{{?}}
|
||||
|
||||
{{~ data.parameters :p}}
|
||||
|
||||
{{? p.schema && p.schema.enum }}
|
||||
{{~ p.schema.enum :e}}
|
||||
{{ var entry = {}; entry.name = p.name; entry.value = e; data.enums.push(entry); }}
|
||||
{{~}}
|
||||
{{?}}
|
||||
|
||||
{{? p.schema && p.schema.items && p.schema.items.enum }}
|
||||
{{~ p.schema.items.enum :e}}
|
||||
{{ var entry = {}; entry.name = p.name; entry.value = e; data.enums.push(entry); }}
|
||||
{{~}}
|
||||
{{?}}
|
||||
|
||||
{{~}}
|
||||
|
||||
{{? data.enums && data.enums.length }}
|
||||
#### Enumerated Values
|
||||
|
||||
|Parameter|Value|
|
||||
|---|---|
|
||||
{{~ data.enums :e}}|{{=e.name}}|{{=data.utils.toPrimitive(e.value)}}|
|
||||
{{~}}
|
||||
{{?}}
|
||||
{{= data.tags.endSection }}
|
|
@ -0,0 +1,113 @@
|
|||
{{
|
||||
function renderSingleResponseType(r) {
|
||||
var content;
|
||||
for (var ct in r.content) {
|
||||
content = r.content[ct];
|
||||
break;
|
||||
}
|
||||
if (!content) {
|
||||
return "no schema";
|
||||
}
|
||||
|
||||
var ref = content.schema["x-widdershins-oldRef"];
|
||||
if (!ref) {
|
||||
ref = content.schema.items["x-widdershins-oldRef"];
|
||||
}
|
||||
const aType = ref.replace("#/components/schemas/","");
|
||||
const href = aType.replace(".","").toLowerCase();
|
||||
return "[" + aType + "](schemas.md#" + href + ")";
|
||||
}
|
||||
|
||||
function renderResponseType(r) {
|
||||
if (r.type == "array") {
|
||||
return "array of " + renderSingleResponseType(r);
|
||||
}
|
||||
return renderSingleResponseType(r);
|
||||
}
|
||||
}}
|
||||
{{ data.responses = data.utils.getResponses(data); }}
|
||||
{{ data.responseSchemas = false; }}
|
||||
{{~ data.responses :response }}
|
||||
{{ if (response.content) data.responseSchemas = true; }}
|
||||
{{~}}
|
||||
|
||||
{{? data.responseSchemas }}
|
||||
### Example responses
|
||||
|
||||
{{= data.utils.getResponseExamples(data) }}
|
||||
{{?}}
|
||||
|
||||
{{= data.tags.section }}
|
||||
### Responses
|
||||
|
||||
|Status|Meaning|Description|Schema|
|
||||
|---|---|---|---|
|
||||
{{~ data.responses :r}}|{{=r.status}}|{{=r.meaning}}|{{=r.description || 'none'}}|{{= renderResponseType(r)}}|
|
||||
{{~}}
|
||||
|
||||
{{ data.responseSchemas = false; }}
|
||||
{{~ data.responses :response }}
|
||||
{{ if (response.content && !response.$ref && !data.utils.isPrimitive(response.type)) data.responseSchemas = true; }}
|
||||
{{~}}
|
||||
{{? data.responseSchemas }}
|
||||
<h3 id="{{=data.operationUniqueSlug}}-responseschema">Response Schema</h3>
|
||||
{{~ data.responses :response}}
|
||||
{{? response.content && !response.$ref && !data.utils.isPrimitive(response.type)}}
|
||||
{{? Object.keys(response.content).length }}
|
||||
{{ var responseKey = Object.keys(response.content)[0]; }}
|
||||
{{ var responseSchema = response.content[responseKey].schema; }}
|
||||
{{ var enums = []; }}
|
||||
{{ var blocks = data.utils.schemaToArray(responseSchema,0,{trim:true,join:true},data); }}
|
||||
{{ for (var block of blocks) {
|
||||
for (var p of block.rows) {
|
||||
if (p.schema && p.schema.enum) {
|
||||
for (var e of p.schema.enum) {
|
||||
enums.push({name:p.name,value:e});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
{{? blocks[0].rows.length || blocks[0].title }}
|
||||
Status Code **{{=response.status}}**
|
||||
|
||||
{{~ blocks :block}}
|
||||
{{? block.title }}*{{=block.title}}*
|
||||
{{?}}
|
||||
|Name|Type|Required|Restrictions|Description|
|
||||
|---|---|---|---|---|
|
||||
{{~block.rows :p}}|{{=p.displayName}}|{{? p.$ref}}`{{=p.$ref}}`{{?}}{{? !p.$ref}}{{=p.type}}{{?}}|{{=p.required}}|{{=p.restrictions||'none'}}|{{=p.description||'none'}}|
|
||||
{{~}}
|
||||
{{~}}
|
||||
{{?}}
|
||||
|
||||
{{? enums.length > 0 }}
|
||||
#### Enumerated Values
|
||||
|
||||
|Property|Value|
|
||||
|---|---|
|
||||
{{~ enums :e}}|{{=e.name}}|{{=data.utils.toPrimitive(e.value)}}|
|
||||
{{~}}
|
||||
|
||||
{{?}}
|
||||
{{?}}
|
||||
|
||||
{{ data.response = response; }}
|
||||
|
||||
{{?}}
|
||||
{{~}}
|
||||
{{?}}
|
||||
|
||||
{{ data.responseHeaders = data.utils.getResponseHeaders(data); }}
|
||||
{{? data.responseHeaders.length }}
|
||||
|
||||
### Response Headers
|
||||
|
||||
|Status|Header|Type|Format|Description|
|
||||
|---|---|---|---|---|
|
||||
{{~ data.responseHeaders :h}}|{{=h.status}}|{{=h.header}}|{{=h.type}}|{{=h.format||''}}|{{=h.description||'none'}}|
|
||||
{{~}}
|
||||
|
||||
{{?}}
|
||||
{{= data.tags.endSection }}
|
|
@ -0,0 +1,27 @@
|
|||
<!-- APIDOCGEN: BEGIN SECTION -->
|
||||
{{= data.tags.section }}# Authentication
|
||||
{{ for (var s in data.api.components.securitySchemes) { }}
|
||||
{{ var sd = data.api.components.securitySchemes[s]; }}
|
||||
{{? sd.type == 'apiKey' }}
|
||||
- API Key ({{=s}})
|
||||
- Parameter Name: **{{=sd.name}}**, in: {{=sd.in}}. {{=sd.description || ''}}
|
||||
{{?}}
|
||||
{{? sd.type == 'http'}}
|
||||
- HTTP Authentication, scheme: {{=sd.scheme}}{{? sd.description }}<br/>{{=sd.description}}{{?}}
|
||||
{{?}}
|
||||
{{? sd.type == 'oauth2'}}
|
||||
- oAuth2 authentication. {{=sd.description || ''}}
|
||||
{{ for (var f in sd.flows) { }}
|
||||
{{ var flow = sd.flows[f]; }}
|
||||
- Flow: {{=f}}
|
||||
{{? flow.authorizationUrl}} - Authorization URL = [{{=flow.authorizationUrl}}]({{=flow.authorizationUrl}}){{?}}
|
||||
{{? flow.tokenUrl}} - Token URL = [{{=flow.tokenUrl}}]({{=flow.tokenUrl}}){{?}}
|
||||
{{? flow.scopes && Object.keys(flow.scopes).length}}
|
||||
|Scope|Scope Description|
|
||||
|---|---|
|
||||
{{ for (var sc in flow.scopes) { }}|{{=sc}}|{{=data.utils.join(flow.scopes[sc])}}|
|
||||
{{ } /* of scopes */ }}
|
||||
{{?}}
|
||||
{{ } /* of flows */ }}
|
||||
{{?}}
|
||||
{{ } /* of securitySchemes */ }}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"widdershins": "^4.0.1"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
const (
|
||||
apiSubdir = "api"
|
||||
apiIndexFile = "index.md"
|
||||
apiIndexContent = `Get started with Coder API:
|
||||
|
||||
<children>
|
||||
This page is rendered on https://coder.com/docs/coder-oss/api. Refer to the other documents in the ` + "`" + `api/` + "`" + ` directory.
|
||||
</children>
|
||||
`
|
||||
)
|
||||
|
||||
var (
|
||||
docsDirectory string
|
||||
inMdFileSingle string
|
||||
|
||||
sectionSeparator = []byte("<!-- APIDOCGEN: BEGIN SECTION -->\n")
|
||||
nonAlphanumericRegex = regexp.MustCompile(`[^a-z0-9 ]+`)
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Println("Postprocess API docs")
|
||||
|
||||
flag.StringVar(&docsDirectory, "docs-directory", "../../docs", "Path to Coder docs directory")
|
||||
flag.StringVar(&inMdFileSingle, "in-md-file-single", "", "Path to single Markdown file, output from widdershins.js")
|
||||
flag.Parse()
|
||||
|
||||
if inMdFileSingle == "" {
|
||||
flag.Usage()
|
||||
log.Fatal("missing value for in-md-file-single")
|
||||
}
|
||||
|
||||
sections, err := loadMarkdownSections()
|
||||
if err != nil {
|
||||
log.Fatal("can't load markdown sections: ", err)
|
||||
}
|
||||
|
||||
err = prepareDocsDirectory()
|
||||
if err != nil {
|
||||
log.Fatal("can't prepare docs directory: ", err)
|
||||
}
|
||||
|
||||
err = writeDocs(sections)
|
||||
if err != nil {
|
||||
log.Fatal("can't write docs directory: ", err)
|
||||
}
|
||||
|
||||
log.Println("Done")
|
||||
}
|
||||
|
||||
func loadMarkdownSections() ([][]byte, error) {
|
||||
log.Printf("Read the md-file-single: %s", inMdFileSingle)
|
||||
mdFile, err := os.ReadFile(inMdFileSingle)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("can't read the md-file-single: %w", err)
|
||||
}
|
||||
log.Printf("Read %dB", len(mdFile))
|
||||
|
||||
sections := bytes.Split(mdFile, sectionSeparator)
|
||||
if len(sections) < 2 {
|
||||
return nil, xerrors.Errorf("At least 1 section is expected: %w", err)
|
||||
}
|
||||
sections = sections[1:] // Skip the first element which is the empty byte array
|
||||
log.Printf("Loaded %d sections", len(sections))
|
||||
return sections, nil
|
||||
}
|
||||
|
||||
func prepareDocsDirectory() error {
|
||||
log.Println("Prepare docs directory")
|
||||
|
||||
apiPath := path.Join(docsDirectory, apiSubdir)
|
||||
|
||||
err := os.RemoveAll(apiPath)
|
||||
if err != nil {
|
||||
return xerrors.Errorf(`os.RemoveAll failed for "%s": %w`, apiPath, err)
|
||||
}
|
||||
|
||||
err = os.MkdirAll(apiPath, 0755)
|
||||
if err != nil {
|
||||
return xerrors.Errorf(`os.MkdirAll failed for "%s": %w`, apiPath, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeDocs(sections [][]byte) error {
|
||||
log.Println("Write docs to destination")
|
||||
|
||||
apiDir := path.Join(docsDirectory, apiSubdir)
|
||||
err := os.WriteFile(path.Join(apiDir, apiIndexFile), []byte(apiIndexContent), 0644) // #nosec
|
||||
if err != nil {
|
||||
return xerrors.Errorf(`can't write the index file: %w`, err)
|
||||
}
|
||||
|
||||
type mdFile struct {
|
||||
title string
|
||||
path string
|
||||
}
|
||||
var mdFiles []mdFile
|
||||
|
||||
// Write .md files for grouped API method (Templates, Workspaces, etc.)
|
||||
for _, section := range sections {
|
||||
sectionName, err := extractSectionName(section)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("can't extract section name: %w", err)
|
||||
}
|
||||
log.Printf("Write section: %s", sectionName)
|
||||
|
||||
mdFilename := toMdFilename(sectionName)
|
||||
docPath := path.Join(apiDir, mdFilename)
|
||||
err = os.WriteFile(docPath, section, 0644) // #nosec
|
||||
if err != nil {
|
||||
return xerrors.Errorf(`can't write doc file "%s": %w`, docPath, err)
|
||||
}
|
||||
mdFiles = append(mdFiles, mdFile{
|
||||
title: sectionName,
|
||||
path: "./" + path.Join(apiSubdir, mdFilename),
|
||||
})
|
||||
}
|
||||
|
||||
// Update manifest.json
|
||||
type route struct {
|
||||
Title string `json:"title,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
IconPath string `json:"icon_path,omitempty"`
|
||||
State string `json:"state,omitempty"`
|
||||
Children []route `json:"children,omitempty"`
|
||||
}
|
||||
|
||||
type manifest struct {
|
||||
Versions []string `json:"versions,omitempty"`
|
||||
Routes []route `json:"routes,omitempty"`
|
||||
}
|
||||
|
||||
manifestPath := path.Join(docsDirectory, "manifest.json")
|
||||
manifestFile, err := os.ReadFile(manifestPath)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("can't read manifest file: %w", err)
|
||||
}
|
||||
log.Printf("Read manifest file: %dB", len(manifestFile))
|
||||
|
||||
var m manifest
|
||||
err = json.Unmarshal(manifestFile, &m)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("json.Unmarshal failed: %w", err)
|
||||
}
|
||||
|
||||
for i, r := range m.Routes {
|
||||
if r.Title != "API" {
|
||||
continue
|
||||
}
|
||||
|
||||
var children []route
|
||||
for _, mdf := range mdFiles {
|
||||
docRoute := route{
|
||||
Title: mdf.title,
|
||||
Path: mdf.path,
|
||||
}
|
||||
children = append(children, docRoute)
|
||||
}
|
||||
|
||||
m.Routes[i].Children = children
|
||||
break
|
||||
}
|
||||
|
||||
manifestFile, err = json.MarshalIndent(m, "", " ")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("json.Marshal failed: %w", err)
|
||||
}
|
||||
|
||||
err = os.WriteFile(manifestPath, manifestFile, 0644) // #nosec
|
||||
if err != nil {
|
||||
return xerrors.Errorf("can't write manifest file: %w", err)
|
||||
}
|
||||
log.Printf("Write manifest file: %dB", len(manifestFile))
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractSectionName(section []byte) (string, error) {
|
||||
scanner := bufio.NewScanner(bytes.NewReader(section))
|
||||
if !scanner.Scan() {
|
||||
return "", xerrors.Errorf("section header was expected")
|
||||
}
|
||||
|
||||
header := scanner.Text()[2:] // Skip #<space>
|
||||
return strings.TrimSpace(header), nil
|
||||
}
|
||||
|
||||
func toMdFilename(sectionName string) string {
|
||||
return nonAlphanumericRegex.ReplaceAllLiteralString(strings.ToLower(sectionName), "-") + ".md"
|
||||
}
|
|
@ -121,7 +121,7 @@ fatal() {
|
|||
trap 'fatal "Script encountered an error"' ERR
|
||||
|
||||
cdroot
|
||||
start_cmd API "" "${CODER_DEV_SHIM}" server --http-address 0.0.0.0:3000
|
||||
start_cmd API "" "${CODER_DEV_SHIM}" server --http-address 0.0.0.0:3000 --swagger-enable
|
||||
|
||||
echo '== Waiting for Coder to become ready'
|
||||
# Start the timeout in the background so interrupting this script
|
||||
|
|
|
@ -26,7 +26,7 @@ var (
|
|||
|
||||
func main() {
|
||||
flag.StringVar(&metricsFile, "metrics-file", "scripts/metricsdocgen/metrics", "Path to Prometheus metrics file")
|
||||
flag.StringVar(&prometheusDocFile, "prometheus-doc-file", "docs/admin/prometheus.md", "Path to prometheus doc file")
|
||||
flag.StringVar(&prometheusDocFile, "prometheus-doc-file", "docs/admin/prometheus.md", "Path to Prometheus doc file")
|
||||
flag.BoolVar(&dryRun, "dry-run", false, "Dry run")
|
||||
flag.Parse()
|
||||
|
||||
|
|
|
@ -307,6 +307,7 @@ export interface DeploymentConfig {
|
|||
readonly experimental: DeploymentConfigField<boolean>
|
||||
readonly update_check: DeploymentConfigField<boolean>
|
||||
readonly max_token_lifetime: DeploymentConfigField<number>
|
||||
readonly swagger: SwaggerConfig
|
||||
}
|
||||
|
||||
// From codersdk/deploymentconfig.go
|
||||
|
@ -616,6 +617,11 @@ export interface ServiceBanner {
|
|||
readonly background_color?: string
|
||||
}
|
||||
|
||||
// From codersdk/deploymentconfig.go
|
||||
export interface SwaggerConfig {
|
||||
readonly enable: DeploymentConfigField<boolean>
|
||||
}
|
||||
|
||||
// From codersdk/deploymentconfig.go
|
||||
export interface TLSConfig {
|
||||
readonly enable: DeploymentConfigField<boolean>
|
||||
|
|
|
@ -25,6 +25,10 @@ export default defineConfig({
|
|||
ws: true,
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
},
|
||||
"/swagger": {
|
||||
target: process.env.CODER_HOST || "http://localhost:3000",
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
},
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
|
|
Loading…
Reference in New Issue