From a31e4265bdd823d7b7f8624249cb9f87bffb1817 Mon Sep 17 00:00:00 2001 From: Mole Date: Mon, 26 Aug 2024 11:21:02 +0200 Subject: [PATCH] Improve dotnet templates (#16815) * Add delivery api toggle * Add Dockerfile * add docker compose template * Ensure no duplicate database containers * Remove wwwroot/umbraco permission check We don't need write access to this folder * Provide environment variables from dokcer-compose * Build as debug from compose The compose file is intended to be used for local dev * Don't store password in docker files Still not great to store it in .env but it's fine for dev * Add additional template files * Add docker ignore file * Enable delivery API in settings too * Enable models builder mode toggle * Add WIP for umbraco release option * Add starterkit option * Add option to chose LTS or latest * Add development mode option * Add descriptions * Add display names * Add backoffice development at explicit default * Rearrange DevelopmentMode before ModelsBuilderMode * Allow specifying a port for the compose file * Add some notes * Move starterkits into its own template * Don't update version * Remove test configuration from Dockerfile * Add default modelsbuilder option * Update descriptions * overwrite default values in IDE development * Remove obsolete runtime minification * Try and fix healthcheck * Don't use post action for starterkit otherwise it won't work with Rider, also make the version 13.0.0 if LTS is chosen * Move UmbracoVersion above FinalVersion Otherwise, rider will use UmbracoVersion for some weird reason * Fix healthcheck * Use else instead of second if for modelsbuilder * Obsolete UmbracoVersion * Remove custom release option * Use forward slashes for volumes * Add MSSQL_SA_PASSWORD env variable * Temporarily limit acceptance tests so it works * Try again * Disable SQLServer integration tests * Set UseHttps to false in appsettings.Development.json You still want to be able to use non-https when developing locally * Fix LTS version LTS still needs installer endpoints added * Update permissions of wwwroot/umbraco for v13 sites * Fix conditional in Program.cs * Undo pipeline shenanigans --- .../Install/FilePermissionHelper.cs | 1 - src/Umbraco.Web.UI/Program.cs | 5 + templates/Umbraco.Templates.csproj | 3 +- templates/UmbracoDockerCompose/.env | 1 + .../.template.config/dotnetcli.host.json | 24 +++ .../.template.config/ide.host.json | 23 +++ .../.template.config/template.json | 49 ++++++ .../UmbracoDockerCompose/Database/Dockerfile | 21 +++ .../Database/healthcheck.sh | 15 ++ .../UmbracoDockerCompose/Database/setup.sql | 10 ++ .../UmbracoDockerCompose/Database/startup.sh | 23 +++ .../UmbracoDockerCompose/docker-compose.yml | 102 +++++++++++++ templates/UmbracoProject/.dockerignore | 25 ++++ .../.template.config/dotnetcli.host.json | 27 +++- .../.template.config/ide.host.json | 30 +++- .../starterkits.template.json | 47 ++++++ .../.template.config/template.json | 141 +++++++++++++++++- templates/UmbracoProject/Dockerfile | 33 ++++ .../UmbracoProject/UmbracoProject.csproj | 11 +- .../appsettings.Development.json | 23 ++- templates/UmbracoProject/appsettings.json | 20 ++- 21 files changed, 620 insertions(+), 14 deletions(-) create mode 100644 templates/UmbracoDockerCompose/.env create mode 100644 templates/UmbracoDockerCompose/.template.config/dotnetcli.host.json create mode 100644 templates/UmbracoDockerCompose/.template.config/ide.host.json create mode 100644 templates/UmbracoDockerCompose/.template.config/template.json create mode 100644 templates/UmbracoDockerCompose/Database/Dockerfile create mode 100644 templates/UmbracoDockerCompose/Database/healthcheck.sh create mode 100644 templates/UmbracoDockerCompose/Database/setup.sql create mode 100644 templates/UmbracoDockerCompose/Database/startup.sh create mode 100644 templates/UmbracoDockerCompose/docker-compose.yml create mode 100644 templates/UmbracoProject/.dockerignore create mode 100644 templates/UmbracoProject/.template.config/starterkits.template.json create mode 100644 templates/UmbracoProject/Dockerfile diff --git a/src/Umbraco.Infrastructure/Install/FilePermissionHelper.cs b/src/Umbraco.Infrastructure/Install/FilePermissionHelper.cs index ccb3e4a0da..d3777d4113 100644 --- a/src/Umbraco.Infrastructure/Install/FilePermissionHelper.cs +++ b/src/Umbraco.Infrastructure/Install/FilePermissionHelper.cs @@ -51,7 +51,6 @@ public class FilePermissionHelper : IFilePermissionHelper { hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.Bin), hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.Umbraco), - hostingEnvironment.MapPathWebRoot(_globalSettings.UmbracoPath), hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.Packages), }; } diff --git a/src/Umbraco.Web.UI/Program.cs b/src/Umbraco.Web.UI/Program.cs index e91f6ba60d..8fca919b0a 100644 --- a/src/Umbraco.Web.UI/Program.cs +++ b/src/Umbraco.Web.UI/Program.cs @@ -3,7 +3,9 @@ WebApplicationBuilder builder = WebApplication.CreateBuilder(args); builder.CreateUmbracoBuilder() .AddBackOffice() .AddWebsite() +#if UseDeliveryApi .AddDeliveryApi() +#endif .AddComposers() .Build(); @@ -23,6 +25,9 @@ app.UseUmbraco() }) .WithEndpoints(u => { + /*#if (UmbracoRelease = 'LTS') + u.UseInstallerEndpoints(); + #endif */ u.UseBackOfficeEndpoints(); u.UseWebsiteEndpoints(); }); diff --git a/templates/Umbraco.Templates.csproj b/templates/Umbraco.Templates.csproj index 57830bff09..b75df9f9a5 100644 --- a/templates/Umbraco.Templates.csproj +++ b/templates/Umbraco.Templates.csproj @@ -19,6 +19,7 @@ + UmbracoProject\Views\Partials\blocklist\%(RecursiveDir)%(Filename)%(Extension) UmbracoProject\Views\Partials\blocklist @@ -47,7 +48,7 @@ - + <_PackageFiles Include="%(_TemplateJsonFiles.DestinationFile)"> %(_TemplateJsonFiles.RelativeDir) diff --git a/templates/UmbracoDockerCompose/.env b/templates/UmbracoDockerCompose/.env new file mode 100644 index 0000000000..38985be5c5 --- /dev/null +++ b/templates/UmbracoDockerCompose/.env @@ -0,0 +1 @@ +DB_PASSWORD=Password1234 diff --git a/templates/UmbracoDockerCompose/.template.config/dotnetcli.host.json b/templates/UmbracoDockerCompose/.template.config/dotnetcli.host.json new file mode 100644 index 0000000000..aaab590168 --- /dev/null +++ b/templates/UmbracoDockerCompose/.template.config/dotnetcli.host.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://json.schemastore.org/dotnetcli.host.json", + "symbolInfo": { + "ProjectName": { + "longName": "ProjectName", + "shortName": "P" + }, + "DatabasePassword": { + "longName": "DatabasePassword", + "shortName": "dbpw" + }, + "Port": + { + "longName": "Port", + "shortName": "p" + } + }, + "usageExamples": [ + "dotnet new umbraco-compose -P MyProject", + "dotnet new umbraco-compose --ProjectName MyProject", + "dotnet new umbraco-compose -P -MyProject -dbpw MyStr0ngP@ssword", + "dotnet new umbraco-compose -P -MyProject --DatabasePassword MyStr0ngP@ssword" + ] +} diff --git a/templates/UmbracoDockerCompose/.template.config/ide.host.json b/templates/UmbracoDockerCompose/.template.config/ide.host.json new file mode 100644 index 0000000000..ae8c5fb05c --- /dev/null +++ b/templates/UmbracoDockerCompose/.template.config/ide.host.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/ide.host.json", + "order": 0, + "icon": "../../icon.png", + "description": { + "id": "UmbracoDockerCompose", + "text": "Umbraco Docker Compose - Docker compose for Umbraco CMS and associated database" + }, + "symbolInfo": [ + { + "id": "ProjectName", + "isVisible": true + }, + { + "id": "DatabasePassword", + "isVisible": true + }, + { + "id": "Port", + "isVisible": true + } + ] +} diff --git a/templates/UmbracoDockerCompose/.template.config/template.json b/templates/UmbracoDockerCompose/.template.config/template.json new file mode 100644 index 0000000000..6f6877b7e0 --- /dev/null +++ b/templates/UmbracoDockerCompose/.template.config/template.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://json.schemastore.org/template.json", + "author": "Umbraco HQ", + "classifications": [ + "Web", + "CMS", + "Umbraco" + ], + "name": "Umbraco Docker Compose", + "description": "Creates the prerequisites for developing Umbraco in Docker containers", + "groupIdentity": "Umbraco.Templates.UmbracoDockerCompose", + "identity": "Umbraco.Templates.UmbracoDockerCompose", + "shortName": "umbraco-compose", + "tags": { + "type": "item" + }, + "symbols": { + "ProjectName": { + "type": "parameter", + "description": "The name of the project the Docker Compose file will be created for", + "datatype": "string", + "replaces": "UmbracoProject", + "isRequired": true + }, + "DatabasePassword": { + "type": "parameter", + "description": "The password to the database, will be stored in .env file", + "datatype": "string", + "replaces": "Password1234", + "defaultValue": "Password1234" + }, + "Port": { + "type": "parameter", + "description": "The port forward on the docker container, this is the port you use to access the site", + "datatype": "string", + "replaces": "TEMPLATE_PORT", + "defaultValue": "44372" + }, + "ImageName": { + "type": "generated", + "generator": "casing", + "parameters": { + "source": "ProjectName", + "toLower": true + }, + "replaces": "umbraco_image" + } + } +} diff --git a/templates/UmbracoDockerCompose/Database/Dockerfile b/templates/UmbracoDockerCompose/Database/Dockerfile new file mode 100644 index 0000000000..4e74b6435e --- /dev/null +++ b/templates/UmbracoDockerCompose/Database/Dockerfile @@ -0,0 +1,21 @@ +FROM mcr.microsoft.com/azure-sql-edge:latest + +ENV ACCEPT_EULA=Y + +USER root + +RUN mkdir /var/opt/sqlserver + +RUN chown mssql /var/opt/sqlserver + +ENV MSSQL_BACKUP_DIR="/var/opt/mssql" +ENV MSSQL_DATA_DIR="/var/opt/mssql/data" +ENV MSSQL_LOG_DIR="/var/opt/mssql/log" + +EXPOSE 1433/tcp +COPY setup.sql / +COPY startup.sh / +COPY healthcheck.sh / + +ENTRYPOINT [ "/bin/bash", "startup.sh" ] +CMD [ "/opt/mssql/bin/sqlservr" ] diff --git a/templates/UmbracoDockerCompose/Database/healthcheck.sh b/templates/UmbracoDockerCompose/Database/healthcheck.sh new file mode 100644 index 0000000000..2964e17dc4 --- /dev/null +++ b/templates/UmbracoDockerCompose/Database/healthcheck.sh @@ -0,0 +1,15 @@ +value="$(/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "$SA_PASSWORD" -d master -Q "SELECT state_desc FROM sys.databases WHERE name = 'umbracoDb'" | awk 'NR==3')" + +# This checks for any non-zero length string, and $value will be empty when the database does not exist. +if [ -n "$value" ] +then + echo "ONLINE" + return 0 # With docker 0 = success +else + echo "OFFLINE" + return 1 # And 1 = unhealthy +fi + +# This is useful for debugging +# echo "Value is:" +# echo "$value" diff --git a/templates/UmbracoDockerCompose/Database/setup.sql b/templates/UmbracoDockerCompose/Database/setup.sql new file mode 100644 index 0000000000..466030dd50 --- /dev/null +++ b/templates/UmbracoDockerCompose/Database/setup.sql @@ -0,0 +1,10 @@ +USE [master] +GO + +IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = 'UmbracoDb') + BEGIN + CREATE DATABASE [umbracoDb] + END; +GO + +USE UmbracoDb; \ No newline at end of file diff --git a/templates/UmbracoDockerCompose/Database/startup.sh b/templates/UmbracoDockerCompose/Database/startup.sh new file mode 100644 index 0000000000..c4fad8f0ae --- /dev/null +++ b/templates/UmbracoDockerCompose/Database/startup.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -e + +# Taken from: https://github.com/CarlSargunar/Umbraco-Docker-Workshop +if [ "$1" = '/opt/mssql/bin/sqlservr' ]; then + # If this is the container's first run, initialize the application database + if [ ! -f /tmp/app-initialized ]; then + # Initialize the application database asynchronously in a background process. This allows a) the SQL Server process to be the main process in the container, which allows graceful shutdown and other goodies, and b) us to only start the SQL Server process once, as opposed to starting, stopping, then starting it again. + function initialize_app_database() { + # Wait a bit for SQL Server to start. SQL Server's process doesn't provide a clever way to check if it's up or not, and it needs to be up before we can import the application database + sleep 15s + + #run the setup script to create the DB and the schema in the DB + /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "$SA_PASSWORD" -d master -i setup.sql + + # Note that the container has been initialized so future starts won't wipe changes to the data + touch /tmp/app-initialized + } + initialize_app_database & + fi +fi + +exec "$@" diff --git a/templates/UmbracoDockerCompose/docker-compose.yml b/templates/UmbracoDockerCompose/docker-compose.yml new file mode 100644 index 0000000000..7acae5d8d6 --- /dev/null +++ b/templates/UmbracoDockerCompose/docker-compose.yml @@ -0,0 +1,102 @@ +services: + umb_database: + container_name: umbraco_image_database + build: + context: ./Database + environment: + SA_PASSWORD: ${DB_PASSWORD} + MSSQL_SA_PASSWORD: ${DB_PASSWORD} + ports: + - "1433:1433" + - "1434:1434" + volumes: + - umb_database:/var/opt/mssql + networks: + - umbnet + healthcheck: + # This healthcheck is to make sure that the database is up and running before the umbraco container starts. + # It works by querying the database for the state of the umbracoDb database, ensuring it exists. + test: ./healthcheck.sh + interval: 5m + timeout: 5s + retries: 3 + start_period: 15s # Bootstrap duration, for this duration failures does not count towards max retries. + start_interval: 5s # How long after the health check has started to run the healthcheck again. + + umbraco_image: + image: umbraco_image + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ConnectionStrings__umbracoDbDSN=Server=umb_database;Database=umbracoDb;User Id=sa;Password=${DB_PASSWORD};TrustServerCertificate=true; + - ConnectionStrings__umbracoDbDSN_ProviderName=Microsoft.Data.SqlClient + volumes: + - umb_media:/app/wwwroot/media + - umb_scripts:/app/wwwroot/scripts + - umb_styles:/app/wwwroot/css + - umb_logs:/app/umbraco/Logs + - umb_views:/app/Views + - umb_data:/app/umbraco + - umb_models:/app/umbraco/models + build: + context: . + dockerfile: UmbracoProject/Dockerfile + args: + - BUILD_CONFIGURATION=Debug + + depends_on: + umb_database: + condition: service_healthy + restart: always + ports: + - "TEMPLATE_PORT:8080" + networks: + - umbnet + develop: + # This allows you to run docker compose watch, after doing so the container will rebuild when the models are changed. + # Once a restart only feature is implemented (https://github.com/docker/compose/issues/11446) + # It would be really nice to add a restart only watch to \Views, since the file watchers for recompilation of Razor views does not work with docker. + watch: + - path: ./UmbracoProject/umbraco/models + action: rebuild + +# These volumes are all made as bind mounts, meaning that they are bound to the host machine's file system. +# This is to better facilitate local development in the IDE, so the views, models, etc... are available in the IDE. +# This can be changed by removing the driver and driver_opts from the volumes. +volumes: + umb_media: + driver: local + driver_opts: + type: none + device: ./UmbracoProject/wwwroot/media + o: bind + umb_scripts: + driver: local + driver_opts: + type: none + device: ./UmbracoProject/wwwroot/scripts + o: bind + umb_styles: + driver: local + driver_opts: + type: none + device: ./UmbracoProject/wwwroot/css + o: bind + umb_logs: + umb_views: + driver: local + driver_opts: + type: none + device: ./UmbracoProject/Views + o: bind + umb_data: + umb_models: + driver: local + driver_opts: + type: none + device: ./UmbracoProject/umbraco/models + o: bind + umb_database: + +networks: + umbnet: + driver: bridge diff --git a/templates/UmbracoProject/.dockerignore b/templates/UmbracoProject/.dockerignore new file mode 100644 index 0000000000..2f32bfe4fe --- /dev/null +++ b/templates/UmbracoProject/.dockerignore @@ -0,0 +1,25 @@ +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/.idea +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md diff --git a/templates/UmbracoProject/.template.config/dotnetcli.host.json b/templates/UmbracoProject/.template.config/dotnetcli.host.json index dfd6f80184..b18020b6de 100644 --- a/templates/UmbracoProject/.template.config/dotnetcli.host.json +++ b/templates/UmbracoProject/.template.config/dotnetcli.host.json @@ -8,12 +8,25 @@ }, "UmbracoVersion": { "longName": "version", - "shortName": "v" + "shortName": "v", + "isHidden": true + }, + "UmbracoRelease": { + "longName": "release", + "shortName": "r" }, "UseHttpsRedirect": { "longName": "use-https-redirect", "shortName": "" }, + "UseDeliveryApi": { + "longName": "use-delivery-api", + "shortName": "da" + }, + "Docker": { + "longName": "add-docker", + "shortName": "" + }, "SkipRestore": { "longName": "no-restore", "shortName": "" @@ -58,6 +71,18 @@ "longName": "PackageTestSiteName", "shortName": "p", "isHidden": true + }, + "ModelsBuilderMode": { + "longName": "models-mode", + "shortName": "mm" + }, + "StarterKit": { + "longName": "starter-kit", + "shortName": "sk" + }, + "DevelopmentMode": { + "longName": "development-mode", + "shortName": "dm" } }, "usageExamples": [ diff --git a/templates/UmbracoProject/.template.config/ide.host.json b/templates/UmbracoProject/.template.config/ide.host.json index 1a302779cc..90de3b977a 100644 --- a/templates/UmbracoProject/.template.config/ide.host.json +++ b/templates/UmbracoProject/.template.config/ide.host.json @@ -9,11 +9,22 @@ "symbolInfo": [ { "id": "UmbracoVersion", - "isVisible": true + "isVisible": false }, { "id": "UseHttpsRedirect", "isVisible": true, + "persistenceScope": "templateGroup", + "defaultValue": "true" + }, + { + "id": "UseDeliveryApi", + "isVisible": true, + "persistenceScope": "templateGroup" + }, + { + "id": "ModelsBuilderMode", + "isVisible": true, "persistenceScope": "templateGroup" }, { @@ -54,6 +65,23 @@ { "id": "NoNodesViewPath", "isVisible": true + }, + { + "id": "Docker", + "isVisible": true + }, + { + "id": "StarterKit", + "isVisible": true + }, + { + "id": "UmbracoRelease", + "isVisible": true + }, + { + "id": "DevelopmentMode", + "isVisible": true, + "defaultValue": "IDEDevelopment" } ] } diff --git a/templates/UmbracoProject/.template.config/starterkits.template.json b/templates/UmbracoProject/.template.config/starterkits.template.json new file mode 100644 index 0000000000..5d2a5dabf9 --- /dev/null +++ b/templates/UmbracoProject/.template.config/starterkits.template.json @@ -0,0 +1,47 @@ +{ + "$schema": "https://json.schemastore.org/template.json", + "symbols": { + "StarterKit": { + "displayName": "Starter kit", + "type": "parameter", + "datatype": "choice", + "description": "Choose a starter kit to install.", + "defaultValue": "None", + "replaces": "STARTER_KIT_NAME", + // The choice here should be the name of the starter kit package, since it will be used directly for package reference. + "choices": [ + { + "choice": "None", + "description": "No starter kit." + }, + { + "choice": "Umbraco.TheStarterKit", + "description": "The Umbraco starter kit.", + "displayName": "The Starter Kit" + } + ] + }, + // Used to determine the version of the starter kit to install. + // there should be cases for Latest, LTS and Custom for every starterkit added above. + // This has the benefit that all maintenance of starter kits in template can be done from this file. + "StarterKitVersion": { + "type": "generated", + "generator": "switch", + "replaces": "STARTER_KIT_VERSION", + "parameters": { + "evaluator": "C++", + "datatype": "string", + "cases": [ + { + "condition": "(StarterKit == 'Umbraco.TheStarterKit' && (UmbracoRelease == 'Latest' || UmbracoRelease == 'Custom'))", + "value": "14.0.0" + }, + { + "condition": "(StarterKit == 'Umbraco.TheStarterKit' && UmbracoRelease == 'LTS')", + "value": "13.0.0" + } + ] + } + } + } +} diff --git a/templates/UmbracoProject/.template.config/template.json b/templates/UmbracoProject/.template.config/template.json index b17352476e..e342cdaeb8 100644 --- a/templates/UmbracoProject/.template.config/template.json +++ b/templates/UmbracoProject/.template.config/template.json @@ -18,6 +18,7 @@ "sourceName": "UmbracoProject", "defaultName": "UmbracoProject1", "preferNameDirectory": true, + "additionalConfigFiles": [ "starterkits.template.json"], "sources": [ { "modifiers": [ @@ -26,6 +27,13 @@ "exclude": [ ".gitignore" ] + }, + { + "condition": "(!Docker)", + "exclude": [ + "Dockerfile", + ".dockerignore" + ] } ] } @@ -46,13 +54,72 @@ "defaultValue": "net8.0", "replaces": "net8.0" }, + "UmbracoRelease": { + "displayName": "Umbraco Version", + "description": "The Umbraco release to use, either latest or latest long term supported", + "type": "parameter", + "datatype": "choice", + "defaultValue": "Latest", + "choices": [ + { + "choice": "Latest", + "description": "The latest umbraco release" + }, + { + "choice": "LTS", + "description": "The most recent long term supported version", + "displayName": "Long Term Supported" + } + ], + "isRequired": false + }, "UmbracoVersion": { - "displayName": "Umbraco version", - "description": "The version of Umbraco.Cms to add as PackageReference.", + "displayName": "Custom Version", + "description": "The selected custom version of Umbraco, this is obsoleted, and will be removed in a future version of the template.", "type": "parameter", "datatype": "string", - "defaultValue": "*", - "replaces": "UMBRACO_VERSION_FROM_TEMPLATE" + "defaultValue": "null", + "replaces": "CUSTOM_VERSION", + "isRequired": false + }, + "FinalVersion" : { + "type": "generated", + "generator": "switch", + "datatype": "text", + "description": "The calculated version of Umbraco to use", + "replaces": "UMBRACO_VERSION_FROM_TEMPLATE", + "parameters": { + "evaluator": "C++", + "datatype": "text", + "cases": [ + { + "condition": "(UmbracoRelease == 'Latest')", + "value": "*" + }, + { + "condition": "(UmbracoRelease == 'LTS')", + "value": "13.4.1" + } + ] + } + }, + "DotnetVersion": + { + "type": "generated", + "generator": "switch", + "datatype": "text", + "description": "Not relevant at the moment, but if we need to change the dotnet version based on the Umbraco version, we can do it here", + "replaces": "DOTNET_VERSION_FROM_TEMPLATE", + "parameters": { + "evaluator": "C++", + "datatype": "text", + "cases": [ + { + "condition": "(true)", + "value": "net8.0" + } + ] + } }, "UseHttpsRedirect": { "displayName": "Use HTTPS redirect", @@ -61,6 +128,20 @@ "datatype": "bool", "defaultValue": "false" }, + "UseDeliveryApi": { + "displayName": "Use Delivery API", + "description": "Enables the Delivery API", + "type": "parameter", + "datatype": "bool", + "defaultValue": "false" + }, + "Docker": { + "displayName": "Add Docker file", + "description": "Adds a docker file to the project.", + "type": "parameter", + "datatype": "bool", + "defaultValue": "false" + }, "SkipRestore": { "displayName": "Skip restore", "description": "If specified, skips the automatic restore of the project on create.", @@ -244,6 +325,58 @@ "defaultValue": "", "replaces": "PACKAGE_PROJECT_NAME_FROM_TEMPLATE" }, + "DevelopmentMode": { + "type": "parameter", + "displayName": "Development mode", + "datatype": "choice", + "description": "Choose the development mode to use for the project.", + "defaultValue": "BackofficeDevelopment", + "choices": [ + { + "choice": "BackofficeDevelopment", + "description": "Enables backoffice development, allowing you to develop from within the backoffice, this is the default behaviour.", + "displayName": "Backoffice Development" + }, + { + "choice": "IDEDevelopment", + "description": "Configures appsettings.Development.json to Development runtime mode and SourceCodeAuto models builder mode, and configures appsettings.json to Production runtime mode, Nothing models builder mode, and enables UseHttps", + "displayName": "IDE Development" + } + ] + }, + "ModelsBuilderMode": { + "type": "parameter", + "displayName": "Models builder mode", + "datatype": "choice", + "description": "Choose the models builder mode to use for the project. When development mode is set to IDEDevelopment this only changes the models builder mode appsetttings.development.json", + "defaultValue": "Default", + "replaces": "MODELS_MODE", + "choices": [ + { + "choice": "Default", + "description": "Let DevelopmentMode determine the models builder mode." + }, + { + "choice": "InMemoryAuto", + "description": "Generate models in memory, automatically updating when a content type change, this means no need for app rebuild, however models are only available in views.", + "displayName": "In Memory Auto" + }, + { + "choice": "SourceCodeManual", + "description": "Generate models as source code, only updating when requested manually, this means a interaction and rebuild is required when content type(s) change, however models are available in code.", + "displayName": "Source Code Manual" + }, + { + "choice": "SourceCodeAuto", + "description": "Generate models as source code, automatically updating when a content type change, this means a rebuild is required when content type(s) change, however models are available in code.", + "displayName": "Source Code Auto" + }, + { + "choice": "Nothing", + "description": "No models are generated, this is recommended for production assuming generated models are used for development." + } + ] + }, "Namespace": { "type": "derived", "valueSource": "name", diff --git a/templates/UmbracoProject/Dockerfile b/templates/UmbracoProject/Dockerfile new file mode 100644 index 0000000000..e3eda648dd --- /dev/null +++ b/templates/UmbracoProject/Dockerfile @@ -0,0 +1,33 @@ +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +USER $APP_UID +WORKDIR /app +EXPOSE 8080 +EXPOSE 8081 + +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["UmbracoProject/UmbracoProject.csproj", "UmbracoProject/"] +RUN dotnet restore "UmbracoProject/UmbracoProject.csproj" +COPY . . +WORKDIR "/src/UmbracoProject" +RUN dotnet build "UmbracoProject.csproj" -c $BUILD_CONFIGURATION -o /app/build + +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "UmbracoProject.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +# We need to make sure that the user running the app has write access to the umbraco folder, in order to write logs and other files. +# Since these are volumes they are created as root by the docker daemon. +USER root +RUN mkdir umbraco +RUN mkdir umbraco/Logs +RUN chown $APP_UID umbraco --recursive +#if (UmbracoRelease = 'LTS') +RUN chown $APP_UID wwwroot/umbraco --recursive +#endif +USER $APP_UID +ENTRYPOINT ["dotnet", "UmbracoProject.dll"] diff --git a/templates/UmbracoProject/UmbracoProject.csproj b/templates/UmbracoProject/UmbracoProject.csproj index ee8dd5e56e..019d5d2990 100644 --- a/templates/UmbracoProject/UmbracoProject.csproj +++ b/templates/UmbracoProject/UmbracoProject.csproj @@ -1,13 +1,20 @@ - net8.0 + DOTNET_VERSION_FROM_TEMPLATE enable enable Umbraco.Cms.Web.UI + + + + @@ -21,11 +28,13 @@ true + false false + diff --git a/templates/UmbracoProject/appsettings.Development.json b/templates/UmbracoProject/appsettings.Development.json index 17b9f86361..0521b835ed 100644 --- a/templates/UmbracoProject/appsettings.Development.json +++ b/templates/UmbracoProject/appsettings.Development.json @@ -25,6 +25,11 @@ //#endif "Umbraco": { "CMS": { + //#if (UseHttpsRedirect || DevelopmentMode == "IDEDevelopment") + "Global": { + "UseHttps": false + }, + //#endif //#if (UsingUnattenedInstall) "Unattended": { "InstallUnattended": true, @@ -36,12 +41,22 @@ "Content": { "MacroErrors": "Throw" }, + //#if (DevelopmentMode == "IDEDevelopment") + "Runtime": { + "Mode": "Development" + }, + //#if (ModelsBuilderMode == "Default") + "ModelsBuilder": { + "ModelsMode": "SourceCodeAuto" + }, + ////#else + //"ModelsBuilder": { + // "ModelsMode": "MODELS_MODE" + //}, + //#endif + //#endif "Hosting": { "Debug": true - }, - "RuntimeMinification": { - "UseInMemoryCache": true, - "CacheBuster": "Timestamp" } } } diff --git a/templates/UmbracoProject/appsettings.json b/templates/UmbracoProject/appsettings.json index 6678478951..23520bbe6b 100644 --- a/templates/UmbracoProject/appsettings.json +++ b/templates/UmbracoProject/appsettings.json @@ -20,7 +20,7 @@ "CMS": { "Global": { "Id": "TELEMETRYID_FROM_TEMPLATE", - //#if (UseHttpsRedirect) + //#if (UseHttpsRedirect || DevelopmentMode == "IDEDevelopment") "UseHttps": true, //#endif //#if (HasNoNodesViewPath) @@ -37,6 +37,24 @@ "Unattended": { "UpgradeUnattended": true }, + //#if (UseDeliveryApi) + "DeliveryApi": { + "Enabled": true + }, + //#endif + //#if (ModelsBuilderMode != "Default" && DevelopmentMode == "BackOfficeDevelopment") + "ModelsBuilder": { + "ModelsMode": "MODELS_MODE" + }, + //#endif + //#if (DevelopmentMode == "IDEDevelopment") + "Runtime": { + "Mode": "Production" + }, + "ModelsBuilder": { + "ModelsMode": "Nothing" + }, + //#endif "Security": { "AllowConcurrentLogins": false }