diff --git a/cmd/connect-client/commands/init.go b/cmd/connect-client/commands/init.go index 33de82d49..8d9127386 100644 --- a/cmd/connect-client/commands/init.go +++ b/cmd/connect-client/commands/init.go @@ -5,7 +5,6 @@ package commands import ( "fmt" - "github.com/rstudio/connect-client/internal/apptypes" "github.com/rstudio/connect-client/internal/bundles" "github.com/rstudio/connect-client/internal/cli_types" "github.com/rstudio/connect-client/internal/config" @@ -22,7 +21,7 @@ func (cmd *InitCommand) inspectProjectType(log logging.Logger) (*inspect.Content if err != nil { return nil, fmt.Errorf("error detecting content type: %w", err) } - log.Info("Deployment type", "Entrypoint", contentType.Entrypoint, "AppMode", contentType.AppMode) + log.Info("Deployment type", "Entrypoint", contentType.Entrypoint, "AppMode", contentType.Type) return contentType, nil } @@ -33,8 +32,8 @@ type InitCommand struct { config *config.Config } -func (cmd *InitCommand) requiresPython(appMode apptypes.AppMode) (bool, error) { - if appMode.IsPythonContent() { +func (cmd *InitCommand) requiresPython(contentType config.ContentType) (bool, error) { + if contentType.IsPythonContent() { return true, nil } if cmd.Python.Path() != "" { @@ -79,10 +78,10 @@ func (cmd *InitCommand) Run(args *cli_types.CommonArgs, ctx *cli_types.CLIContex if err != nil { return err } - cmd.config.Type = contentType.AppMode + cmd.config.Type = contentType.Type cmd.config.Entrypoint = contentType.Entrypoint - requiresPython, err := cmd.requiresPython(contentType.AppMode) + requiresPython, err := cmd.requiresPython(contentType.Type) if err != nil { return err } diff --git a/internal/bundles/manifest.go b/internal/bundles/manifest.go index d27d7cab7..6a2dea8ca 100644 --- a/internal/bundles/manifest.go +++ b/internal/bundles/manifest.go @@ -154,11 +154,33 @@ func NewManifest() *Manifest { } } +var connectContentTypeMap = map[config.ContentType]apptypes.AppMode{ + config.ContentTypeHTML: apptypes.StaticMode, + config.ContentTypeJupyterNotebook: apptypes.StaticJupyterMode, + config.ContentTypeJupyterVoila: apptypes.JupyterVoilaMode, + config.ContentTypePythonBokeh: apptypes.PythonBokehMode, + config.ContentTypePythonDash: apptypes.PythonDashMode, + config.ContentTypePythonFastAPI: apptypes.PythonFastAPIMode, + config.ContentTypePythonFlask: apptypes.PythonAPIMode, + config.ContentTypePythonShiny: apptypes.PythonShinyMode, + config.ContentTypePythonStreamlit: apptypes.PythonStreamlitMode, + config.ContentTypeQuartoShiny: apptypes.ShinyQuartoMode, + config.ContentTypeQuarto: apptypes.StaticQuartoMode, + config.ContentTypeRPlumber: apptypes.PlumberAPIMode, + config.ContentTypeRShiny: apptypes.ShinyMode, + config.ContentTypeRMarkdownShiny: apptypes.ShinyRmdMode, + config.ContentTypeRMarkdown: apptypes.StaticRmdMode, +} + func NewManifestFromConfig(cfg *config.Config) *Manifest { + contentType, ok := connectContentTypeMap[cfg.Type] + if !ok { + contentType = apptypes.UnknownMode + } m := &Manifest{ Version: 1, Metadata: Metadata{ - AppMode: cfg.Type, + AppMode: contentType, Entrypoint: cfg.Entrypoint, }, Jupyter: nil, @@ -185,10 +207,10 @@ func NewManifestFromConfig(cfg *config.Config) *Manifest { } } switch cfg.Type { - case apptypes.StaticRmdMode: - case apptypes.ShinyRmdMode: + case config.ContentTypeRMarkdown: + case config.ContentTypeRMarkdownShiny: m.Metadata.PrimaryRmd = cfg.Entrypoint - case apptypes.StaticMode: + case config.ContentTypeHTML: m.Metadata.PrimaryHtml = cfg.Entrypoint } return m diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 1e7e70680..6846c1778 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -6,7 +6,6 @@ import ( "io/fs" "testing" - "github.com/rstudio/connect-client/internal/apptypes" "github.com/rstudio/connect-client/internal/util" "github.com/rstudio/connect-client/internal/util/utiltest" "github.com/spf13/afero" @@ -60,7 +59,7 @@ func (s *ConfigSuite) TestFromFile() { cfg, err := FromFile(path) s.NoError(err) s.NotNil(cfg) - s.Equal(apptypes.AppMode("python-dash"), cfg.Type) + s.Equal(ContentTypePythonDash, cfg.Type) } func (s *ConfigSuite) TestFromFileErr() { diff --git a/internal/config/types.go b/internal/config/types.go index 9e75413b5..1b45c678a 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -2,26 +2,57 @@ package config // Copyright (C) 2023 by Posit Software, PBC. -import ( - "github.com/rstudio/connect-client/internal/apptypes" +type ContentType string + +const ( + ContentTypeHTML ContentType = "html" + ContentTypeJupyterNotebook ContentType = "jupyter-notebook" + ContentTypeJupyterVoila ContentType = "jupyter-voila" + ContentTypePythonBokeh ContentType = "python-bokeh" + ContentTypePythonDash ContentType = "python-dash" + ContentTypePythonFastAPI ContentType = "python-fastapi" + ContentTypePythonFlask ContentType = "python-flask" + ContentTypePythonShiny ContentType = "python-shiny" + ContentTypePythonStreamlit ContentType = "python-streamlit" + ContentTypeQuartoShiny ContentType = "quarto-shiny" + ContentTypeQuarto ContentType = "quarto" + ContentTypeRPlumber ContentType = "r-plumber" + ContentTypeRShiny ContentType = "r-shiny" + ContentTypeRMarkdownShiny ContentType = "rmd-shiny" + ContentTypeRMarkdown ContentType = "rmd" ) +func (t ContentType) IsPythonContent() bool { + switch t { + case ContentTypeJupyterNotebook: + case ContentTypeJupyterVoila: + case ContentTypePythonBokeh: + case ContentTypePythonDash: + case ContentTypePythonFastAPI: + case ContentTypePythonFlask: + case ContentTypePythonShiny: + case ContentTypePythonStreamlit: + return true + } + return false +} + type Config struct { - Schema SchemaURL `toml:"$schema" json:"$schema"` - Type apptypes.AppMode `toml:"type" json:"type"` - Entrypoint string `toml:"entrypoint,omitempty" json:"entrypoint,omitempty"` - Title string `toml:"title,omitempty" json:"title,omitempty"` - Description string `toml:"description,multiline,omitempty" json:"description,omitempty"` - ThumbnailFile string `toml:"thumbnail,omitempty" json:"thumbnail,omitempty"` - Tags []string `toml:"tags,omitempty" json:"tags,omitempty"` - Python *Python `toml:"python,omitempty" json:"python,omitempty"` - R *R `toml:"r,omitempty" json:"r,omitempty"` - Quarto *Quarto `toml:"quarto,omitempty" json:"quarto,omitempty"` - Environment Environment `toml:"environment,omitempty" json:"environment,omitempty"` - Secrets []string `toml:"secrets,omitempty" json:"secrets,omitempty"` - Schedules []Schedule `toml:"schedules,omitempty" json:"schedules,omitempty"` - Access *Access `toml:"access,omitempty" json:"access,omitempty"` - Connect *Connect `toml:"connect,omitempty" json:"connect,omitempty"` + Schema SchemaURL `toml:"$schema" json:"$schema"` + Type ContentType `toml:"type" json:"type"` + Entrypoint string `toml:"entrypoint,omitempty" json:"entrypoint,omitempty"` + Title string `toml:"title,omitempty" json:"title,omitempty"` + Description string `toml:"description,multiline,omitempty" json:"description,omitempty"` + ThumbnailFile string `toml:"thumbnail,omitempty" json:"thumbnail,omitempty"` + Tags []string `toml:"tags,omitempty" json:"tags,omitempty"` + Python *Python `toml:"python,omitempty" json:"python,omitempty"` + R *R `toml:"r,omitempty" json:"r,omitempty"` + Quarto *Quarto `toml:"quarto,omitempty" json:"quarto,omitempty"` + Environment Environment `toml:"environment,omitempty" json:"environment,omitempty"` + Secrets []string `toml:"secrets,omitempty" json:"secrets,omitempty"` + Schedules []Schedule `toml:"schedules,omitempty" json:"schedules,omitempty"` + Access *Access `toml:"access,omitempty" json:"access,omitempty"` + Connect *Connect `toml:"connect,omitempty" json:"connect,omitempty"` } type SchemaURL string diff --git a/internal/inspect/all_test.go b/internal/inspect/all_test.go index 6e2f7ca75..44de407b1 100644 --- a/internal/inspect/all_test.go +++ b/internal/inspect/all_test.go @@ -6,7 +6,7 @@ import ( "os" "testing" - "github.com/rstudio/connect-client/internal/apptypes" + "github.com/rstudio/connect-client/internal/config" "github.com/rstudio/connect-client/internal/util" "github.com/rstudio/connect-client/internal/util/utiltest" "github.com/spf13/afero" @@ -35,7 +35,7 @@ func (s *AllSuite) TestInferTypeDirectory() { t, err := detector.InferType(path) s.Nil(err) s.Equal(&ContentType{ - AppMode: apptypes.PythonDashMode, + Type: config.ContentTypePythonDash, Entrypoint: appFilename, RequiresPython: true, }, t) @@ -57,7 +57,7 @@ func (s *AllSuite) TestInferTypeFileLowerPriority() { t, err := detector.InferType(htmlPath) s.Nil(err) s.Equal(&ContentType{ - AppMode: apptypes.StaticMode, + Type: config.ContentTypeHTML, Entrypoint: htmlFilename, }, t) } @@ -78,7 +78,7 @@ func (s *AllSuite) TestInferTypeFileHigherPriority() { t, err := detector.InferType(appPath) s.Nil(err) s.Equal(&ContentType{ - AppMode: apptypes.PythonDashMode, + Type: config.ContentTypePythonDash, Entrypoint: appFilename, RequiresPython: true, }, t) @@ -99,7 +99,7 @@ func (s *AllSuite) TestInferTypeDirectoryPriority() { t, err := detector.InferType(path) s.Nil(err) s.Equal(&ContentType{ - AppMode: apptypes.PythonDashMode, + Type: config.ContentTypePythonDash, Entrypoint: appFilename, RequiresPython: true, }, t) diff --git a/internal/inspect/html.go b/internal/inspect/html.go index 7f36e0ad3..a7e3bfdc9 100644 --- a/internal/inspect/html.go +++ b/internal/inspect/html.go @@ -3,7 +3,7 @@ package inspect // Copyright (C) 2023 by Posit Software, PBC. import ( - "github.com/rstudio/connect-client/internal/apptypes" + "github.com/rstudio/connect-client/internal/config" "github.com/rstudio/connect-client/internal/util" ) @@ -30,7 +30,7 @@ func (d *StaticHTMLDetector) InferType(path util.Path) (*ContentType, error) { } if entrypoint != "" { return &ContentType{ - AppMode: apptypes.StaticMode, + Type: config.ContentTypeHTML, Entrypoint: entrypoint, }, nil } diff --git a/internal/inspect/html_test.go b/internal/inspect/html_test.go index ce57b1e1c..44af8af93 100644 --- a/internal/inspect/html_test.go +++ b/internal/inspect/html_test.go @@ -6,7 +6,7 @@ import ( "errors" "testing" - "github.com/rstudio/connect-client/internal/apptypes" + "github.com/rstudio/connect-client/internal/config" "github.com/rstudio/connect-client/internal/util" "github.com/rstudio/connect-client/internal/util/utiltest" "github.com/spf13/afero" @@ -32,7 +32,7 @@ func (s *StaticHTMLDetectorSuite) TestInferTypeSpecifiedFile() { t, err := detector.InferType(path) s.Nil(err) s.Equal(&ContentType{ - AppMode: apptypes.StaticMode, + Type: config.ContentTypeHTML, Entrypoint: filename, }, t) } @@ -47,7 +47,7 @@ func (s *StaticHTMLDetectorSuite) TestInferTypePreferredFilename() { t, err := detector.InferType(path) s.Nil(err) s.Equal(&ContentType{ - AppMode: apptypes.StaticMode, + Type: config.ContentTypeHTML, Entrypoint: filename, }, t) } @@ -62,7 +62,7 @@ func (s *StaticHTMLDetectorSuite) TestInferTypeOnlyHTMLFile() { t, err := detector.InferType(path) s.Nil(err) s.Equal(&ContentType{ - AppMode: apptypes.StaticMode, + Type: config.ContentTypeHTML, Entrypoint: filename, }, t) } diff --git a/internal/inspect/infer.go b/internal/inspect/infer.go index ffbc30b98..4635b703f 100644 --- a/internal/inspect/infer.go +++ b/internal/inspect/infer.go @@ -5,12 +5,12 @@ package inspect import ( "io" - "github.com/rstudio/connect-client/internal/apptypes" + "github.com/rstudio/connect-client/internal/config" "github.com/rstudio/connect-client/internal/util" ) type ContentType struct { - AppMode apptypes.AppMode + Type config.ContentType Entrypoint string RequiresR bool RequiresPython bool diff --git a/internal/inspect/notebook.go b/internal/inspect/notebook.go index c46fcdd51..2c2769466 100644 --- a/internal/inspect/notebook.go +++ b/internal/inspect/notebook.go @@ -8,7 +8,7 @@ import ( "io" "strings" - "github.com/rstudio/connect-client/internal/apptypes" + "github.com/rstudio/connect-client/internal/config" "github.com/rstudio/connect-client/internal/util" ) @@ -53,9 +53,9 @@ func (d *NotebookDetector) InferType(path util.Path) (*ContentType, error) { RequiresPython: true, } if isVoila { - t.AppMode = apptypes.JupyterVoilaMode + t.Type = config.ContentTypeJupyterVoila } else { - t.AppMode = apptypes.StaticJupyterMode + t.Type = config.ContentTypeJupyterNotebook } return t, nil } diff --git a/internal/inspect/notebook_test.go b/internal/inspect/notebook_test.go index 4d4556660..c9b1a450d 100644 --- a/internal/inspect/notebook_test.go +++ b/internal/inspect/notebook_test.go @@ -10,7 +10,7 @@ import ( "strings" "testing" - "github.com/rstudio/connect-client/internal/apptypes" + "github.com/rstudio/connect-client/internal/config" "github.com/rstudio/connect-client/internal/util" "github.com/rstudio/connect-client/internal/util/utiltest" "github.com/spf13/afero" @@ -100,7 +100,7 @@ func (s *NotebookDetectorSuite) TestInferTypePlainNotebook() { t, err := detector.InferType(path) s.Nil(err) s.Equal(&ContentType{ - AppMode: apptypes.StaticJupyterMode, + Type: config.ContentTypeJupyterNotebook, Entrypoint: filename, RequiresPython: true, }, t) @@ -116,7 +116,7 @@ func (s *NotebookDetectorSuite) TestInferTypeVoilaNotebook() { t, err := detector.InferType(path) s.Nil(err) s.Equal(&ContentType{ - AppMode: apptypes.JupyterVoilaMode, + Type: config.ContentTypeJupyterVoila, Entrypoint: filename, RequiresPython: true, }, t) diff --git a/internal/inspect/python.go b/internal/inspect/python.go index 586253ddb..95f456650 100644 --- a/internal/inspect/python.go +++ b/internal/inspect/python.go @@ -3,26 +3,26 @@ package inspect // Copyright (C) 2023 by Posit Software, PBC. import ( - "github.com/rstudio/connect-client/internal/apptypes" + "github.com/rstudio/connect-client/internal/config" "github.com/rstudio/connect-client/internal/util" ) type PythonAppDetector struct { inferenceHelper - appMode apptypes.AppMode - imports []string + contentType config.ContentType + imports []string } -func NewPythonAppDetector(appMode apptypes.AppMode, imports []string) *PythonAppDetector { +func NewPythonAppDetector(contentType config.ContentType, imports []string) *PythonAppDetector { return &PythonAppDetector{ inferenceHelper: defaultInferenceHelper{}, - appMode: appMode, + contentType: contentType, imports: imports, } } func NewFlaskDetector() *PythonAppDetector { - return NewPythonAppDetector(apptypes.PythonAPIMode, []string{ + return NewPythonAppDetector(config.ContentTypePythonFlask, []string{ "flask", // also matches flask_api, flask_openapi3, etc. "flasgger", "falcon", // must check for this after falcon.asgi (FastAPI) @@ -30,7 +30,7 @@ func NewFlaskDetector() *PythonAppDetector { } func NewFastAPIDetector() *PythonAppDetector { - return NewPythonAppDetector(apptypes.PythonFastAPIMode, []string{ + return NewPythonAppDetector(config.ContentTypePythonFastAPI, []string{ "fastapi", "falcon.asgi", "quart", @@ -41,25 +41,25 @@ func NewFastAPIDetector() *PythonAppDetector { } func NewDashDetector() *PythonAppDetector { - return NewPythonAppDetector(apptypes.PythonDashMode, []string{ + return NewPythonAppDetector(config.ContentTypePythonDash, []string{ "dash", // also matches dash_core_components, dash_bio, etc. }) } func NewStreamlitDetector() *PythonAppDetector { - return NewPythonAppDetector(apptypes.PythonStreamlitMode, []string{ + return NewPythonAppDetector(config.ContentTypePythonStreamlit, []string{ "streamlit", }) } func NewBokehDetector() *PythonAppDetector { - return NewPythonAppDetector(apptypes.PythonBokehMode, []string{ + return NewPythonAppDetector(config.ContentTypePythonBokeh, []string{ "bokeh", }) } func NewPyShinyDetector() *PythonAppDetector { - return NewPythonAppDetector(apptypes.PythonShinyMode, []string{ + return NewPythonAppDetector(config.ContentTypePythonShiny, []string{ "shiny", }) } @@ -77,7 +77,7 @@ func (d *PythonAppDetector) InferType(path util.Path) (*ContentType, error) { if matches { return &ContentType{ Entrypoint: entrypoint, - AppMode: d.appMode, + Type: d.contentType, RequiresPython: true, }, nil } diff --git a/internal/inspect/python_test.go b/internal/inspect/python_test.go index bff3443d6..c6bc49d4b 100644 --- a/internal/inspect/python_test.go +++ b/internal/inspect/python_test.go @@ -6,7 +6,7 @@ import ( "errors" "testing" - "github.com/rstudio/connect-client/internal/apptypes" + "github.com/rstudio/connect-client/internal/config" "github.com/rstudio/connect-client/internal/util" "github.com/rstudio/connect-client/internal/util/utiltest" "github.com/spf13/afero" @@ -32,7 +32,7 @@ func (s *PythonSuite) TestInferTypeSpecifiedFile() { t, err := detector.InferType(path) s.Nil(err) s.Equal(&ContentType{ - AppMode: apptypes.PythonAPIMode, + Type: config.ContentTypePythonFlask, Entrypoint: filename, RequiresPython: true, }, t) @@ -48,7 +48,7 @@ func (s *PythonSuite) TestInferTypePreferredFilename() { t, err := detector.InferType(path) s.Nil(err) s.Equal(&ContentType{ - AppMode: apptypes.PythonAPIMode, + Type: config.ContentTypePythonFlask, Entrypoint: filename, RequiresPython: true, }, t) @@ -64,7 +64,7 @@ func (s *PythonSuite) TestInferTypeOnlyPythonFile() { t, err := detector.InferType(path) s.Nil(err) s.Equal(&ContentType{ - AppMode: apptypes.PythonAPIMode, + Type: config.ContentTypePythonFlask, Entrypoint: filename, RequiresPython: true, }, t) diff --git a/schema/deploy.toml b/schema/deploy.toml new file mode 100644 index 000000000..a6e75db99 --- /dev/null +++ b/schema/deploy.toml @@ -0,0 +1,47 @@ +"$schema" = "./posit-publishing-schema-v3.json" +type = "quarto" +entrypoint = "report.qmd" +title = "Regional Quarterly Sales Report" +description = "This is the quarterly sales report, broken down by region." + +[python] +version = "3.11.3" +package-file = "requirements.txt" +package-manager = "pip" + +[r] +version = "4.3.1" +package-file = "renv.lock" +package-manager = "renv" + +[quarto] +version = "1.4" + +[environment] +API_URL = "https://example.com/api" + +[connect.access] +run-as = "rstudio-connect" +run-as-current-user = false + +[connect.runtime] +connection-timeout = 5 +read-timeout = 30 +init-timeout = 60 +idle-timeout = 120 +max-processes = 5 +min-processes = 1 +max-connections = 50 +load-factor = 0.5 + +[connect.kubernetes] +amd-gpu-limit = 0 +cpu-limit = 1 +cpu-request = 0.5 +image-name = "posit/connect-runtime-python3.11-r4.3" +memory-limit = "100000000" +memory-request = "20000000" +nvidia-gpu-limit = 0 +service-account-name = "posit-connect-content" +r-environment-management = true +py-environment-management = true diff --git a/schema/draft/deploy.toml b/schema/draft/deploy.toml new file mode 100644 index 000000000..a125a1612 --- /dev/null +++ b/schema/draft/deploy.toml @@ -0,0 +1,67 @@ +"$schema" = "./posit-publishing-schema-v3.json" +type = "quarto" +entrypoint = "report.qmd" +title = "Regional Quarterly Sales Report" +description = "This is the quarterly sales report, broken down by region." +thumbnail = "images/thumbnail.jpg" +tags = [ "sales", "quarterly", "regional" ] + +secrets = ["API_KEY"] + +[python] +version = "3.11.3" +package-file = "requirements.txt" +package-manager = "pip" + +[r] +version = "4.3.1" +package-file = "renv.lock" +package-manager = "renv" + +[quarto] +version = "1.4" + +[environment] +API_URL = "https://example.com/api" + +[[schedules]] +start = "2023-10-25T08:00:00Z" +recurrence = "FREQ=MONTHLY;INTERVAL=3" + +[[access.users]] +id = "jqpublic" +guid = "536b456e-0311-4f92-ba10-dbf1db8a468e" +name = "John Q. Public" +permissions = "editor" + +[[access.groups]] +id = "Data Science Team" +guid = "8b4fde3e-f995-4894-bc02-ae47538262ff" +name = "Data Science Team" +permissions = "editor" + +[connect.access] +run-as = "rstudio-connect" +run-as-current-user = false + +[connect.runtime] +connection-timeout = 5 +read-timeout = 30 +init-timeout = 60 +idle-timeout = 120 +max-processes = 5 +min-processes = 1 +max-connections = 50 +load-factor = 0.5 + +[connect.kubernetes] +amd-gpu-limit = 0 +cpu-limit = 1 +cpu-request = 0.5 +image-name = "posit/connect-runtime-python3.11-r4.3" +memory-limit = "100000000" +memory-request = "20000000" +nvidia-gpu-limit = 0 +service-account-name = "posit-connect-content" +r-environment-management = true +py-environment-management = true diff --git a/schema/draft/posit-publishing-record-schema-v3.json b/schema/draft/posit-publishing-record-schema-v3.json new file mode 100644 index 000000000..3701e9f8c --- /dev/null +++ b/schema/draft/posit-publishing-record-schema-v3.json @@ -0,0 +1,65 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/rstudio/publishing-client/posit-publishing-record-schema-v3.json", + "type": "object", + "additionalProperties": false, + "description": "Posit Publishing Record", + "required": [ + "$schema", + "server-url", + "id", + "configuration-name" + ], + "properties": { + "$schema": { + "type": "string", + "format": "url", + "description": "URL of the json-schema definition for this file. Must be 'https://cdn.posit.co/connect/posit-publishing-record-schema-v3.json'.", + "enum": [ + "./posit-publishing-record-schema-v3.json" + ], + "examples": [ + "https://cdn.posit.co/connect/posit-publishing-record-schema-v3.json" + ] + }, + "server-url": { + "type": "string", + "format": "uri", + "description": "URL of the server where this content was deployed.", + "examples": [ + "https://connect.example.com" + ] + }, + "id": { + "type": "string", + "description": "Unique ID of this deployment.", + "examples": [ + "de2e7bdb-b085-401e-a65c-443e40009749" + ] + }, + "configuration-name": { + "type": "string", + "description": "Name of the configuration that was used during deployment.", + "examples": [ + "production" + ] + }, + "configuration": { + "$ref": "./posit-publishing-schema-v3.json" + }, + "files": { + "type": "array", + "items": { + "type": [ + "string" + ] + }, + "description": "Project-relative paths of the files that were included in the deployment.", + "examples": [ + "app.py", + "model/weights.csv" + ] + + } + } +} diff --git a/schema/draft/posit-publishing-schema-v3.json b/schema/draft/posit-publishing-schema-v3.json new file mode 100644 index 000000000..faa3b29c0 --- /dev/null +++ b/schema/draft/posit-publishing-schema-v3.json @@ -0,0 +1,531 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/rstudio/publishing-client/posit-publishing-schema-v3.json", + "type": "object", + "additionalProperties": false, + "description": "Posit Publishing Configuration", + "required": [ + "$schema", + "type", + "entrypoint" + ], + "properties": { + "$schema": { + "type": "string", + "format": "url", + "description": "URL of the json-schema definition for this file. Must be 'https://cdn.posit.co/connect/posit-publishing-schema-v3.json'.", + "enum": [ + "./posit-publishing-schema-v3.json" + ], + "examples": [ + "https://cdn.posit.co/connect/posit-publishing-schema-v3.json" + ] + }, + "type": { + "type": "string", + "description": "Indicates the type of content being deployed.", + "enum": [ + "html", + "jupyter-notebook", + "jupyter-voila", + "python-bokeh", + "python-dash", + "python-fastapi", + "python-flask", + "python-shiny", + "python-streamlit", + "quarto-shiny", + "quarto", + "r-plumber", + "r-shiny", + "rmd-shiny", + "rmd" + ], + "examples": [ + "quarto" + ] + }, + "entrypoint": { + "type": "string", + "description": "Name of the primary file containing the content. For some types of Python executable content, this may also indicate the object within the file in module:object format.", + "examples": [ + "app.py", + "report.qmd" + ] + }, + "title": { + "type": "string", + "pattern": "^[^\t\n\f\r]{3,1024}$|", + "description": "Human-readable title for this content.", + "examples": [ + "Quarterly Sales Report" + ] + }, + "description": { + "type": "string", + "description": "Human-readable description for this content.", + "examples": [ + "This is the quarterly sales report, broken down by region." + ] + }, + "thumbnail": { + "type": "string", + "description": "Path to thumbnail preview image for this content.", + "examples": [ + "images/thumbnail.jpg" + ] + }, + "tags": { + "type": "array", + "description": "List of tags to apply to this deployment. When publishing to Connect, tags must be pre-defined by an administrator.", + "items": { + "type": "string", + "examples": [ + "sales", + "quarterly", + "regional" + ] + } + }, + "python": { + "type": "object", + "additionalProperties": false, + "description": "Python language and dependencies.", + "required": [ + "version" + ], + "properties": { + "version": { + "type": "string", + "description": "Python version. The server must have a matching Python version in order to run the content.", + "examples": [ + "3.11.3", + "3.11" + ] + }, + "package-file": { + "type": "string", + "description": "File containing package dependencies. The file must exist and be listed under 'files'.", + "default": "requirements.txt", + "examples": [ + "requirements.txt" + ] + }, + "package-manager": { + "type": "string", + "default": "pip", + "enum": [ + "pip", + "conda", + "pipenv", + "poetry", + "none" + ], + "description": "Package manager that will install the dependencies. If package-manager is none, dependencies will not be installed.", + "examples": [ + "pip" + ] + } + } + }, + "r": { + "type": "object", + "additionalProperties": false, + "description": "R language and dependencies.", + "required": [ + "version" + ], + "properties": { + "version": { + "type": "string", + "description": "R version. The server must have a similar R version in order to run the content.", + "examples": [ + "4.3.1" + ] + }, + "package-file": { + "type": "string", + "default": "renv.lock", + "description": "File containing package dependencies. The file must exist and be listed under 'files'.", + "examples": [ + "renv.lock" + ] + }, + "package-manager": { + "type": "string", + "default": "renv", + "enum": [ + "renv", + "none" + ], + "description": "Package manager that will install the dependencies. If package-manager is none, dependencies will not be installed.", + "examples": [ + "renv" + ] + } + } + }, + "quarto": { + "type": "object", + "additionalProperties": false, + "description": "Quarto version required to run the content.", + "required": [ + "version" + ], + "properties": { + "version": { + "type": "string", + "description": "Quarto version. The server must have a similar Quarto version in order to run the content.", + "examples": [ + "1.4" + ] + }, + "engines": { + "type": "array", + "description": "List of Quarto engines required for this content.", + "items": { + "type": "string", + "enum": [ + "knitr", + "jupyter" + ], + "examples": [ + "knitr", + "jupyter" + ] + } + } + } + }, + "environment": { + "type": "object", + "additionalProperties": { + "type": [ + "string" + ] + }, + "description": "Environment variable/value map. Secrets such as API keys or tokens should not be stored here.", + "examples": [ + { + "API_URL": "https://example.com/api" + } + ] + }, + "secrets": { + "type": "array", + "items": { + "type": [ + "string" + ] + }, + "description": "Names of secrets that should be injected as environment variables.", + "examples": [ + "API_KEY" + ] + }, + "schedules": { + "type": "array", + "description": "Schedules for recurring execution of this content. Only applies to reports, such as Quarto, R Markdown, and Jupyter Notebooks.", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "start", + "recurrence" + ], + "properties": { + "start": { + "type": "string", + "description": "Time for the first run of the content.", + "examples": [ + "2023-10-25T08:00:00Z" + ] + }, + "recurrence": { + "type": "string", + "description": "Recurrence scheme for the content, in cron or iCalendar RRULE format.", + "examples": [ + "FREQ=MONTHLY;INTERVAL=3", + "0 2 * * *" + ] + } + } + } + }, + "access": { + "type": "object", + "additionalProperties": false, + "description": "Access control settings.", + "properties": { + "type": { + "type": "string", + "default": "acl", + "description": "Type of access control. 'public' make the deployment public (no login required), with no login required. 'all-users' allows all logged-in users to access the content. 'acl' (the default) allows only specific users and groups to access the content.", + "enum": [ + "public", + "all-users", + "acl" + ], + "examples": [ + "all-users" + ] + }, + "users": { + "type": "array", + "description": "List of users who have access to this content.", + "items": { + "type": "object", + "additionalProperties": false, + "anyOf": [ + { "required": ["id"] }, + { "required": ["guid"] } + ], + "properties": { + "id": { + "type": "string", + "description": "Unique ID from the authentication provider that identifies this user. This may be a username, LDAP CN/DN, email address, etc. depending on the provider.", + "examples": [ + "jqpublic" + ] + }, + "guid": { + "type": "string", + "description": "Unique identifier assigned by Connect. When deploying to the same server, this will determine the user who is granted access. When deploying to a different server, the provider-id will be used to look up the user.", + "examples": [ + "cd2e7cef-a195-512e-b76d-554f4f5a239c" + ] + }, + "name": { + "type": "string", + "description": "User's name. This field is informational only.", + "examples": [ + "John Q. Public" + ] + }, + "permissions": { + "type": "string", + "description": "Permission level assigned to this user.", + "enum": ["viewer", "editor", "owner"], + "examples": [ + "viewer" + ] + } + } + } + }, + "groups": { + "type": "array", + "description": "List of groups who have access to this content.", + "items": { + "type": "object", + "additionalProperties": false, + "anyOf": [ + { "required": ["id"] }, + { "required": ["guid"] } + ], + "properties": { + "id": { + "type": "string", + "description": "Unique ID from the authentication provider that identifies this group. For groups created by Connect, this will be the group name. This may be a group name, LDAP CN/DN, etc. depending on the provider.", + "examples": [ + "Data Science Team" + ] + }, + "guid": { + "type": "string", + "description": "Unique identifier assigned by Connect. When deploying to the same server, this will determine the user who is granted access. When deploying to a different server, the provider-id will be used to look up the user.", + "examples": [ + "8b4fde3e-f995-4894-bc02-ae47538262ff" + ] + }, + "name": { + "type": "string", + "description": "Group name. This field is informational only.", + "examples": [ + "Data Science Team" + ] + }, + "permissions": { + "type": "string", + "default": "viewer", + "description": "Permission level assigned to this group.", + "enum": ["viewer", "editor", "owner"], + "examples": [ + "editor" + ] + } + } + } + } + } + }, + "connect": { + "type": "object", + "additionalProperties": false, + "description": "Setting specific to Posit Connect deployments.", + "properties": { + "access": { + "run-as": { + "type": "string", + "description": "The system username under which the content should be run. Must be an existing user in the allowed group. You must be an administrator to set this value.", + "examples": [ + "rstudio-connect" + ] + }, + "run-as-current-user": { + "type": "boolean", + "default": false, + "description": "For application content types, run a separate process for each visiting user under that user's server account. Requires PAM authentication on the Posit Connect server. You must be an administrator to set this value." + } + }, + "runtime": { + "type": "object", + "additionalProperties": false, + "description": "Runtime settings for application content types.", + "properties": { + "connection-timeout": { + "type": "integer", + "minimum": 0, + "description": "Maximum number of seconds allowed without data sent or received across a client connection. A value of `0` means connections will never time-out (not recommended).", + "examples": [ + 5 + ] + }, + "read-timeout": { + "type": "integer", + "minimum": 0, + "description": "Maximum number of seconds allowed without data received from a client connection. A value of `0` means a lack of client (browser) interaction never causes the connection to close.", + "examples": [ + 30 + ] + }, + "init-timeout": { + "type": "integer", + "description": "The maximum number of seconds allowed for an interactive application to start. Posit Connect must be able to connect to a newly launched application before this threshold has elapsed.", + "examples": [ + 60 + ] + }, + "idle-timeout": { + "type": "integer", + "description": "The maximum number of seconds a worker process for an interactive application to remain alive after it goes idle (no active connections).", + "examples": [ + 120 + ] + }, + "max-processes": { + "type": "integer", + "minimum": 1, + "description": "Specifies the total number of concurrent processes allowed for a single interactive application.", + "examples": [ + 5 + ] + }, + "min-processes": { + "type": "integer", + "minimum": 0, + "description": "Specifies the minimum number of concurrent processes allowed for a single interactive application.", + "examples": [ + 1 + ] + }, + "max-connections": { + "type": "integer", + "minimum": 1, + "description": "Specifies the maximum number of client connections allowed to an individual process. Incoming connections which will exceed this limit are routed to a new process or rejected.", + "examples": [ + 50 + ] + }, + "load-factor": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Controls how aggressively new processes are spawned. The valid range is between 0.0 and 1.0.", + "examples": [ + 0.5 + ] + } + } + }, + "kubernetes": { + "type": "object", + "additionalProperties": false, + "description": "Settings used with Posit Connect's off-host execution feature, where content is run in Kubernetes.", + "properties": { + "amd-gpu-limit": { + "type": "integer", + "description": "The number of AMD GPUs that will be allocated by Kubernetes to run this content.", + "examples": [ + 0 + ] + }, + "cpu-limit": { + "type": "integer", + "description": "The maximum amount of compute power this content will be allowed to consume when executing or rendering, expressed in CPU Units, where 1.0 unit is equivalent to 1 physical or virtual core. Fractional values are allowed. If the process tries to use more CPU than allowed, it will be throttled.", + "examples": [ + 1 + ] + }, + "cpu-request": { + "type": "number", + "description": "The minimum amount of compute power this content needs when executing virtual core. Fractional values are allowed.", + "examples": [ + 0.5 + ] + }, + "image-name": { + "type": "string", + "description": "Name of the target container image.", + "examples": [ + "posit/connect-runtime-python3.11-r4.3" + ] + }, + "memory-limit": { + "type": "string", + "description": "The maximum amount of RAM this content will be allowed to consume when executing or rendering, expressed in bytes. If the process tries to use more memory than allowed, it will be terminated", + "examples": [ + "100000000" + ] + }, + "memory-request": { + "type": "string", + "description": "The minimum amount of RAM this content needs when executing or rendering, expressed in bytes.", + "examples": [ + "20000000" + ] + }, + "nvidia-gpu-limit": { + "type": "integer", + "description": "The number of NVIDIA GPUs that will be allocated by Kubernetes to run this content.", + "examples": [ + 0 + ] + }, + "service-account-name": { + "type": "string", + "description": "The name of the Kubernetes service account that is used to run this content. It must adhere to Kubernetes service account naming rules. You must be an administrator to set this value.", + "examples": [ + "posit-connect-content" + ] + }, + "r-environment-management": { + "type": "boolean", + "description": "Enables or disables R environment management. When false, Posit Connect will not install R packages and instead assume that all required packages are present in the container image.", + "examples": [ + true + ] + }, + "py-environment-management": { + "type": "boolean", + "description": "Enables or disables Python environment management. When false, Posit Connect will not install Python packages and instead assume that all required packages are present in the container image.", + "examples": [ + true + ] + } + } + } + } + } + } +} diff --git a/schema/draft/record.toml b/schema/draft/record.toml new file mode 100644 index 000000000..aad3d9ad3 --- /dev/null +++ b/schema/draft/record.toml @@ -0,0 +1,72 @@ +"$schema" = "./posit-publishing-record-schema-v3.json" +server-url = "https://connect.example.com" +id = "de2e7bdb-b085-401e-a65c-443e40009749" +configuration-name = "production.json" + +[configuration] +"$schema" = "./posit-publishing-schema-v3.json" +type = "quarto" +entrypoint = "report.qmd" +title = "Regional Quarterly Sales Report" +description = "This is the quarterly sales report, broken down by region." +thumbnail = "images/thumbnail.jpg" +tags = [ "sales", "quarterly", "regional" ] +secrets = ["API_KEY"] + +[configuration.python] +version = "3.11.3" +package_file = "requirements.txt" +package_manager = "pip" + +[configuration.r] +version = "4.3.1" +package_file = "renv.lock" +package_manager = "renv" + +[configuration.quarto] +version = "1.4" + +[configuration.environment] +API_URL = "https://example.com/api" + +[[configuration.schedules]] +start = "2023-10-25T08:00:00Z" +recurrence = "FREQ=MONTHLY;INTERVAL=3" + +[[configuration.access.users]] +id = "jqpublic" +guid = "536b456e-0311-4f92-ba10-dbf1db8a468e" +name = "John Q. Public" +permissions = "editor" + +[[configuration.access.groups]] +id = "Data Science Team" +guid = "8b4fde3e-f995-4894-bc02-ae47538262ff" +name = "Data Science Team" +permissions = "editor" + +[configuration.connect.access] +run_as = "rstudio-connect" +run_as_current_user = false + +[configuration.connect.runtime] +connection_timeout = 5 +read_timeout = 30 +init_timeout = 60 +idle_timeout = 120 +max_processes = 5 +min_processes = 1 +max_conns_per_process = 50 +load_factor = 0.5 + +[configuration.connect.kubernetes] +amd_gpu_limit = 0 +cpu_limit = 1 +cpu_request = 0.5 +image_name = "posit/connect-runtime-python3.11-r4.3" +memory_limit = "100000000" +memory_request = "20000000" +nvidia_gpu_limit = 0 +service_account_name = "posit-connect-content" +r_environment_management = true +py_environment_management = true diff --git a/schema/posit-publishing-record-schema-v3.json b/schema/posit-publishing-record-schema-v3.json new file mode 100644 index 000000000..3701e9f8c --- /dev/null +++ b/schema/posit-publishing-record-schema-v3.json @@ -0,0 +1,65 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/rstudio/publishing-client/posit-publishing-record-schema-v3.json", + "type": "object", + "additionalProperties": false, + "description": "Posit Publishing Record", + "required": [ + "$schema", + "server-url", + "id", + "configuration-name" + ], + "properties": { + "$schema": { + "type": "string", + "format": "url", + "description": "URL of the json-schema definition for this file. Must be 'https://cdn.posit.co/connect/posit-publishing-record-schema-v3.json'.", + "enum": [ + "./posit-publishing-record-schema-v3.json" + ], + "examples": [ + "https://cdn.posit.co/connect/posit-publishing-record-schema-v3.json" + ] + }, + "server-url": { + "type": "string", + "format": "uri", + "description": "URL of the server where this content was deployed.", + "examples": [ + "https://connect.example.com" + ] + }, + "id": { + "type": "string", + "description": "Unique ID of this deployment.", + "examples": [ + "de2e7bdb-b085-401e-a65c-443e40009749" + ] + }, + "configuration-name": { + "type": "string", + "description": "Name of the configuration that was used during deployment.", + "examples": [ + "production" + ] + }, + "configuration": { + "$ref": "./posit-publishing-schema-v3.json" + }, + "files": { + "type": "array", + "items": { + "type": [ + "string" + ] + }, + "description": "Project-relative paths of the files that were included in the deployment.", + "examples": [ + "app.py", + "model/weights.csv" + ] + + } + } +} diff --git a/schema/posit-publishing-schema-v3.json b/schema/posit-publishing-schema-v3.json new file mode 100644 index 000000000..9b883e198 --- /dev/null +++ b/schema/posit-publishing-schema-v3.json @@ -0,0 +1,364 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/rstudio/publishing-client/posit-publishing-schema-v3.json", + "type": "object", + "additionalProperties": false, + "description": "Posit Publishing Configuration", + "required": [ + "$schema", + "type", + "entrypoint" + ], + "properties": { + "$schema": { + "type": "string", + "format": "url", + "description": "URL of the json-schema definition for this file. Must be 'https://cdn.posit.co/connect/posit-publishing-schema-v3.json'.", + "enum": [ + "./posit-publishing-schema-v3.json" + ], + "examples": [ + "https://cdn.posit.co/connect/posit-publishing-schema-v3.json" + ] + }, + "type": { + "type": "string", + "description": "Indicates the type of content being deployed.", + "enum": [ + "html", + "jupyter-notebook", + "jupyter-voila", + "python-bokeh", + "python-dash", + "python-fastapi", + "python-flask", + "python-shiny", + "python-streamlit", + "quarto-shiny", + "quarto", + "r-plumber", + "r-shiny", + "rmd-shiny", + "rmd" + ], + "examples": [ + "quarto" + ] + }, + "entrypoint": { + "type": "string", + "description": "Name of the primary file containing the content. For some types of Python executable content, this may also indicate the object within the file in module:object format.", + "examples": [ + "app.py", + "report.qmd" + ] + }, + "title": { + "type": "string", + "pattern": "^[^\t\n\f\r]{3,1024}$|", + "description": "Human-readable title for this content.", + "examples": [ + "Quarterly Sales Report" + ] + }, + "description": { + "type": "string", + "description": "Human-readable description for this content.", + "examples": [ + "This is the quarterly sales report, broken down by region." + ] + }, + "python": { + "type": "object", + "additionalProperties": false, + "description": "Python language and dependencies.", + "required": [ + "version" + ], + "properties": { + "version": { + "type": "string", + "description": "Python version. The server must have a matching Python version in order to run the content.", + "examples": [ + "3.11.3", + "3.11" + ] + }, + "package-file": { + "type": "string", + "description": "File containing package dependencies. The file must exist and be listed under 'files'.", + "default": "requirements.txt", + "examples": [ + "requirements.txt" + ] + }, + "package-manager": { + "type": "string", + "default": "pip", + "enum": [ + "pip", + "conda", + "pipenv", + "poetry", + "none" + ], + "description": "Package manager that will install the dependencies. If package-manager is none, dependencies will not be installed.", + "examples": [ + "pip" + ] + } + } + }, + "r": { + "type": "object", + "additionalProperties": false, + "description": "R language and dependencies.", + "required": [ + "version" + ], + "properties": { + "version": { + "type": "string", + "description": "R version. The server must have a similar R version in order to run the content.", + "examples": [ + "4.3.1" + ] + }, + "package-file": { + "type": "string", + "default": "renv.lock", + "description": "File containing package dependencies. The file must exist and be listed under 'files'.", + "examples": [ + "renv.lock" + ] + }, + "package-manager": { + "type": "string", + "default": "renv", + "enum": [ + "renv", + "none" + ], + "description": "Package manager that will install the dependencies. If package-manager is none, dependencies will not be installed.", + "examples": [ + "renv" + ] + } + } + }, + "quarto": { + "type": "object", + "additionalProperties": false, + "description": "Quarto version required to run the content.", + "required": [ + "version" + ], + "properties": { + "version": { + "type": "string", + "description": "Quarto version. The server must have a similar Quarto version in order to run the content.", + "examples": [ + "1.4" + ] + }, + "engines": { + "type": "array", + "description": "List of Quarto engines required for this content.", + "items": { + "type": "string", + "enum": [ + "knitr", + "jupyter" + ], + "examples": [ + "knitr", + "jupyter" + ] + } + } + } + }, + "environment": { + "type": "object", + "additionalProperties": { + "type": [ + "string" + ] + }, + "description": "Environment variable/value map. Secrets such as API keys or tokens should not be stored here.", + "examples": [ + { + "API_URL": "https://example.com/api" + } + ] + }, + "connect": { + "type": "object", + "additionalProperties": false, + "description": "Setting specific to Posit Connect deployments.", + "properties": { + "access": { + "run-as": { + "type": "string", + "description": "The system username under which the content should be run. Must be an existing user in the allowed group. You must be an administrator to set this value.", + "examples": [ + "rstudio-connect" + ] + }, + "run-as-current-user": { + "type": "boolean", + "default": false, + "description": "For application content types, run a separate process for each visiting user under that user's server account. Requires PAM authentication on the Posit Connect server. You must be an administrator to set this value." + } + }, + "runtime": { + "type": "object", + "additionalProperties": false, + "description": "Runtime settings for application content types.", + "properties": { + "connection-timeout": { + "type": "integer", + "minimum": 0, + "description": "Maximum number of seconds allowed without data sent or received across a client connection. A value of `0` means connections will never time-out (not recommended).", + "examples": [ + 5 + ] + }, + "read-timeout": { + "type": "integer", + "minimum": 0, + "description": "Maximum number of seconds allowed without data received from a client connection. A value of `0` means a lack of client (browser) interaction never causes the connection to close.", + "examples": [ + 30 + ] + }, + "init-timeout": { + "type": "integer", + "description": "The maximum number of seconds allowed for an interactive application to start. Posit Connect must be able to connect to a newly launched application before this threshold has elapsed.", + "examples": [ + 60 + ] + }, + "idle-timeout": { + "type": "integer", + "description": "The maximum number of seconds a worker process for an interactive application to remain alive after it goes idle (no active connections).", + "examples": [ + 120 + ] + }, + "max-processes": { + "type": "integer", + "minimum": 1, + "description": "Specifies the total number of concurrent processes allowed for a single interactive application.", + "examples": [ + 5 + ] + }, + "min-processes": { + "type": "integer", + "minimum": 0, + "description": "Specifies the minimum number of concurrent processes allowed for a single interactive application.", + "examples": [ + 1 + ] + }, + "max-connections": { + "type": "integer", + "minimum": 1, + "description": "Specifies the maximum number of client connections allowed to an individual process. Incoming connections which will exceed this limit are routed to a new process or rejected.", + "examples": [ + 50 + ] + }, + "load-factor": { + "type": "number", + "minimum": 0, + "maximum": 1, + "description": "Controls how aggressively new processes are spawned. The valid range is between 0.0 and 1.0.", + "examples": [ + 0.5 + ] + } + } + }, + "kubernetes": { + "type": "object", + "additionalProperties": false, + "description": "Settings used with Posit Connect's off-host execution feature, where content is run in Kubernetes.", + "properties": { + "amd-gpu-limit": { + "type": "integer", + "description": "The number of AMD GPUs that will be allocated by Kubernetes to run this content.", + "examples": [ + 0 + ] + }, + "cpu-limit": { + "type": "integer", + "description": "The maximum amount of compute power this content will be allowed to consume when executing or rendering, expressed in CPU Units, where 1.0 unit is equivalent to 1 physical or virtual core. Fractional values are allowed. If the process tries to use more CPU than allowed, it will be throttled.", + "examples": [ + 1 + ] + }, + "cpu-request": { + "type": "number", + "description": "The minimum amount of compute power this content needs when executing virtual core. Fractional values are allowed.", + "examples": [ + 0.5 + ] + }, + "image-name": { + "type": "string", + "description": "Name of the target container image.", + "examples": [ + "posit/connect-runtime-python3.11-r4.3" + ] + }, + "memory-limit": { + "type": "string", + "description": "The maximum amount of RAM this content will be allowed to consume when executing or rendering, expressed in bytes. If the process tries to use more memory than allowed, it will be terminated", + "examples": [ + "100000000" + ] + }, + "memory-request": { + "type": "string", + "description": "The minimum amount of RAM this content needs when executing or rendering, expressed in bytes.", + "examples": [ + "20000000" + ] + }, + "nvidia-gpu-limit": { + "type": "integer", + "description": "The number of NVIDIA GPUs that will be allocated by Kubernetes to run this content.", + "examples": [ + 0 + ] + }, + "service-account-name": { + "type": "string", + "description": "The name of the Kubernetes service account that is used to run this content. It must adhere to Kubernetes service account naming rules. You must be an administrator to set this value.", + "examples": [ + "posit-connect-content" + ] + }, + "r-environment-management": { + "type": "boolean", + "description": "Enables or disables R environment management. When false, Posit Connect will not install R packages and instead assume that all required packages are present in the container image.", + "examples": [ + true + ] + }, + "py-environment-management": { + "type": "boolean", + "description": "Enables or disables Python environment management. When false, Posit Connect will not install Python packages and instead assume that all required packages are present in the container image.", + "examples": [ + true + ] + } + } + } + } + } + } +} diff --git a/schema/record.toml b/schema/record.toml new file mode 100644 index 000000000..1de26aeac --- /dev/null +++ b/schema/record.toml @@ -0,0 +1,50 @@ +"$schema" = "./posit-publishing-record-schema-v3.json" +server-url = "https://connect.example.com" +id = "de2e7bdb-b085-401e-a65c-443e40009749" +configuration-name = "production" + +[configuration] +"$schema" = "./posit-publishing-schema-v3.json" +type = "quarto" +entrypoint = "report.qmd" +title = "Regional Quarterly Sales Report" +description = "This is the quarterly sales report, broken down by region." + +[configuration.python] +version = "3.11.3" +package_file = "requirements.txt" +package_manager = "pip" + +[configuration.r] +version = "4.3.1" +package_file = "renv.lock" +package_manager = "renv" + +[configuration.quarto] +version = "1.4" + +[configuration.connect.access] +run_as = "rstudio-connect" +run_as_current_user = false + +[configuration.connect.runtime] +connection_timeout = 5 +read_timeout = 30 +init_timeout = 60 +idle_timeout = 120 +max_processes = 5 +min_processes = 1 +max_conns_per_process = 50 +load_factor = 0.5 + +[configuration.connect.kubernetes] +amd_gpu_limit = 0 +cpu_limit = 1 +cpu_request = 0.5 +image_name = "posit/connect-runtime-python3.11-r4.3" +memory_limit = "100000000" +memory_request = "20000000" +nvidia_gpu_limit = 0 +service_account_name = "posit-connect-content" +r_environment_management = true +py_environment_management = true