From 2095cd845bbb0672f6345ec087abb2bb4ec23982 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Mon, 16 May 2022 11:11:18 +0200 Subject: [PATCH 001/810] Module Federation Documentation. --- docs/classic-ui/module-federation.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 docs/classic-ui/module-federation.md diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md new file mode 100644 index 000000000..0e8a956b8 --- /dev/null +++ b/docs/classic-ui/module-federation.md @@ -0,0 +1,11 @@ +--- +html_meta: + "description": "How to use Module Federation in Mockup and add-on bundles." + "property=og:description": "How to use Module Federation in Mockup and add-on bundles." + "property=og:title": "Module Federation in Mockup" + "keywords": "Plone, Classic UI, classic-ui, Mockup, mockup, Module Federation, Webpack, JavaScript" +--- + +(classic-ui-module-federation-in-mockup-label)= + +# Module Federation in Mockup From c406f842f91038a11a0e0cf7692beb5713f3c3ed Mon Sep 17 00:00:00 2001 From: Manuel Reinhardt Date: Wed, 18 May 2022 14:41:46 +0200 Subject: [PATCH 002/810] Extended module federation documentation. --- docs/classic-ui/module-federation.md | 53 ++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index 0e8a956b8..07128900b 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -9,3 +9,56 @@ html_meta: (classic-ui-module-federation-in-mockup-label)= # Module Federation in Mockup + +## Introduction + +For a general introduction see: https://webpack.js.org/concepts/module-federation/ + +Module Federation allows to share dependencies between bundles. +Each bundle includes the whole set of dependencies. +However, if multiple bundles have the same dependencies they are only loaded once. + +For example, if bundle A and B both depend on jQuery and bundle A has already loaded it, bundle B can just reuse the already loaded jQuery file. +But if only bundle B is loaded, it uses its own bundled version of the jQuery library. + +There is a host bundle - in the fictional example above our bundle "A". +In Plone the host bundle is the main mockup bundle. +Addons can add bundles called "remotes" which are initialized for module federation by the host bundle. + +## Using module federation + +Starting with the webpack configuration that you get when creating a barceloneta theme package via [plonecli][1], add the following: + +- Create a new entry point ``index.js`` which only imports the normal entry point. + +``` +import("./patterns"); +``` + +- Add the module federation plugin in webpack.config.js. There is a configuration factory `mf_config` which you can use for that. Add the following line near the top of the file: + +``` +const mf_config = require("@patternslib/patternslib/webpack/webpack.mf"); +``` + +Then find the following line: + +``` + config = patternslib_config(env, argv, config, ["mockup"]); +``` + +Below this line add the following: + +``` + config.plugins.push( + mf_config({ + filename: "myaddon-remote.min.js", + package_json: package_json, + remote_entry: config.entry["myaddon.min"], + }) + ); +``` + +Replace `myaddon-remote.min.js` with the file name you want to use for your remote bundle. Replace `myaddon.min` with the corresponding key in `config.entry` that points to your `index.js`. + +[1]: https://pypi.org/project/plonecli/ From c0b4a2b70fcec5a76c72b57b0b9fc6405af88755 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Mon, 13 Jun 2022 12:37:31 +0200 Subject: [PATCH 003/810] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Katja Süss --- docs/classic-ui/module-federation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index 07128900b..a94aa81c4 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -26,7 +26,7 @@ In Plone the host bundle is the main mockup bundle. Addons can add bundles called "remotes" which are initialized for module federation by the host bundle. ## Using module federation - +This instruction is for you if you created an add-on with a Mockup pattern and you want to include the respective Javascript code in your theme code. Starting with the webpack configuration that you get when creating a barceloneta theme package via [plonecli][1], add the following: - Create a new entry point ``index.js`` which only imports the normal entry point. From 96369664c266d31c1d5055fc0dc866d4372c3056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Katja=20S=C3=BCss?= Date: Mon, 13 Jun 2022 13:26:30 +0200 Subject: [PATCH 004/810] Update docs/classic-ui/module-federation.md Co-authored-by: Steve Piercy --- docs/classic-ui/module-federation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index a94aa81c4..ae23f0609 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -26,7 +26,7 @@ In Plone the host bundle is the main mockup bundle. Addons can add bundles called "remotes" which are initialized for module federation by the host bundle. ## Using module federation -This instruction is for you if you created an add-on with a Mockup pattern and you want to include the respective Javascript code in your theme code. +This instruction is for you if you created an add-on with a Mockup pattern and you want to include the respective JavaScript code in your theme code. Starting with the webpack configuration that you get when creating a barceloneta theme package via [plonecli][1], add the following: - Create a new entry point ``index.js`` which only imports the normal entry point. From 9f72377bd50a8a03d19b2b206ca831d94c216fa8 Mon Sep 17 00:00:00 2001 From: Peter Mathis Date: Tue, 19 Jul 2022 10:12:00 +0200 Subject: [PATCH 005/810] new @patternslib/dev package and note on global modules --- docs/classic-ui/module-federation.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index ae23f0609..e5ff01831 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -14,9 +14,9 @@ html_meta: For a general introduction see: https://webpack.js.org/concepts/module-federation/ -Module Federation allows to share dependencies between bundles. +Module Federation allows to share dependencies between bundles. Each bundle includes the whole set of dependencies. -However, if multiple bundles have the same dependencies they are only loaded once. +However, if multiple bundles have the same dependencies they are loaded only once. For example, if bundle A and B both depend on jQuery and bundle A has already loaded it, bundle B can just reuse the already loaded jQuery file. But if only bundle B is loaded, it uses its own bundled version of the jQuery library. @@ -38,7 +38,7 @@ import("./patterns"); - Add the module federation plugin in webpack.config.js. There is a configuration factory `mf_config` which you can use for that. Add the following line near the top of the file: ``` -const mf_config = require("@patternslib/patternslib/webpack/webpack.mf"); +const mf_config = require("@patternslib/dev/webpack/webpack.mf"); ``` Then find the following line: @@ -62,3 +62,16 @@ Below this line add the following: Replace `myaddon-remote.min.js` with the file name you want to use for your remote bundle. Replace `myaddon.min` with the corresponding key in `config.entry` that points to your `index.js`. [1]: https://pypi.org/project/plonecli/ + +## Special case: global modules ``jQuery`` and ``Bootstrap`` + +In order to preserve compatibility with older addons and JavaScript implementations, +the modules ``jQuery`` and ``Bootstrap`` are stored in the global ``window`` namespace. +So constructs like the following are still working: + +``` + (function($) { + // JS code which uses $ + })(jQuery); +``` + From 17b11c7612edc043022587827bc9ae60690795f2 Mon Sep 17 00:00:00 2001 From: Peter Mathis Date: Tue, 19 Jul 2022 10:28:12 +0200 Subject: [PATCH 006/810] fix single backtick and lexer for code blocks --- docs/classic-ui/module-federation.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index e5ff01831..8fead1336 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -29,27 +29,27 @@ Addons can add bundles called "remotes" which are initialized for module federat This instruction is for you if you created an add-on with a Mockup pattern and you want to include the respective JavaScript code in your theme code. Starting with the webpack configuration that you get when creating a barceloneta theme package via [plonecli][1], add the following: -- Create a new entry point ``index.js`` which only imports the normal entry point. +- Create a new entry point `index.js` which only imports the normal entry point. -``` +```js import("./patterns"); ``` - Add the module federation plugin in webpack.config.js. There is a configuration factory `mf_config` which you can use for that. Add the following line near the top of the file: -``` +```js const mf_config = require("@patternslib/dev/webpack/webpack.mf"); ``` Then find the following line: -``` +```js config = patternslib_config(env, argv, config, ["mockup"]); ``` Below this line add the following: -``` +```js config.plugins.push( mf_config({ filename: "myaddon-remote.min.js", @@ -63,13 +63,13 @@ Replace `myaddon-remote.min.js` with the file name you want to use for your remo [1]: https://pypi.org/project/plonecli/ -## Special case: global modules ``jQuery`` and ``Bootstrap`` +## Special case: global modules `jQuery` and `Bootstrap` In order to preserve compatibility with older addons and JavaScript implementations, -the modules ``jQuery`` and ``Bootstrap`` are stored in the global ``window`` namespace. +the modules `jQuery` and `Bootstrap` are stored in the global `window` namespace. So constructs like the following are still working: -``` +```js (function($) { // JS code which uses $ })(jQuery); From 1b69e41e285266c3824f9804bf30fec5a683e077 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Thu, 21 Jul 2022 01:10:02 +0200 Subject: [PATCH 007/810] Update docs/classic-ui/module-federation.md Co-authored-by: Steve Piercy --- docs/classic-ui/module-federation.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index 8fead1336..8b0adfc91 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -10,7 +10,6 @@ html_meta: # Module Federation in Mockup -## Introduction For a general introduction see: https://webpack.js.org/concepts/module-federation/ From 662e21ebd1a2e4ca1c64638efe8eb793bef846b0 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Thu, 21 Jul 2022 01:10:59 +0200 Subject: [PATCH 008/810] Update docs/classic-ui/module-federation.md Co-authored-by: Steve Piercy --- docs/classic-ui/module-federation.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index 8b0adfc91..50f954582 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -11,7 +11,9 @@ html_meta: # Module Federation in Mockup -For a general introduction see: https://webpack.js.org/concepts/module-federation/ +```{seealso} +Webpack's documentation on [Module Federation](https://webpack.js.org/concepts/module-federation/). +``` Module Federation allows to share dependencies between bundles. Each bundle includes the whole set of dependencies. From a2f09be23046bbe028e82bce73fa8a0454d84822 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Thu, 21 Jul 2022 01:11:33 +0200 Subject: [PATCH 009/810] Update docs/classic-ui/module-federation.md Co-authored-by: Steve Piercy --- docs/classic-ui/module-federation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index 50f954582..2142c79b7 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -15,7 +15,7 @@ html_meta: Webpack's documentation on [Module Federation](https://webpack.js.org/concepts/module-federation/). ``` -Module Federation allows to share dependencies between bundles. +Module Federation allows sharing of dependencies between bundles. Each bundle includes the whole set of dependencies. However, if multiple bundles have the same dependencies they are loaded only once. From 6578cd224ff91be198e9617d4baa5e429f1ac46a Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Thu, 21 Jul 2022 01:12:00 +0200 Subject: [PATCH 010/810] Update docs/classic-ui/module-federation.md Co-authored-by: Steve Piercy --- docs/classic-ui/module-federation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index 2142c79b7..40e4df7b1 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -22,7 +22,7 @@ However, if multiple bundles have the same dependencies they are loaded only onc For example, if bundle A and B both depend on jQuery and bundle A has already loaded it, bundle B can just reuse the already loaded jQuery file. But if only bundle B is loaded, it uses its own bundled version of the jQuery library. -There is a host bundle - in the fictional example above our bundle "A". +There is a host bundle, as in the fictional example above, our bundle A. In Plone the host bundle is the main mockup bundle. Addons can add bundles called "remotes" which are initialized for module federation by the host bundle. From 9c7285f89aff094ba50ba04a7d40a9947d6d8237 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Thu, 21 Jul 2022 01:12:16 +0200 Subject: [PATCH 011/810] Update docs/classic-ui/module-federation.md Co-authored-by: Steve Piercy --- docs/classic-ui/module-federation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index 40e4df7b1..ca23f8cd3 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -24,7 +24,7 @@ But if only bundle B is loaded, it uses its own bundled version of the jQuery li There is a host bundle, as in the fictional example above, our bundle A. In Plone the host bundle is the main mockup bundle. -Addons can add bundles called "remotes" which are initialized for module federation by the host bundle. +Add-ons can add bundles called "remotes" which are initialized for module federation by the host bundle. ## Using module federation This instruction is for you if you created an add-on with a Mockup pattern and you want to include the respective JavaScript code in your theme code. From 6a72e3a6ff7ae6b2f9afe49ab8cb8c698ba69040 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Thu, 21 Jul 2022 01:12:49 +0200 Subject: [PATCH 012/810] Update docs/classic-ui/module-federation.md Co-authored-by: Steve Piercy --- docs/classic-ui/module-federation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index ca23f8cd3..8600960e4 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -27,7 +27,7 @@ In Plone the host bundle is the main mockup bundle. Add-ons can add bundles called "remotes" which are initialized for module federation by the host bundle. ## Using module federation -This instruction is for you if you created an add-on with a Mockup pattern and you want to include the respective JavaScript code in your theme code. +The following instructions are for you if you created an add-on with a Mockup pattern and you want to include the respective JavaScript code in your theme code. Starting with the webpack configuration that you get when creating a barceloneta theme package via [plonecli][1], add the following: - Create a new entry point `index.js` which only imports the normal entry point. From 490b6599bff89a4e572482b63898e0a6c4861f27 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Thu, 21 Jul 2022 01:13:55 +0200 Subject: [PATCH 013/810] Update docs/classic-ui/module-federation.md Co-authored-by: Steve Piercy --- docs/classic-ui/module-federation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index 8600960e4..3cfbd54e7 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -28,7 +28,7 @@ Add-ons can add bundles called "remotes" which are initialized for module federa ## Using module federation The following instructions are for you if you created an add-on with a Mockup pattern and you want to include the respective JavaScript code in your theme code. -Starting with the webpack configuration that you get when creating a barceloneta theme package via [plonecli][1], add the following: +Starting with the webpack configuration that you get when creating a Barceloneta theme package via [plonecli][1], add the following: - Create a new entry point `index.js` which only imports the normal entry point. From 412a636a669af9b18d3aff20114a5b3eb12fd533 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Thu, 21 Jul 2022 01:14:44 +0200 Subject: [PATCH 014/810] Update docs/classic-ui/module-federation.md Co-authored-by: Steve Piercy --- docs/classic-ui/module-federation.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index 3cfbd54e7..781c06de2 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -36,7 +36,9 @@ Starting with the webpack configuration that you get when creating a Barceloneta import("./patterns"); ``` -- Add the module federation plugin in webpack.config.js. There is a configuration factory `mf_config` which you can use for that. Add the following line near the top of the file: +Next add the module federation plugin in `webpack.config.js`. +There is a configuration factory `mf_config` which you can use for that. +Add the following line near the top of the file: ```js const mf_config = require("@patternslib/dev/webpack/webpack.mf"); From de8edb189ec91d8c89312e25757e71c8ffb9fa5c Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Thu, 21 Jul 2022 01:15:49 +0200 Subject: [PATCH 015/810] Update docs/classic-ui/module-federation.md Co-authored-by: Steve Piercy --- docs/classic-ui/module-federation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index 781c06de2..a0f721b0a 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -30,7 +30,7 @@ Add-ons can add bundles called "remotes" which are initialized for module federa The following instructions are for you if you created an add-on with a Mockup pattern and you want to include the respective JavaScript code in your theme code. Starting with the webpack configuration that you get when creating a Barceloneta theme package via [plonecli][1], add the following: -- Create a new entry point `index.js` which only imports the normal entry point. +Create a new entry point `index.js` which only imports the normal entry point. ```js import("./patterns"); From f2a9188044150aed19855e41ce684dbbc85fbc15 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Thu, 21 Jul 2022 01:16:23 +0200 Subject: [PATCH 016/810] Update docs/classic-ui/module-federation.md Co-authored-by: Steve Piercy --- docs/classic-ui/module-federation.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index a0f721b0a..c4b6509c7 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -62,7 +62,8 @@ Below this line add the following: ); ``` -Replace `myaddon-remote.min.js` with the file name you want to use for your remote bundle. Replace `myaddon.min` with the corresponding key in `config.entry` that points to your `index.js`. +Replace `myaddon-remote.min.js` with the file name you want to use for your remote bundle. +Replace `myaddon.min` with the corresponding key in `config.entry` that points to your `index.js`. [1]: https://pypi.org/project/plonecli/ From 7f7e7060d1e2f93d5933da8d1289af573d6b5c37 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Thu, 21 Jul 2022 01:16:39 +0200 Subject: [PATCH 017/810] Update docs/classic-ui/module-federation.md Co-authored-by: Steve Piercy --- docs/classic-ui/module-federation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index c4b6509c7..f75440412 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -69,7 +69,7 @@ Replace `myaddon.min` with the corresponding key in `config.entry` that points t ## Special case: global modules `jQuery` and `Bootstrap` -In order to preserve compatibility with older addons and JavaScript implementations, +In order to preserve compatibility with older add-ons and JavaScript implementations, the modules `jQuery` and `Bootstrap` are stored in the global `window` namespace. So constructs like the following are still working: From 8165545e4639017216068a1d8570b5a81b4cd941 Mon Sep 17 00:00:00 2001 From: Johannes Raggam Date: Thu, 21 Jul 2022 23:52:08 +0200 Subject: [PATCH 018/810] more fixes and for latest webpack.mf.js and example references. --- docs/classic-ui/module-federation.md | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index f75440412..f13b05a35 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -44,6 +44,16 @@ Add the following line near the top of the file: const mf_config = require("@patternslib/dev/webpack/webpack.mf"); ``` +Import all the dependencies you want to share. +Potentially these are the ones from Patternslib, Mockup and your own dependencies. +You can just add the Patternslib and Mockup dependencies, even if you are not using them. + +```js +const package_json = require("./package.json"); +const package_json_mockup = require("@plone/mockup/package.json"); +const package_json_patternslib = require("@patternslib/patternslib/package.json"); +``` + Then find the following line: ```js @@ -55,17 +65,29 @@ Below this line add the following: ```js config.plugins.push( mf_config({ + name: "myaddon", filename: "myaddon-remote.min.js", - package_json: package_json, remote_entry: config.entry["myaddon.min"], + dependencies: { + ...package_json_patternslib.dependencies, + ...package_json_mockup.dependencies, + ...package_json.dependencies, + }, }) ); ``` -Replace `myaddon-remote.min.js` with the file name you want to use for your remote bundle. -Replace `myaddon.min` with the corresponding key in `config.entry` that points to your `index.js`. +Replace the name `myaddon` with your addon bundle's name (any unique name will do...), +replace the filename `myaddon-remote.min.js` with the file name you want to use for your remote bundle, +and replace `myaddon.min` with the corresponding key in `config.entry` that points to your `index.js`. + +For a full but simple example, see the Patterns generator [pat-PATTERN-TEMPLATE][2] or any other Pattern addon in the patternslib GitHub organisation. +For a complex example with Mockup integration see [plone.app.mosaic][3] and [Mockup][4] itself. [1]: https://pypi.org/project/plonecli/ +[2]: https://github.com/Patternslib/pat-PATTERN_TEMPLATE/blob/master/webpack.config.js +[3]: https://github.com/plone/plone.app.mosaic/blob/master/webpack.config.js +[4]: https://github.com/plone/mockup/blob/master/webpack.config.js ## Special case: global modules `jQuery` and `Bootstrap` From b803e5789e8781e54440393e1abbd013c9d73824 Mon Sep 17 00:00:00 2001 From: Peter Mathis Date: Fri, 22 Jul 2022 07:55:37 +0200 Subject: [PATCH 019/810] fix babel_include package name --- docs/classic-ui/module-federation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index f13b05a35..3dd79c525 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -57,7 +57,7 @@ const package_json_patternslib = require("@patternslib/patternslib/package.json" Then find the following line: ```js - config = patternslib_config(env, argv, config, ["mockup"]); + config = patternslib_config(env, argv, config, ["@plone/mockup"]); ``` Below this line add the following: From 08b9534b97b4dd34ed4ae285eb701fbc4bb28053 Mon Sep 17 00:00:00 2001 From: Peter Mathis Date: Fri, 22 Jul 2022 07:55:49 +0200 Subject: [PATCH 020/810] add doc to toctree --- docs/classic-ui/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/classic-ui/index.md b/docs/classic-ui/index.md index 30e19607b..799b09be7 100644 --- a/docs/classic-ui/index.md +++ b/docs/classic-ui/index.md @@ -49,6 +49,7 @@ This chapter is a developer reference manual for working with Classic UI. theming/index static-resources +module-federation templates templates-global-variables views From 6594061cbe87ddeca32e9e5d2fd1e20d1717dc06 Mon Sep 17 00:00:00 2001 From: Peter Mathis Date: Mon, 6 Nov 2023 16:50:24 +0100 Subject: [PATCH 021/810] add autoform documentation for classic UI --- docs/classic-ui/forms.md | 318 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 318 insertions(+) diff --git a/docs/classic-ui/forms.md b/docs/classic-ui/forms.md index 7ea2fc947..546fcc061 100644 --- a/docs/classic-ui/forms.md +++ b/docs/classic-ui/forms.md @@ -120,6 +120,324 @@ schema = IMyForm If your form is not bound to an object (such as a Dexterity object), set `ignoreContext = True`. +(classic-ui-forms-autoform-label)= +## Controlling form presentation + +Directives can be specified in the schema to control aspects of form presentation. + +### Changing a field's display mode + +A field's widget can be displayed in several "modes": + +* input - allows the user to enter data into the field +* display - a read-only indication of the field's value +* hidden - a record of the field's value that is included only in the HTML source + +The mode can be controlled using the `mode` directive. + +```python + from plone.supermodel import model + from plone.autoform import directives as form + + class IMySchema(model.Schema): + + form.mode(secret='hidden') + form.mode(IEditForm, secret='input') + secret = schema.TextLine( + title=u"Secret", + default=u"Secret stuff (except on edit forms)" + ) +``` + +In this case the mode for the `secret` field is set to 'hidden' for most forms, +but 'input' for forms that provide the IEditForm interface. + +The corresponding supermodel XML directive is `form:mode`: + +```xml + + Secret + Secret stuff (except on edit forms) + +``` + +The mode can be specified briefly if it should be the same for all forms: + +```xml + + Secret + Secret stuff + +``` + +In other words, `form:mode` may be either a single mode, or a space-separated +list of form_interface:mode pairs. + + +### Omitting fields + +A field can be omitted entirely from all forms, or from some forms, +using the `omitted` and `no_omit` directives. In this example, +the `dummy` field is omitted from all forms, and the `edit_only` +field is omitted from all forms except those that provide the +IEditForm interface: + +```python + from z3c.form.interfaces import IEditForm + from plone.supermodel import model + from plone.autoform import directives as form + + class IMySchema(model.Schema): + + form.omitted('dummy') + dummy = schema.Text( + title=u"Dummy" + ) + + form.omitted('edit_only') + form.no_omit(IEditForm, 'edit_only') + edit_only = schema.TextLine( + title = u'Only included on edit forms', + ) +``` + +In supermodel XML, this can be specified as: + +```xml + + Dummy + + + + Only included on edit form + +``` + +`form:omitted` may be either a single boolean value, or a space-separated +list of form_interface:boolean pairs. + + +### Re-ordering fields + +A field's position in the form can be influenced using the `order_before` +and `order_after` directives. In this example, the `not_last` field +is placed before the `summary` field even though it is defined afterward: + +```python + from plone.supermodel import model + from plone.autoform import directives as form + + class IMySchema(model.Schema): + + summary = schema.Text( + title=u"Summary", + description=u"Summary of the body", + readonly=True + ) + + form.order_before(not_last='summary') + not_last = schema.TextLine( + title=u"Not last", + ) +``` + +The value passed to the directive may be either '*' (indicating before or after +all fields) or the name of another field. Use `'.fieldname'` to refer to +field in the current schema or a base schema. Prefix with the schema name (e.g. +`'IDublinCore.title'`) to refer to a field in another schema. Use an +unprefixed name to refer to a field in the current or the default schema for +the form. + +In supermodel XML, the directives are called `form:before` and `form:after`. +For example: + +```xml + + Not last + +``` + + +### Organizing fields into fieldsets + +Fields can be grouped into fieldsets, which will be rendered within an HTML +`
` tag. In this example the `footer` and `dummy` fields +are placed within the `extra` fieldset: + +```python + from plone.supermodel import model + from plone.autoform import directives as form + + class IMySchema(model.Schema): + + model.fieldset('extra', + label=u"Extra info", + fields=['footer', 'dummy'] + ) + + footer = schema.Text( + title=u"Footer text", + ) + + dummy = schema.Text( + title=u"Dummy" + ) +``` + +In supermodel XML fieldsets are specified by grouping fields within a +`
` tag: + +```xml +
+ + Footer text + + + Dummy + +
+``` + + +### Changing a field's widget + +Usually, z3c.form picks a widget based on the type of your field. +You can change the widget using the `widget` directive if you want +users to enter or view data in a different format. For example, +here we change the widget for the `human` field to use yes/no +radio buttons instead of a checkbox: + +```python + from plone.supermodel import model + from plone.autoform import directives as form + from z3c.form.browser.radio import RadioFieldWidget + + class IMySchema(model.Schema): + form.widget('human', RadioFieldWidget) + human = schema.Bool( + title = u'Are you human?', + ) +``` + +You can also pass widget parameters to control attributes of the +widget. For example, here we keep the default widget, but +set a CSS class: + +```python + from plone.supermodel import model + from plone.autoform import directives as form + from z3c.form.browser.radio import RadioWidget + + class IMySchema(model.Schema): + form.widget('human', klass='annoying') + human = schema.Bool( + title = u'Are you human?', + ) +``` + +In supermodel XML the widget is specified using a `` tag, which +can have its own elements specifying parameters:: + +```xml + + Are you human? + + annoying + + +``` + +Note: In order to be included in the XML representation of a schema, +widget parameters must be handled by a WidgetExportImportHandler utility. +There is a default one which handles the attributes defined in +`z3c.form.browser.interfaces.IHTMLFormElement`. + +### Protect a field with a permission + +By default, fields are included in the form regardless of the user's +permissions. Fields can be protected using the `read_permission` +and `write_permission` directives. The read permission is checked when +the field is in display mode, and the write permission is checked when +the field is in input mode. The permission should be given with its +Zope 3-style name (i.e. cmf.ManagePortal rather than 'Manage portal'). + +In this example, the `secret` field is protected by the +`cmf.ManagePortal` permission as both a read and write permission. +This means that in both display and input modes, the field will +only be included in the form for users who have that permission: + +```python + from plone.supermodel import model + from plone.autoform import directives as form + + class IMySchema(model.Schema): + form.read_permission(secret='cmf.ManagePortal') + form.write_permission(secret='cmf.ManagePortal') + secret = schema.TextLine( + title = u'Secret', + ) +``` + +In supermodel XML the directives are `security:read-permission` and +`security:write-permission`: + +```xml + + Secret + +``` + +## Display Forms + + +Sometimes rather than rendering a form for data entry, you want to display +stored values based on the same schema. This can be done using a "display form." +The display form renders each field's widget in "display mode," which means +that it shows the field value in read-only form rather than as a form input. + +To use the display form, create a view that extends `WidgetsView` like this: + +```python + from plone.autoform.view import WidgetsView + + class MyView(WidgetsView): + schema = IMySchema + additionalSchemata = (ISchemaOne, ISchemaTwo,) + + # ... +``` + +To render the form, do not override `__call__()`. Instead, either implement +the `render()` method, set an `index` attribute to a page template or +other callable, or use the `template` attribute of the `` +ZCML directive when registering the view. + +In the template, you can use the following variables: + +* `view/w` is a dictionary of all widgets, including those from non-default + fieldsets (by contrast, the `widgets` variable contains only those + widgets in the default fieldset). The keys are the field names, and the + values are widget instances. To render a widget (in display mode), you can + do `tal:replace="structure view/w/myfield/render" />`. +* `view/fieldsets` is a dictionary of all fieldsets (not including the + default fieldset, i.e. those widgets not placed into a fieldset). They keys + are the fieldset names, and the values are the fieldset form instances, + which in turn have variables like `widgets` given a list of all widgets. + + (classic-ui-forms-dexterity-add-edit-forms-label)= ## Dexterity add and edit forms From 8aa3a900e5fd476f8da00f7737c54245363cb438 Mon Sep 17 00:00:00 2001 From: Peter Mathis Date: Thu, 9 Nov 2023 15:48:19 +0100 Subject: [PATCH 022/810] Move content to the right place. --- docs/backend/fields.md | 40 ++++- docs/backend/schemas.md | 155 +++++++++++++++++-- docs/backend/widgets.md | 69 +++++++++ docs/classic-ui/forms.md | 313 +++------------------------------------ 4 files changed, 264 insertions(+), 313 deletions(-) diff --git a/docs/backend/fields.md b/docs/backend/fields.md index 735fd74c3..3aac2727a 100644 --- a/docs/backend/fields.md +++ b/docs/backend/fields.md @@ -136,19 +136,45 @@ See {ref}`backend-ploneschema-label` for more details. (backend-fields-schema-label)= -## schema +## Schema +With `plone.autoform` and `plone.supermodel` we can use directives to add information to the schema fields. -(backend-fields-schema-autoform-label)= -### `autoform` (directives) schema ordering, filtering, and permissions +(backend-fields-schema-autoform-permission)= +### Protect a field with a permission -(backend-fields-supermodel-label)= +By default, fields are included in the form regardless of the user's permissions. +Fields can be protected using the `read_permission` and `write_permission` directives. +The read permission is checked when the field is in display mode, and the write permission is checked when the field is in input mode. +The permission should be given with its Zope 3-style name (i.e. cmf.ManagePortal rather than 'Manage portal'). -## `supermodel` (XML) +In this example, the `secret` field is protected by the +`cmf.ManagePortal` permission as both a read and write permission. +This means that in both display and input modes, the field will +only be included in the form for users who have that permission: +```python +from plone.supermodel import model +from plone.autoform import directives as form -(backend-fields-supermodel-autoform-label)= +class IMySchema(model.Schema): + form.read_permission(secret='cmf.ManagePortal') + form.write_permission(secret='cmf.ManagePortal') + secret = schema.TextLine( + title = u'Secret', + ) +``` + +In supermodel XML the directives are `security:read-permission` and +`security:write-permission`: -### `autoform` (directives) supermodel ordering, filtering, and permissions +```xml + + Secret + +``` diff --git a/docs/backend/schemas.md b/docs/backend/schemas.md index 445b73272..2fd34d1ea 100644 --- a/docs/backend/schemas.md +++ b/docs/backend/schemas.md @@ -217,6 +217,148 @@ Note this won't have behavior fields added to it at this stage, only the fields - {doc}`reference list of fields used in Plone ` +(backend-schemas-directives-label)= + +## Using schema directives + +With `plone.autoform` and `plone.supermodel` we can use directives to add information to the schema fields. + + +### Omitting fields + +A field can be omitted entirely from all forms, or from some forms, using the `omitted` and `no_omit` directives. +In this example, the `dummy` field is omitted from all forms, and the `edit_only` field is omitted from all forms except those that provide the IEditForm interface: + +```{code-block} python +:emphasize-lines: 7,12,13 +:linenos: + +from z3c.form.interfaces import IEditForm +from plone.supermodel import model +from plone.autoform import directives as form + +class IMySchema(model.Schema): + + form.omitted('dummy') + dummy = schema.Text( + title=u"Dummy" + ) + + form.omitted('edit_only') + form.no_omit(IEditForm, 'edit_only') + edit_only = schema.TextLine( + title = u'Only included on edit forms', + ) +``` + +In supermodel XML, this can be specified as: + +```{code-block} xml +:emphasize-lines: 3,9 + + + Dummy + + + + Only included on edit form + +``` + +`form:omitted` may be either a single boolean value, or a space-separated list of form_interface:boolean pairs. + + +### Re-ordering fields + +A field's position in the form can be influenced using the `order_before` and `order_after` directives. +In this example, the `not_last` field is placed before the `summary` field even though it is defined afterward: + +```{code-block} python +:emphasize-lines: 12 +:linenos: + +from plone.supermodel import model +from plone.autoform import directives as form + +class IMySchema(model.Schema): + + summary = schema.Text( + title=u"Summary", + description=u"Summary of the body", + readonly=True + ) + + form.order_before(not_last='summary') + not_last = schema.TextLine( + title=u"Not last", + ) +``` + +The value passed to the directive may be either '*' (indicating before or after all fields) or the name of another field. +Use `'.fieldname'` to refer to field in the current schema or a base schema. +Prefix with the schema name (e.g. `'IDublinCore.title'`) to refer to a field in another schema. +Use an unprefixed name to refer to a field in the current or the default schema for the form. + +In supermodel XML, the directives are called `form:before` and `form:after`. +For example: + +```{code-block} xml +:emphasize-lines: 3 + + + Not last + +``` + + +### Organizing fields into fieldsets + +Fields can be grouped into fieldsets, which will be rendered within an HTML `
` tag. +In this example the `footer` and `dummy` fields are placed within the `extra` fieldset: + +```{code-block} python +:emphasize-lines: 6,7,8,9 +:linenos: + +from plone.supermodel import model +from plone.autoform import directives as form + +class IMySchema(model.Schema): + + model.fieldset('extra', + label=u"Extra info", + fields=['footer', 'dummy'] + ) + + footer = schema.Text( + title=u"Footer text", + ) + + dummy = schema.Text( + title=u"Dummy" + ) +``` + +In supermodel XML fieldsets are specified by grouping fields within a `
` tag: + +```xml +
+ + Footer text + + + Dummy + +
+``` + + ## Advanced ```{note} @@ -588,17 +730,4 @@ def fields(self): f.field = schema_field ``` -#### Don't use dict `{}` or list `[]` as a default value - -Because of how Python object construction works, giving `[]` or `{}` as a default value will make all created field values share this same object. - -```{seealso} -[The Hitchhiker's Guide to Python, Common Gotchas](https://docs.python-guide.org/writing/gotchas) -``` - -Use value adapters instead. - -```{seealso} -[`plone.directives.form` documentation of Value adapters](https://pypi.org/project/plone.directives.form/#value-adapters) -``` diff --git a/docs/backend/widgets.md b/docs/backend/widgets.md index 23e5d55dc..847bf1c1a 100644 --- a/docs/backend/widgets.md +++ b/docs/backend/widgets.md @@ -63,6 +63,75 @@ The main widgets are: - DateTime Picker +(backend-widgets-fields-display-label)= + +## Changing a field's display mode + +A field's widget can be displayed in several modes: + +`input` +: Allows the user to enter data into the field + +`display` +: A read-only indication of the field's value + +`hidden` +: A record of the field's value that is included only in the HTML source + + +### `plone.autoform` `mode` directive + + +```{code-block} python +:emphasize-lines: 6,7 +:linenos: + +from plone.supermodel import model +from plone.autoform import directives as form + +class IMySchema(model.Schema): + + form.mode(secret='hidden') + form.mode(IEditForm, secret='input') + secret = schema.TextLine( + title=u"Secret", + default=u"Secret stuff (except on edit forms)" + ) +``` + +In this case the mode for the `secret` field is set to 'hidden' for most forms, but 'input' for forms that provide the IEditForm interface. + +The corresponding supermodel XML directive is `form:mode`: + +```{code-block} xml +:emphasize-lines: 3 + + + Secret + Secret stuff (except on edit forms) + +``` + +The mode can be specified briefly if it should be the same for all forms: + +```{code-block} xml +:emphasize-lines: 3 + + + Secret + Secret stuff + +``` + +In other words, `form:mode` may be either a single mode, or a space-separated list of form_interface:mode pairs. + + +(backend-widgets-fields-widget-label)= + ## Changing a field's widget You can change the widget that you use for a field in several ways. diff --git a/docs/classic-ui/forms.md b/docs/classic-ui/forms.md index 546fcc061..2dea62fb5 100644 --- a/docs/classic-ui/forms.md +++ b/docs/classic-ui/forms.md @@ -125,317 +125,44 @@ If your form is not bound to an object (such as a Dexterity object), set `ignore Directives can be specified in the schema to control aspects of form presentation. -### Changing a field's display mode +### Control field and widget presentation -A field's widget can be displayed in several "modes": +See the corresponding chapters to learn how to control field and widget presentation in a form. -* input - allows the user to enter data into the field -* display - a read-only indication of the field's value -* hidden - a record of the field's value that is included only in the HTML source - -The mode can be controlled using the `mode` directive. - -```python - from plone.supermodel import model - from plone.autoform import directives as form - - class IMySchema(model.Schema): - - form.mode(secret='hidden') - form.mode(IEditForm, secret='input') - secret = schema.TextLine( - title=u"Secret", - default=u"Secret stuff (except on edit forms)" - ) -``` - -In this case the mode for the `secret` field is set to 'hidden' for most forms, -but 'input' for forms that provide the IEditForm interface. - -The corresponding supermodel XML directive is `form:mode`: - -```xml - - Secret - Secret stuff (except on edit forms) - -``` - -The mode can be specified briefly if it should be the same for all forms: - -```xml - - Secret - Secret stuff - -``` - -In other words, `form:mode` may be either a single mode, or a space-separated -list of form_interface:mode pairs. - - -### Omitting fields - -A field can be omitted entirely from all forms, or from some forms, -using the `omitted` and `no_omit` directives. In this example, -the `dummy` field is omitted from all forms, and the `edit_only` -field is omitted from all forms except those that provide the -IEditForm interface: - -```python - from z3c.form.interfaces import IEditForm - from plone.supermodel import model - from plone.autoform import directives as form - - class IMySchema(model.Schema): - - form.omitted('dummy') - dummy = schema.Text( - title=u"Dummy" - ) - - form.omitted('edit_only') - form.no_omit(IEditForm, 'edit_only') - edit_only = schema.TextLine( - title = u'Only included on edit forms', - ) -``` - -In supermodel XML, this can be specified as: - -```xml - - Dummy - - - - Only included on edit form - -``` - -`form:omitted` may be either a single boolean value, or a space-separated -list of form_interface:boolean pairs. - - -### Re-ordering fields - -A field's position in the form can be influenced using the `order_before` -and `order_after` directives. In this example, the `not_last` field -is placed before the `summary` field even though it is defined afterward: - -```python - from plone.supermodel import model - from plone.autoform import directives as form - - class IMySchema(model.Schema): - - summary = schema.Text( - title=u"Summary", - description=u"Summary of the body", - readonly=True - ) - - form.order_before(not_last='summary') - not_last = schema.TextLine( - title=u"Not last", - ) -``` - -The value passed to the directive may be either '*' (indicating before or after -all fields) or the name of another field. Use `'.fieldname'` to refer to -field in the current schema or a base schema. Prefix with the schema name (e.g. -`'IDublinCore.title'`) to refer to a field in another schema. Use an -unprefixed name to refer to a field in the current or the default schema for -the form. - -In supermodel XML, the directives are called `form:before` and `form:after`. -For example: - -```xml - - Not last - -``` - - -### Organizing fields into fieldsets - -Fields can be grouped into fieldsets, which will be rendered within an HTML -`
` tag. In this example the `footer` and `dummy` fields -are placed within the `extra` fieldset: - -```python - from plone.supermodel import model - from plone.autoform import directives as form - - class IMySchema(model.Schema): - - model.fieldset('extra', - label=u"Extra info", - fields=['footer', 'dummy'] - ) - - footer = schema.Text( - title=u"Footer text", - ) - - dummy = schema.Text( - title=u"Dummy" - ) -``` - -In supermodel XML fieldsets are specified by grouping fields within a -`
` tag: - -```xml -
- - Footer text - - - Dummy - -
+```{seealso} +{ref}`Field permission ` +{ref}`Ordering, omitting, grouping ` +{ref}`Changing a field's display mode ` +{ref}`Changing a field's widget ` ``` -### Changing a field's widget - -Usually, z3c.form picks a widget based on the type of your field. -You can change the widget using the `widget` directive if you want -users to enter or view data in a different format. For example, -here we change the widget for the `human` field to use yes/no -radio buttons instead of a checkbox: - -```python - from plone.supermodel import model - from plone.autoform import directives as form - from z3c.form.browser.radio import RadioFieldWidget - - class IMySchema(model.Schema): - form.widget('human', RadioFieldWidget) - human = schema.Bool( - title = u'Are you human?', - ) -``` - -You can also pass widget parameters to control attributes of the -widget. For example, here we keep the default widget, but -set a CSS class: - -```python - from plone.supermodel import model - from plone.autoform import directives as form - from z3c.form.browser.radio import RadioWidget - - class IMySchema(model.Schema): - form.widget('human', klass='annoying') - human = schema.Bool( - title = u'Are you human?', - ) -``` - -In supermodel XML the widget is specified using a `` tag, which -can have its own elements specifying parameters:: - -```xml - - Are you human? - - annoying - - -``` - -Note: In order to be included in the XML representation of a schema, -widget parameters must be handled by a WidgetExportImportHandler utility. -There is a default one which handles the attributes defined in -`z3c.form.browser.interfaces.IHTMLFormElement`. - -### Protect a field with a permission - -By default, fields are included in the form regardless of the user's -permissions. Fields can be protected using the `read_permission` -and `write_permission` directives. The read permission is checked when -the field is in display mode, and the write permission is checked when -the field is in input mode. The permission should be given with its -Zope 3-style name (i.e. cmf.ManagePortal rather than 'Manage portal'). - -In this example, the `secret` field is protected by the -`cmf.ManagePortal` permission as both a read and write permission. -This means that in both display and input modes, the field will -only be included in the form for users who have that permission: - -```python - from plone.supermodel import model - from plone.autoform import directives as form - - class IMySchema(model.Schema): - form.read_permission(secret='cmf.ManagePortal') - form.write_permission(secret='cmf.ManagePortal') - secret = schema.TextLine( - title = u'Secret', - ) -``` - -In supermodel XML the directives are `security:read-permission` and -`security:write-permission`: - -```xml - - Secret - -``` - -## Display Forms +### Display Forms -Sometimes rather than rendering a form for data entry, you want to display -stored values based on the same schema. This can be done using a "display form." -The display form renders each field's widget in "display mode," which means -that it shows the field value in read-only form rather than as a form input. +Sometimes rather than rendering a form for data entry, you want to display stored values based on the same schema. +This can be done using a "display form". +The display form renders each field's widget in "display mode" which means that it shows the field value in read-only form rather than as a form input. To use the display form, create a view that extends `WidgetsView` like this: ```python - from plone.autoform.view import WidgetsView +from plone.autoform.view import WidgetsView - class MyView(WidgetsView): - schema = IMySchema - additionalSchemata = (ISchemaOne, ISchemaTwo,) +class MyView(WidgetsView): + schema = IMySchema + additionalSchemata = (ISchemaOne, ISchemaTwo,) - # ... + # ... ``` -To render the form, do not override `__call__()`. Instead, either implement -the `render()` method, set an `index` attribute to a page template or -other callable, or use the `template` attribute of the `` -ZCML directive when registering the view. +To render the form, do not override `__call__()`. +Instead, either implement the `render()` method, set an `index` attribute to a page template or other callable, or use the `template` attribute of the `` ZCML directive when registering the view. In the template, you can use the following variables: -* `view/w` is a dictionary of all widgets, including those from non-default - fieldsets (by contrast, the `widgets` variable contains only those - widgets in the default fieldset). The keys are the field names, and the - values are widget instances. To render a widget (in display mode), you can - do `tal:replace="structure view/w/myfield/render" />`. -* `view/fieldsets` is a dictionary of all fieldsets (not including the - default fieldset, i.e. those widgets not placed into a fieldset). They keys - are the fieldset names, and the values are the fieldset form instances, - which in turn have variables like `widgets` given a list of all widgets. +- `view/w` is a dictionary of all widgets, including those from non-default fieldsets (by contrast, the `widgets` variable contains only those widgets in the default fieldset). The keys are the field names, and the values are widget instances. To render a widget (in display mode), you can do `tal:replace="structure view/w/myfield/render" />`. +- `view/fieldsets` is a dictionary of all fieldsets (not including the default fieldset, i.e. those widgets not placed into a fieldset). They keys are the fieldset names, and the values are the fieldset form instances, which in turn have variables like `widgets` given a list of all widgets. (classic-ui-forms-dexterity-add-edit-forms-label)= From bd952192cd97bf7cc3ba1a7bdfe037aaec055881 Mon Sep 17 00:00:00 2001 From: Peter Mathis Date: Thu, 9 Nov 2023 15:49:35 +0100 Subject: [PATCH 023/810] suggested change and typo --- docs/classic-ui/forms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/classic-ui/forms.md b/docs/classic-ui/forms.md index 2dea62fb5..f18603ccf 100644 --- a/docs/classic-ui/forms.md +++ b/docs/classic-ui/forms.md @@ -162,7 +162,7 @@ Instead, either implement the `render()` method, set an `index` attribute to a p In the template, you can use the following variables: - `view/w` is a dictionary of all widgets, including those from non-default fieldsets (by contrast, the `widgets` variable contains only those widgets in the default fieldset). The keys are the field names, and the values are widget instances. To render a widget (in display mode), you can do `tal:replace="structure view/w/myfield/render" />`. -- `view/fieldsets` is a dictionary of all fieldsets (not including the default fieldset, i.e. those widgets not placed into a fieldset). They keys are the fieldset names, and the values are the fieldset form instances, which in turn have variables like `widgets` given a list of all widgets. +- `view/fieldsets` is a dictionary of all fieldsets (not including the default fieldset, in other words, those widgets not placed into a fieldset. The keys are the fieldset names, and the values are the fieldset form instances, which in turn have variables like `widgets` given a list of all widgets. (classic-ui-forms-dexterity-add-edit-forms-label)= From 8c26e913883e3fdfb479830cbed890012395d2e7 Mon Sep 17 00:00:00 2001 From: Peter Mathis Date: Thu, 9 Nov 2023 15:58:27 +0100 Subject: [PATCH 024/810] code styling and suggestions --- docs/backend/fields.md | 14 ++++++-------- docs/backend/schemas.md | 24 ++++++++++++------------ docs/backend/widgets.md | 8 ++++---- docs/classic-ui/forms.md | 10 ++++++++-- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/docs/backend/fields.md b/docs/backend/fields.md index 3aac2727a..c87077fbd 100644 --- a/docs/backend/fields.md +++ b/docs/backend/fields.md @@ -148,22 +148,20 @@ With `plone.autoform` and `plone.supermodel` we can use directives to add inform By default, fields are included in the form regardless of the user's permissions. Fields can be protected using the `read_permission` and `write_permission` directives. The read permission is checked when the field is in display mode, and the write permission is checked when the field is in input mode. -The permission should be given with its Zope 3-style name (i.e. cmf.ManagePortal rather than 'Manage portal'). +The permission should be given with its Zope 3-style name (such as `cmf.ManagePortal` instead of `Manage portal`). -In this example, the `secret` field is protected by the -`cmf.ManagePortal` permission as both a read and write permission. -This means that in both display and input modes, the field will -only be included in the form for users who have that permission: +In this example, the `secret` field is protected by the `cmf.ManagePortal` permission as both a read and write permission. +This means that in both display and input modes, the field will only be included in the form for users who have that permission: ```python from plone.supermodel import model from plone.autoform import directives as form class IMySchema(model.Schema): - form.read_permission(secret='cmf.ManagePortal') - form.write_permission(secret='cmf.ManagePortal') + form.read_permission(secret="cmf.ManagePortal") + form.write_permission(secret="cmf.ManagePortal") secret = schema.TextLine( - title = u'Secret', + title = u"Secret", ) ``` diff --git a/docs/backend/schemas.md b/docs/backend/schemas.md index 2fd34d1ea..f51375631 100644 --- a/docs/backend/schemas.md +++ b/docs/backend/schemas.md @@ -224,10 +224,10 @@ Note this won't have behavior fields added to it at this stage, only the fields With `plone.autoform` and `plone.supermodel` we can use directives to add information to the schema fields. -### Omitting fields +### Omit fields A field can be omitted entirely from all forms, or from some forms, using the `omitted` and `no_omit` directives. -In this example, the `dummy` field is omitted from all forms, and the `edit_only` field is omitted from all forms except those that provide the IEditForm interface: +In this example, the `dummy` field is omitted from all forms, and the `edit_only` field is omitted from all forms except those that provide the `IEditForm` interface: ```{code-block} python :emphasize-lines: 7,12,13 @@ -239,15 +239,15 @@ from plone.autoform import directives as form class IMySchema(model.Schema): - form.omitted('dummy') + form.omitted("dummy") dummy = schema.Text( title=u"Dummy" ) - form.omitted('edit_only') - form.no_omit(IEditForm, 'edit_only') + form.omitted("edit_only") + form.no_omit(IEditForm, "edit_only") edit_only = schema.TextLine( - title = u'Only included on edit forms', + title = u"Only included on edit forms", ) ``` @@ -272,7 +272,7 @@ In supermodel XML, this can be specified as: `form:omitted` may be either a single boolean value, or a space-separated list of form_interface:boolean pairs. -### Re-ordering fields +### Reorder fields A field's position in the form can be influenced using the `order_before` and `order_after` directives. In this example, the `not_last` field is placed before the `summary` field even though it is defined afterward: @@ -292,15 +292,15 @@ class IMySchema(model.Schema): readonly=True ) - form.order_before(not_last='summary') + form.order_before(not_last="summary") not_last = schema.TextLine( title=u"Not last", ) ``` -The value passed to the directive may be either '*' (indicating before or after all fields) or the name of another field. -Use `'.fieldname'` to refer to field in the current schema or a base schema. -Prefix with the schema name (e.g. `'IDublinCore.title'`) to refer to a field in another schema. +The value passed to the directive may be either `*` (indicating before or after all fields) or the name of another field. +Use `.fieldname` to refer to field in the current schema or a base schema. +Prefix with the schema name (e.g. `IDublinCore.title`) to refer to a field in another schema. Use an unprefixed name to refer to a field in the current or the default schema for the form. In supermodel XML, the directives are called `form:before` and `form:after`. @@ -345,7 +345,7 @@ class IMySchema(model.Schema): ) ``` -In supermodel XML fieldsets are specified by grouping fields within a `
` tag: +In supermodel XML, fieldsets are specified by grouping fields within a `
` tag: ```xml
diff --git a/docs/backend/widgets.md b/docs/backend/widgets.md index 847bf1c1a..c10786836 100644 --- a/docs/backend/widgets.md +++ b/docs/backend/widgets.md @@ -65,7 +65,7 @@ The main widgets are: (backend-widgets-fields-display-label)= -## Changing a field's display mode +## Change a field's display mode A field's widget can be displayed in several modes: @@ -91,8 +91,8 @@ from plone.autoform import directives as form class IMySchema(model.Schema): - form.mode(secret='hidden') - form.mode(IEditForm, secret='input') + form.mode(secret="hidden") + form.mode(IEditForm, secret="input") secret = schema.TextLine( title=u"Secret", default=u"Secret stuff (except on edit forms)" @@ -132,7 +132,7 @@ In other words, `form:mode` may be either a single mode, or a space-separated li (backend-widgets-fields-widget-label)= -## Changing a field's widget +## Change a field's widget You can change the widget that you use for a field in several ways. This section describes these methods. diff --git a/docs/classic-ui/forms.md b/docs/classic-ui/forms.md index f18603ccf..d10e44ae4 100644 --- a/docs/classic-ui/forms.md +++ b/docs/classic-ui/forms.md @@ -131,9 +131,15 @@ See the corresponding chapters to learn how to control field and widget presenta ```{seealso} {ref}`Field permission ` +``` +```{seealso} {ref}`Ordering, omitting, grouping ` -{ref}`Changing a field's display mode ` -{ref}`Changing a field's widget ` +``` +```{seealso} +{ref}`Changing a field's display mode ` +``` +```{seealso} +{ref}`Changing a field's widget ` ``` From 6f03e5b49fe6a78e6ce12c027684d4aac5725c9d Mon Sep 17 00:00:00 2001 From: Jaroslaw Zabiello Date: Thu, 23 Nov 2023 19:33:49 +0000 Subject: [PATCH 025/810] Update nginx-plone.md (#1580) Add an Nginx mod rewrite rule for the created Plone site instance so it can be opened at http://plone.localhost instead of http://plone.localhost/Plone. --- .../containers/examples/nginx-plone.md | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/docs/install/containers/examples/nginx-plone.md b/docs/install/containers/examples/nginx-plone.md index 99dc400bb..3450ff645 100644 --- a/docs/install/containers/examples/nginx-plone.md +++ b/docs/install/containers/examples/nginx-plone.md @@ -35,27 +35,33 @@ Add a `default.conf` that will be used by the nginx image: ```nginx upstream backend { - server backend:8080; + server backend:8080; } server { - listen 80 default_server; - server_name plone.localhost; - - location ~ / { - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_redirect http:// https://; - proxy_pass http://backend; - } + listen 80 default_server; + server_name plone.localhost; + + location / { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_redirect http:// https://; + if (!-f $request_filename) { + rewrite ^/(.*)$ /VirtualHostBase/http/plone.localhost:80/Plone/VirtualHostRoot/$1; + } + } + + location /VirtualHostBase/ { + proxy_pass http://backend; + } } ``` ```{note} `http://plone.localhost/` is the URL you will be using to access the website. -You can either use `localhost`, or add it in your `/etc/hosts` file or DNS to point to the Docker host IP. +You can either use `plone.localhost`, or add it in your `/etc/hosts` file or DNS to point to the Docker host IP. ``` ### Service configuration with Docker Compose @@ -103,7 +109,7 @@ This pulls the needed images and starts Plone. ## Access Plone via Browser -After startup, go to `http://plone.localhost/` and you should see the site. +After startup, go to `http://plone.localhost/` and you should see the site. You can also open the main Plone control page where you can create more Plone sites at `http://plone.localhost:8080`. ## Shutdown and cleanup From 8b60339d7e06e78e33df6ca2e99005cb4fd1056c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 23 Nov 2023 13:23:54 -0800 Subject: [PATCH 026/810] Style guide fixes --- .../containers/examples/nginx-plone.md | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/docs/install/containers/examples/nginx-plone.md b/docs/install/containers/examples/nginx-plone.md index 3450ff645..f0b113e4c 100644 --- a/docs/install/containers/examples/nginx-plone.md +++ b/docs/install/containers/examples/nginx-plone.md @@ -35,33 +35,33 @@ Add a `default.conf` that will be used by the nginx image: ```nginx upstream backend { - server backend:8080; + server backend:8080; } server { - listen 80 default_server; - server_name plone.localhost; - - location / { - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_redirect http:// https://; - if (!-f $request_filename) { - rewrite ^/(.*)$ /VirtualHostBase/http/plone.localhost:80/Plone/VirtualHostRoot/$1; - } + listen 80 default_server; + server_name plone.localhost; + + location / { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_redirect http:// https://; + if (!-f $request_filename) { + rewrite ^/(.*)$ /VirtualHostBase/http/plone.localhost:80/Plone/VirtualHostRoot/$1; } + } - location /VirtualHostBase/ { - proxy_pass http://backend; - } + location /VirtualHostBase/ { + proxy_pass http://backend; + } } ``` ```{note} `http://plone.localhost/` is the URL you will be using to access the website. -You can either use `plone.localhost`, or add it in your `/etc/hosts` file or DNS to point to the Docker host IP. +You can either use `plone.localhost`, or add it in your `/etc/hosts` file or DNS, to point to the Docker host IP. ``` ### Service configuration with Docker Compose @@ -109,7 +109,8 @@ This pulls the needed images and starts Plone. ## Access Plone via Browser -After startup, go to `http://plone.localhost/` and you should see the site. You can also open the main Plone control page where you can create more Plone sites at `http://plone.localhost:8080`. +After startup, go to `http://plone.localhost/` and you should see the site. +You can also open the main Plone control page where you can create more Plone sites at `http://plone.localhost:8080`. ## Shutdown and cleanup From 13ab753ddee14cfe3658cfe7bfce17a1130d29c0 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 30 Nov 2023 00:13:11 -0800 Subject: [PATCH 027/810] Members of the Contributors team have only Read role, and Triage or greater is required to request a pull request review. --- docs/contributing/first-time.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/contributing/first-time.md b/docs/contributing/first-time.md index bd27a14b8..3413055d3 100644 --- a/docs/contributing/first-time.md +++ b/docs/contributing/first-time.md @@ -217,15 +217,20 @@ Once you have completed, tested, and linted your code, and created a {ref}`contr git push -u origin my-branch-name ``` -1. Visit your fork of the Plone repository on GitHub, and [create a pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) against the development branch. +1. Visit your fork of the Plone repository on GitHub, and [**create a pull request**](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) against the development branch. - Make both your title and description descriptive. Reviewers look at many pull requests, and need to quickly understand the context. A lazily written phrase such as "Fixes bug" is meaningless. - Include "Fixes #" and the related issue number in the description. This enables automatic closing of the related issue when the pull request is merged. This also creates a hyperlink to the original issue for easy reference. -1. [Request a review](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/requesting-a-pull-request-review) from other team members. +1. **Request a review.** + Identify who you should ask by either checking the history of the files you edit, or viewing the project's list of contributors for an active member. + If you have write access to the repository, [request a review](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/requesting-a-pull-request-review) from other team members. + If you do not have write access, instead add a comment and mention maintainers of the project, tagging them with `@username`. + You can find maintainers by visiting 1. Members who subscribe to the repository will receive a notification and review your request. + They will usually provide feedback within a week. (update-your-pull-request-from-your-fork-label)= From dc4821f1e3dfba8c6a3da296a63670a8b981e0b6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 30 Nov 2023 01:45:24 -0800 Subject: [PATCH 028/810] Fix broken links after monorepo merge --- docs/i18n-l10n/language-negotiation-volto.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/i18n-l10n/language-negotiation-volto.md b/docs/i18n-l10n/language-negotiation-volto.md index 203fdf68e..d62d6665f 100644 --- a/docs/i18n-l10n/language-negotiation-volto.md +++ b/docs/i18n-l10n/language-negotiation-volto.md @@ -21,7 +21,7 @@ Then you need to add the list of supported languages to the `supportedLanguages` As a last thing, you need to set your site's `defaultLanguage` to one of the `supportedLanguages`. -When all these settings are configured, Volto's [`MultilingualRedirector`](https://github.com/plone/volto/blob/main/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx) will handle the language negotiation and the redirect. +When all these settings are configured, Volto's [`MultilingualRedirector`](https://github.com/plone/volto/blob/main/packages/volto/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx) will handle the language negotiation and the redirect. In its configuration, the component tries to match the `I18N_LANGUAGE` cookie set in the user's browser with the list of supported languages, and if the match does not succeed, it selects the default language configured in Volto. From a8e414fd71bfbdc94640a01c5433024e1d66908e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 30 Nov 2023 03:48:44 -0800 Subject: [PATCH 029/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 30102e8c5..d5b83a67b 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 30102e8c50d2829472ba5fba837362c7073b97f4 +Subproject commit d5b83a67b5a894b7985c67e6c2ae0c9eb1034fd6 diff --git a/submodules/volto b/submodules/volto index 44be7cce3..77b5f4153 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 44be7cce35269b76d271196b0e0091595bc52425 +Subproject commit 77b5f415315cf19f3df258b3e640f10161968cc3 From 7c258d7b76deba8312924144e913d784fe2de9fd Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 30 Nov 2023 04:23:34 -0800 Subject: [PATCH 030/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 77b5f4153..9c70fbb87 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 77b5f415315cf19f3df258b3e640f10161968cc3 +Subproject commit 9c70fbb875e7193c345b52aa29180a0321d5c2c3 From dec1504e0fe744a7460adb5ad5073f668fbfd48b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 30 Nov 2023 14:56:38 -0800 Subject: [PATCH 031/810] Forgot to commit and push --- docs/contributing/first-time.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/contributing/first-time.md b/docs/contributing/first-time.md index 3413055d3..65ed984c1 100644 --- a/docs/contributing/first-time.md +++ b/docs/contributing/first-time.md @@ -227,8 +227,8 @@ Once you have completed, tested, and linted your code, and created a {ref}`contr 1. **Request a review.** Identify who you should ask by either checking the history of the files you edit, or viewing the project's list of contributors for an active member. If you have write access to the repository, [request a review](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/requesting-a-pull-request-review) from other team members. - If you do not have write access, instead add a comment and mention maintainers of the project, tagging them with `@username`. - You can find maintainers by visiting + If you do not have write access, instead add a comment and mention a few active contributors of the project, tagging them with `@username`. + You can find them by either checking the files' history via `git blame` or visiting the project's {guilabel}`Contributors` page on GitHub. 1. Members who subscribe to the repository will receive a notification and review your request. They will usually provide feedback within a week. From b4e474b1cec36b0c7a232ddcdf056c0a4525eb54 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 30 Nov 2023 23:36:30 -0800 Subject: [PATCH 032/810] Update tips submodules/plone.api submodules/volto --- submodules/plone.api | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index 54e649178..59a577ef8 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit 54e649178cbb2313b3615802f32ff90f2535876e +Subproject commit 59a577ef8e7072880538eebc51e3af7d3eaf611a diff --git a/submodules/volto b/submodules/volto index 9c70fbb87..bbfc462a8 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 9c70fbb875e7193c345b52aa29180a0321d5c2c3 +Subproject commit bbfc462a8774b1afe35b2ad60387c8894f5b286b From b4a86697f201ffcb50d610de3f4036df6b3506ee Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 1 Dec 2023 00:51:06 -0800 Subject: [PATCH 033/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index bbfc462a8..25e216a92 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit bbfc462a8774b1afe35b2ad60387c8894f5b286b +Subproject commit 25e216a9235ca845b2cadfd88c2b3019aeec40ab From 3f4eb69a1ff0946f3d81e78a855c2d17897ae32b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 1 Dec 2023 02:34:54 -0800 Subject: [PATCH 034/810] Update licenses used in Plone and paths to news --- docs/contributing/index.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/contributing/index.md b/docs/contributing/index.md index 0218a26aa..9d97fc94b 100644 --- a/docs/contributing/index.md +++ b/docs/contributing/index.md @@ -25,7 +25,7 @@ Other chapters cover any variations and additional policies for each project. You must give permission to the Plone Foundation to publish your contribution, according to the license we use. Plone uses the [GNU General Public License, version 2](https://github.com/plone/Products.CMFPlone/blob/master/LICENSE) for most of its projects and for any new projects. -A few other projects use the [modified BSD license](https://opensource.org/license/bsd-3-clause/). +A few other projects use the [modified BSD license](https://opensource.org/license/bsd-3-clause/), [MIT License](https://opensource.org/license/mit/), or [Creative Commons Attribution-ShareAlike 4.0 International license](https://creativecommons.org/licenses/by-sa/4.0/). You grant permission by signing and returning the Plone Contributor Agreement. ```{button-link} https://plone.org/foundation/contributors-agreement @@ -71,15 +71,15 @@ All of a project's CI jobs must pass before a contribution may be accepted. ## Change log entry -Plone projects require that you include a change log entry or news item with your contribution. +Plone packages require that you include a change log entry or news item with your contribution. This is enforced by continuous integration through GitHub Actions. Plone uses [`towncrier`](https://github.com/collective/zestreleaser.towncrier) to manage change log entries and to automatically generate history or change log files from the entries. -The log file is usually named `CHANGES.rst`, `CHANGES.md`, or `CHANGELOG.md`, and is located at the root of the project. -When a project is released with a new version, the release manager runs `towncrier` as part of the release process. +The log file is usually named `CHANGES.rst`, `CHANGES.md`, or `CHANGELOG.md`, and is located at the root of the package. +When a package is released with a new version, the release manager runs `towncrier` as part of the release process. Because the log file is automatically generated, you should not edit it directly, except to make corrections, such as broken links. -To create a change log entry or news item, create a file that is placed in the root of the repository directory at `/news`. +To create a change log entry or news item, create a file in the `news` directory, located in the root of the package. Its format must be `###.type`, where `###` is the referenced GitHub issue or pull request number, `.` is the literal extension delimiter, and `type` is one of the following strings. - `breaking` for breaking changes @@ -88,7 +88,7 @@ Its format must be `###.type`, where `###` is the referenced GitHub issue or pul - `feature` for new features - `internal` for internal changes -A project configures the types it allows in a file `towncrier.toml` located at the root of its repository. +A package configures the types it allows in a file `towncrier.toml` located at the root of its package directory. The content of this file must include the following. @@ -98,7 +98,7 @@ The content of this file must include the following. The following text is an example change log entry, placed inside {file}`/news/4569.documentation`. ```text -Fix broken links for ReactJS.org. @stevepiercy +Fixed broken links for ReactJS.org. @stevepiercy ``` (contributing-project-configuration-files-label)= From 565d8fe4b40a1b3db829b612a17694093990a0c1 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 1 Dec 2023 23:56:45 -0800 Subject: [PATCH 035/810] Fix storybook build without submodule --- .github/workflows/build_deploy.yml | 41 +++++++++++++++++------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build_deploy.yml b/.github/workflows/build_deploy.yml index e8bbdf4c9..a0396b163 100644 --- a/.github/workflows/build_deploy.yml +++ b/.github/workflows/build_deploy.yml @@ -5,6 +5,9 @@ on: branches: - "6.0" +env: + node-version: 20.x + jobs: build_deploy: runs-on: ubuntu-latest @@ -35,31 +38,35 @@ jobs: - name: Prepare deploy run: make deploy - # node setup - - name: Use Node.js 16 + - name: Use Node.js ${{ env.node-version }} uses: actions/setup-node@v3 with: - node-version: '16' - - name: Install Yarn - run: npm install -g yarn - # node cache - - name: Get yarn cache directory path - id: yarn-cache-dir-path - working-directory: submodules/volto - run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT + node-version: ${{ env.node-version }} + + - uses: pnpm/action-setup@v2 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + - uses: actions/cache@v3 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) + name: Setup pnpm cache with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | - ${{ runner.os }}-yarn- + ${{ runner.os }}-pnpm-store- - name: StoryBook build + working-directory: submodules/volto run: | - cd submodules/volto - yarn install --immutable - yarn build-storybook -o ../../_build/html/storybook + pnpm i + make storybook-build - name: Deploy to server id: deploy From c965edf86b0eaa14d35a77d3dfc631c1914c23a4 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 2 Dec 2023 01:04:42 -0800 Subject: [PATCH 036/810] Disable the storybook build temporarily --- .github/workflows/build_deploy.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build_deploy.yml b/.github/workflows/build_deploy.yml index a0396b163..827ce154f 100644 --- a/.github/workflows/build_deploy.yml +++ b/.github/workflows/build_deploy.yml @@ -62,11 +62,11 @@ jobs: restore-keys: | ${{ runner.os }}-pnpm-store- - - name: StoryBook build - working-directory: submodules/volto - run: | - pnpm i - make storybook-build +# - name: StoryBook build +# working-directory: submodules/volto +# run: | +# pnpm i +# make storybook-build - name: Deploy to server id: deploy From ffb8bbe76f9f78cfcd8c4b9f02c37c72a5a57aa1 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 2 Dec 2023 01:12:35 -0800 Subject: [PATCH 037/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 25e216a92..e5d6e4d1d 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 25e216a9235ca845b2cadfd88c2b3019aeec40ab +Subproject commit e5d6e4d1dd08f95131be722e6662055f9744ac29 From 7a769c16c6b067cb8873dee5cba43de370fea70a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 2 Dec 2023 03:39:06 -0800 Subject: [PATCH 038/810] Re-enable storybook --- .github/workflows/build_deploy.yml | 11 ++++++----- Makefile | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build_deploy.yml b/.github/workflows/build_deploy.yml index 827ce154f..17773c890 100644 --- a/.github/workflows/build_deploy.yml +++ b/.github/workflows/build_deploy.yml @@ -62,11 +62,12 @@ jobs: restore-keys: | ${{ runner.os }}-pnpm-store- -# - name: StoryBook build -# working-directory: submodules/volto -# run: | -# pnpm i -# make storybook-build + - name: StoryBook build + working-directory: submodules/volto + run: | + pnpm i + pnpm build:registry + make storybook-build - name: Deploy to server id: deploy diff --git a/Makefile b/Makefile index 057129a65..427c1ad93 100644 --- a/Makefile +++ b/Makefile @@ -239,7 +239,7 @@ netlify: .PHONY: storybook storybook: - cd submodules/volto && yarn && yarn build-storybook -o ../../_build/html/storybook + cd submodules/volto && pnpm i && pnpm build:registry && pnpm --filter @plone/volto build-storybook -o ../../../../_build/html/storybook .PHONY: all all: clean vale linkcheck html ## Clean docs build, then run vale and linkcheck, and build html From e55e9f8b2e4f2ecf1520303de1ec06d88c4e16bf Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 2 Dec 2023 04:01:55 -0800 Subject: [PATCH 039/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index e5d6e4d1d..2fbd07622 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit e5d6e4d1dd08f95131be722e6662055f9744ac29 +Subproject commit 2fbd07622ab6ff27561db148dd8751a30cd609f7 From 5a43e9b6650010a5b74e4adf8c94081aa613640b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 2 Dec 2023 04:13:42 -0800 Subject: [PATCH 040/810] Attempt to fix storybook build --- .github/workflows/build_deploy.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/build_deploy.yml b/.github/workflows/build_deploy.yml index 17773c890..fcae3efb0 100644 --- a/.github/workflows/build_deploy.yml +++ b/.github/workflows/build_deploy.yml @@ -63,11 +63,7 @@ jobs: ${{ runner.os }}-pnpm-store- - name: StoryBook build - working-directory: submodules/volto - run: | - pnpm i - pnpm build:registry - make storybook-build + run: make storybook - name: Deploy to server id: deploy From 418e57bd8f3d527a97bd5be11f74e0e913b7da6e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 3 Dec 2023 01:35:52 -0800 Subject: [PATCH 041/810] Improve documentation by: - Fixing MyST errors - Fixing broken links - Correcting misspellings - Correct a few style issues, such as sentence-case for headings A lot more work needs to be done, specifically adding terms to the Vale dictionary and improving the style to use inline literals instead of bold, which will also cut down on the number of terms that Vale flags. --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 2fbd07622..add2a33de 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 2fbd07622ab6ff27561db148dd8751a30cd609f7 +Subproject commit add2a33de58642468054f4e085a409c6f0bb7d4c From a858b84f14b0c6d157d1024da6146d86486f82fa Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 6 Dec 2023 17:42:13 -0800 Subject: [PATCH 042/810] Added examples of good and bad change log entries, with an explanation of its importance --- docs/contributing/index.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/contributing/index.md b/docs/contributing/index.md index 9d97fc94b..ac28090c1 100644 --- a/docs/contributing/index.md +++ b/docs/contributing/index.md @@ -93,14 +93,28 @@ A package configures the types it allows in a file `towncrier.toml` located at t The content of this file must include the following. - A brief message that summarizes the changes in your contribution. + - Use a narrative format, in the past tense, proper English spelling and grammar, complete sentences, and inline markup as needed. + - If you fix a bug, write what was broken and is now fixed. + - If you add or change a feature, write a summary of previous behavior and what it does now. - An attribution to yourself, in the format of `@github_username`. -The following text is an example change log entry, placed inside {file}`/news/4569.documentation`. +```{important} +These change log entries become narrative documentation. +``` + +The following text is an example of a good change log entry, placed inside {file}`/news/4470.documentation`. ```text -Fixed broken links for ReactJS.org. @stevepiercy +Changed from links to inline literals in `CHANGELOG.md` to fix linkcheckbroken. @stevepiercy ``` +This would be a poor change log entry. + +```text +Fix #123456 by chaning config of additionalToolbarComponents [did_not_read_this_guide] +``` + + (contributing-project-configuration-files-label)= ## Project configuration files From 1f993ef0b0bd7b037bc36b3bc7eb0c831ee9ca49 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 6 Dec 2023 17:53:46 -0800 Subject: [PATCH 043/810] Update submodule tips submodules/plone.api submodules/volto --- submodules/plone.api | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index 59a577ef8..91825e34b 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit 59a577ef8e7072880538eebc51e3af7d3eaf611a +Subproject commit 91825e34bd2703256a397efa6dc07ddd7d93d910 diff --git a/submodules/volto b/submodules/volto index add2a33de..ea22fba21 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit add2a33de58642468054f4e085a409c6f0bb7d4c +Subproject commit ea22fba21337f487fbf9d71734aae626002ce536 From 90243002a46836258cde6a3abc767a2287c77d20 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 6 Dec 2023 22:19:51 -0800 Subject: [PATCH 044/810] Update docs/contributing/index.md Co-authored-by: David Glick --- docs/contributing/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/index.md b/docs/contributing/index.md index ac28090c1..068870ba7 100644 --- a/docs/contributing/index.md +++ b/docs/contributing/index.md @@ -108,7 +108,7 @@ The following text is an example of a good change log entry, placed inside {file Changed from links to inline literals in `CHANGELOG.md` to fix linkcheckbroken. @stevepiercy ``` -This would be a poor change log entry. +The following would be a poor change log entry. ```text Fix #123456 by chaning config of additionalToolbarComponents [did_not_read_this_guide] From f2766c1b751733c245e0cd730f67fdf3bcbd85cd Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 6 Dec 2023 23:09:52 -0800 Subject: [PATCH 045/810] Move guidance to a separate list and wordsmith to improve clarity. --- docs/contributing/index.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/contributing/index.md b/docs/contributing/index.md index 068870ba7..a0ad44213 100644 --- a/docs/contributing/index.md +++ b/docs/contributing/index.md @@ -93,19 +93,26 @@ A package configures the types it allows in a file `towncrier.toml` located at t The content of this file must include the following. - A brief message that summarizes the changes in your contribution. - - Use a narrative format, in the past tense, proper English spelling and grammar, complete sentences, and inline markup as needed. - - If you fix a bug, write what was broken and is now fixed. - - If you add or change a feature, write a summary of previous behavior and what it does now. - An attribution to yourself, in the format of `@github_username`. ```{important} These change log entries become narrative documentation. ``` +You can write good change log entries with the following guidance. + +- Use a narrative format, in the past tense, proper English spelling and grammar, and inline markup as needed. +- Write your change log entry for its appropriate audience. + - Most entries should address _users_ of the software. + - An entry for a change to a public API should address _developers_. +- If you fix a bug, write what was broken and is now fixed. +- If you add or change a feature or public API, write a summary of previous behavior, what it does now, and how to use it. +- Refer to narrative documentation as needed. + The following text is an example of a good change log entry, placed inside {file}`/news/4470.documentation`. ```text -Changed from links to inline literals in `CHANGELOG.md` to fix linkcheckbroken. @stevepiercy +Changed a few broken links in `CHANGELOG.md` from URLs to inline literals to avoid errors when validating links. See https://6.docs.plone.org/volto/contributing/documentation.html#docs-linkcheckbroken for usage. @stevepiercy ``` The following would be a poor change log entry. From e6472aabf61772ce0ad4ce860d58584a4e1fb302 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 7 Dec 2023 01:02:09 -0800 Subject: [PATCH 046/810] Move Vale from a manual installation to pip - Move the install and configuration documentation of Vale to authors.md. --- Makefile | 4 +- docs/contributing/documentation/authors.md | 44 ++++++++++++++++--- .../contributing/documentation/setup-build.md | 27 ------------ requirements.txt | 1 + 4 files changed, 41 insertions(+), 35 deletions(-) diff --git a/Makefile b/Makefile index 427c1ad93..9f58ea24d 100644 --- a/Makefile +++ b/Makefile @@ -196,8 +196,8 @@ linkcheckbroken: deps ## Run linkcheck and show only broken links .PHONY: vale vale: deps ## Run Vale style, grammar, and spell checks - vale sync - vale --no-wrap $(VALEFILES) + bin/vale sync + bin/vale --no-wrap $(VALEFILES) @echo @echo "Vale is finished; look for any errors in the above output." diff --git a/docs/contributing/documentation/authors.md b/docs/contributing/documentation/authors.md index 9c83b1a69..35a121c3f 100644 --- a/docs/contributing/documentation/authors.md +++ b/docs/contributing/documentation/authors.md @@ -53,15 +53,12 @@ Open `/_build/html/index.html` in a web browser. ### American English spelling, grammar, and syntax, and style guide -Spellings are enforced through [`Vale`](https://vale.sh/). +[Vale](https://vale.sh/) is a linter for narrative text. +It checks spelling, English grammar, and style guides. Plone uses American English. -Spelling is configured in {file}`Makefile`, {file}`.vale.ini`, and in files in `styles/Vocab/Plone/`. - -Authors should add new words and proper names using correct casing to {file}`styles/Vocab/Plone/accept.txt`, sorted alphabetically and case-insensitive. - Vale also provides English grammar and syntax checking, as well as a Style Guide. -We follow the [Microsoft Writing Style Guide](https://learn.microsoft.com/en-us/style-guide/welcome/). +The Plone Documentation Team selected the [Microsoft Writing Style Guide](https://learn.microsoft.com/en-us/style-guide/welcome/) for its ease of use—especially for non-native English readers and writers—and attention to non-technical audiences. To perform all these checks, run the following command. @@ -74,6 +71,41 @@ We also understand that contributors might not be fluent in English. We encourage contributors to make a reasonable effort, and to request a review of their pull request from community members who are fluent in English to fix grammar and syntax. Please ask! +```{note} +More corrections to spellings and Vale's configuration are welcome by submitting a pull request. +This is an easy way to become a contributor to Plone. +See {ref}`authors-advanced-vale-usage-label` for details. +``` + + +(authors-advanced-vale-usage-label)= + +#### Advanced Vale usage + +To have Vale check only a specific file or directory of files, you can issue [Vale commands](https://vale.sh/manual/) with options in a shell session. +To allow this, you must either: + +- activate your Python virtual environment +- use the virtual environment path, such as `bin/vale` +- install Vale using operating system's package manager + +The Vale `Makefile` command automatically installs Vale into your Python virtual environment—which is also created via any documentation `Makefile` commands—when you invoke it for the first time. + +Vale has [integrations](https://vale.sh/docs/integrations/guide/) with various IDEs. +Integration might require installing Vale using operating system's package manager. + +- [JetBrains](https://vale.sh/docs/integrations/jetbrains/) +- [Vim](https://github.com/dense-analysis/ale) +- [VS Code](https://github.com/errata-ai/vale-vscode) + +Plone configures Vale in three places: + +- {file}`.vale.ini` is Vale's configuration file. + This file allows overriding rules or changing their severity. +- {file}`Makefile` passes options to the `vale` command, such as the files Vale checks. +- Plone documentation uses a custom spelling dictionary, with accepted and rejected spellings in `styles/Vocab/Plone`. + Authors should add new words and proper names using correct casing to {file}`styles/Vocab/Plone/accept.txt`, sorted alphabetically and case-insensitive. + (authors-linkcheck-label)= diff --git a/docs/contributing/documentation/setup-build.md b/docs/contributing/documentation/setup-build.md index 33c557962..3e56b0318 100644 --- a/docs/contributing/documentation/setup-build.md +++ b/docs/contributing/documentation/setup-build.md @@ -30,33 +30,6 @@ A more recent Python is preferred. Use your system's package manager or [pyenv](https://github.com/pyenv/pyenv) to install an appropriate version of Python. -(setup-build-installation-vale-label)= - -### Vale - -Vale is a linter for narrative text. -It checks spelling, English grammar, and style guides. -Plone documentation uses a custom spelling dictionary, with accepted and rejected spellings in `styles/Vocab/Plone`. - -Use your operating system's package manager to [install Vale](https://vale.sh/docs/vale-cli/installation/). - -Vale also has [integrations](https://vale.sh/docs/integrations/guide/) with various IDEs. - -- [JetBrains](https://vale.sh/docs/integrations/jetbrains/) -- [Vim](https://github.com/dense-analysis/ale) -- [VS Code](https://github.com/errata-ai/vale-vscode) - -Plone documentation uses a file located at the root of the repository, `.vale.ini`, to configure Vale. -This file allows overriding rules or changing their severity. - -The Plone Documentation Team selected the [Microsoft Writing Style Guide](https://learn.microsoft.com/en-us/style-guide/welcome/) for its ease of use—especially for non-native English readers and writers—and attention to non-technical audiences. - -```{note} -More corrections to spellings and Vale's configuration are welcome by submitting a pull request. -This is an easy way to become a contributor to Plone. -``` - - (setup-build-installation-graphviz-label)= ### Graphviz diff --git a/requirements.txt b/requirements.txt index 17c6742b7..f0b170ef2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,3 +16,4 @@ sphinxcontrib.httpdomain # plone.restapi sphinxcontrib.httpexample # plone.restapi sphinxcontrib-video sphinxext-opengraph +vale From 9718cfdec507b325a918cecde8158da9cf1d7aba Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 7 Dec 2023 14:49:41 -0800 Subject: [PATCH 047/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index ea22fba21..936f5ea65 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit ea22fba21337f487fbf9d71734aae626002ce536 +Subproject commit 936f5ea6562a777abfcff90812793321eacf2b06 From 2c98180dabf0a3241f752a6b9e56c48ba2aab0c2 Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Wed, 13 Dec 2023 16:13:31 +0100 Subject: [PATCH 048/810] feat(classic UI): how to get a minimal barceloneta integration Explain all the steps to get a custom CSS bundle out of barceloneta theme to style the core/backend parts of Plone Classic UI. --- docs/classic-ui/theming/from-scratch.md | 79 +++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/docs/classic-ui/theming/from-scratch.md b/docs/classic-ui/theming/from-scratch.md index 9d2110e07..b95296bcd 100644 --- a/docs/classic-ui/theming/from-scratch.md +++ b/docs/classic-ui/theming/from-scratch.md @@ -123,6 +123,85 @@ yarn dist - Import Boostrap (as basis) +#### Minimal backend styling + +When creating a theme from scratch, it still makes sense (and saves time) to reuse the barceloneta theme for: + +- Plone toolbar +- add/edit forms +- control panels + +To be able to do so: + +- create a new CSS file on your theme like this: + +```scss +// plone variables (used in toolbar) +// Plone specific colors +//colors +$state-draft-color: #fab82a!default; // lime-yellow //draft is visible +$state-pending-color: #e2e721!default; // orange +$state-private-color: #c4183c!default; // red +$state-internal-color: #fab82a!default; // is draft +$state-internally-published-color: #883dfa!default; // is intranet +$plone-link-color: #007bb1!default; //plone blue made slightly darker for wcag 2.0 +$spacer: 1rem!default; + +// Toolbar +$plone-toolbar-bg: rgba(0, 0, 0, 0.9); +$plone-toolbar-submenu-bg: rgba(20, 20, 20, 0.95); +$plone-toolbar-font-primary: "Roboto Condensed", sans-serif; +$plone-toolbar-font-secondary: "Roboto", sans-serif; +$plone-toolbar-separator-color: rgba(255, 255, 255, 0.17); +$plone-toolbar-link: $plone-link-color; +$plone-toolbar-text-color: rgba(255, 255, 255, 0.9); +$plone-toolbar-submenu-text-color: #fff; +$plone-toolbar-submenu-header-color: lighten(#000, 80%); + +$plone-toolbar-locked-color: var(--bs-warning); // is intranet + +$plone-toolbar-width: 220px; +$plone-toolbar-width-collapsed: calc($spacer * 2.25); +$plone-toolbar-top-height: calc($spacer * 2.5); + +@import "bootstrap/scss/bootstrap"; + +@import "@plone/plonetheme-barceloneta-base/scss/toolbar"; +@import "@plone/plonetheme-barceloneta-base/scss/controlpanels"; +@import "@plone/plonetheme-barceloneta-base/scss/forms"; +``` + +!!! tip + See all the [barceloneta SCSS files](https://github.com/plone/plonetheme.barceloneta/tree/master/scss) + that are available and import the ones that you want to use. + +Add `@plone/plonetheme-barceloneta-base` as a dependency: + +```shell +yarn add @plone/plonetheme-barceloneta-base +``` + +Add a script on `package.json` to compile the CSS: + +```json + "css-compile-main": "sass --load-path=node_modules --style expanded --source-map --embed-sources --no-error-css plone.scss:../static/plone.css" +``` + +!!! tip + Look at [plonetheme.barcelonta package.json](https://github.com/plone/plonetheme.barceloneta/blob/master/package.json) + for a few more scripts to prefix and minify your CSS to get a production ready bundle. + +Run the compilation: + +```shell +yarn run css-compile-main +``` + +Finally, register the [CSS as a bundle](#bundle-registration). + +With this, you will save yourself quite some work on styling the toolbar, the add/edit forms and controlpanels, +while keeping the rest of your theming on your own. + #### Templates - Add `z3c.jbot` overrides From c5d29ebeb108c396e28219bc5b0f9bc20b62e5e1 Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Wed, 13 Dec 2023 16:21:58 +0100 Subject: [PATCH 049/810] fix admonitions --- docs/classic-ui/theming/from-scratch.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/classic-ui/theming/from-scratch.md b/docs/classic-ui/theming/from-scratch.md index b95296bcd..33bc8d26b 100644 --- a/docs/classic-ui/theming/from-scratch.md +++ b/docs/classic-ui/theming/from-scratch.md @@ -171,9 +171,10 @@ $plone-toolbar-top-height: calc($spacer * 2.5); @import "@plone/plonetheme-barceloneta-base/scss/forms"; ``` -!!! tip - See all the [barceloneta SCSS files](https://github.com/plone/plonetheme.barceloneta/tree/master/scss) - that are available and import the ones that you want to use. +```{tip} +See all the [barceloneta SCSS files](https://github.com/plone/plonetheme.barceloneta/tree/master/scss) +that are available and import the ones that you want to use. +``` Add `@plone/plonetheme-barceloneta-base` as a dependency: @@ -187,10 +188,11 @@ Add a script on `package.json` to compile the CSS: "css-compile-main": "sass --load-path=node_modules --style expanded --source-map --embed-sources --no-error-css plone.scss:../static/plone.css" ``` -!!! tip - Look at [plonetheme.barcelonta package.json](https://github.com/plone/plonetheme.barceloneta/blob/master/package.json) - for a few more scripts to prefix and minify your CSS to get a production ready bundle. - +```{tip} +Look at [plonetheme.barcelonta package.json](https://github.com/plone/plonetheme.barceloneta/blob/master/package.json) +for a few more scripts to prefix and minify your CSS to get a production ready bundle. +``` + Run the compilation: ```shell From bb4bea29672659c3e7f2471fac7094737da42e6f Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Wed, 13 Dec 2023 16:32:03 +0100 Subject: [PATCH 050/810] fix the reference --- docs/classic-ui/theming/from-scratch.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/classic-ui/theming/from-scratch.md b/docs/classic-ui/theming/from-scratch.md index 33bc8d26b..e841be69d 100644 --- a/docs/classic-ui/theming/from-scratch.md +++ b/docs/classic-ui/theming/from-scratch.md @@ -66,6 +66,8 @@ prefix = /++theme++plonetheme.munich doctype = ``` +(classic-ui-from-scratch-bundle-registration-label) + ### Bundle registration ```xml @@ -199,7 +201,7 @@ Run the compilation: yarn run css-compile-main ``` -Finally, register the [CSS as a bundle](#bundle-registration). +Finally, register the bundle: {ref}`classic-ui-from-scratch-bundle-registration-label`. With this, you will save yourself quite some work on styling the toolbar, the add/edit forms and controlpanels, while keeping the rest of your theming on your own. From 5df1d66331e0071d074871f7ccb7fa0d2ae31730 Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Wed, 13 Dec 2023 16:41:54 +0100 Subject: [PATCH 051/810] typo --- docs/classic-ui/theming/from-scratch.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/classic-ui/theming/from-scratch.md b/docs/classic-ui/theming/from-scratch.md index e841be69d..edf9cd26a 100644 --- a/docs/classic-ui/theming/from-scratch.md +++ b/docs/classic-ui/theming/from-scratch.md @@ -66,7 +66,7 @@ prefix = /++theme++plonetheme.munich doctype = ``` -(classic-ui-from-scratch-bundle-registration-label) +(classic-ui-from-scratch-bundle-registration-label)= ### Bundle registration From 02659194b3ac22fa3087090ccb804dc701b89756 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 14 Dec 2023 01:27:34 -0800 Subject: [PATCH 052/810] Clean up English and MyST syntax and grammar --- docs/classic-ui/theming/from-scratch.md | 138 ++++++++++++------------ 1 file changed, 68 insertions(+), 70 deletions(-) diff --git a/docs/classic-ui/theming/from-scratch.md b/docs/classic-ui/theming/from-scratch.md index edf9cd26a..7fb722fe5 100644 --- a/docs/classic-ui/theming/from-scratch.md +++ b/docs/classic-ui/theming/from-scratch.md @@ -122,89 +122,87 @@ yarn dist - Tweak basic settings like rounded corners, shadows, and so on. - Set custom fonts - Define your own stuff -- Import Boostrap (as basis) +- Import Bootstrap (as basis) #### Minimal backend styling -When creating a theme from scratch, it still makes sense (and saves time) to reuse the barceloneta theme for: - -- Plone toolbar -- add/edit forms -- control panels - -To be able to do so: - -- create a new CSS file on your theme like this: - -```scss -// plone variables (used in toolbar) -// Plone specific colors -//colors -$state-draft-color: #fab82a!default; // lime-yellow //draft is visible -$state-pending-color: #e2e721!default; // orange -$state-private-color: #c4183c!default; // red -$state-internal-color: #fab82a!default; // is draft -$state-internally-published-color: #883dfa!default; // is intranet -$plone-link-color: #007bb1!default; //plone blue made slightly darker for wcag 2.0 -$spacer: 1rem!default; - -// Toolbar -$plone-toolbar-bg: rgba(0, 0, 0, 0.9); -$plone-toolbar-submenu-bg: rgba(20, 20, 20, 0.95); -$plone-toolbar-font-primary: "Roboto Condensed", sans-serif; -$plone-toolbar-font-secondary: "Roboto", sans-serif; -$plone-toolbar-separator-color: rgba(255, 255, 255, 0.17); -$plone-toolbar-link: $plone-link-color; -$plone-toolbar-text-color: rgba(255, 255, 255, 0.9); -$plone-toolbar-submenu-text-color: #fff; -$plone-toolbar-submenu-header-color: lighten(#000, 80%); - -$plone-toolbar-locked-color: var(--bs-warning); // is intranet - -$plone-toolbar-width: 220px; -$plone-toolbar-width-collapsed: calc($spacer * 2.25); -$plone-toolbar-top-height: calc($spacer * 2.5); - -@import "bootstrap/scss/bootstrap"; - -@import "@plone/plonetheme-barceloneta-base/scss/toolbar"; -@import "@plone/plonetheme-barceloneta-base/scss/controlpanels"; -@import "@plone/plonetheme-barceloneta-base/scss/forms"; -``` +When you create a theme from scratch, it is convenient to reuse the Barceloneta theme for: -```{tip} -See all the [barceloneta SCSS files](https://github.com/plone/plonetheme.barceloneta/tree/master/scss) -that are available and import the ones that you want to use. -``` +- Plone toolbar +- add and edit forms +- control panels -Add `@plone/plonetheme-barceloneta-base` as a dependency: +To do so, follow this guide. -```shell -yarn add @plone/plonetheme-barceloneta-base -``` +- Create a new CSS file in your theme, such as the following. -Add a script on `package.json` to compile the CSS: + ```scss + // plone variables (used in toolbar) + // Plone specific colors + //colors + $state-draft-color: #fab82a!default; // lime-yellow //draft is visible + $state-pending-color: #e2e721!default; // orange + $state-private-color: #c4183c!default; // red + $state-internal-color: #fab82a!default; // is draft + $state-internally-published-color: #883dfa!default; // is intranet + $plone-link-color: #007bb1!default; //plone blue made slightly darker for wcag 2.0 + $spacer: 1rem!default; + + // Toolbar + $plone-toolbar-bg: rgba(0, 0, 0, 0.9); + $plone-toolbar-submenu-bg: rgba(20, 20, 20, 0.95); + $plone-toolbar-font-primary: "Roboto Condensed", sans-serif; + $plone-toolbar-font-secondary: "Roboto", sans-serif; + $plone-toolbar-separator-color: rgba(255, 255, 255, 0.17); + $plone-toolbar-link: $plone-link-color; + $plone-toolbar-text-color: rgba(255, 255, 255, 0.9); + $plone-toolbar-submenu-text-color: #fff; + $plone-toolbar-submenu-header-color: lighten(#000, 80%); + + $plone-toolbar-locked-color: var(--bs-warning); // is intranet + + $plone-toolbar-width: 220px; + $plone-toolbar-width-collapsed: calc($spacer * 2.25); + $plone-toolbar-top-height: calc($spacer * 2.5); + + @import "bootstrap/scss/bootstrap"; + + @import "@plone/plonetheme-barceloneta-base/scss/toolbar"; + @import "@plone/plonetheme-barceloneta-base/scss/controlpanels"; + @import "@plone/plonetheme-barceloneta-base/scss/forms"; + ``` -```json - "css-compile-main": "sass --load-path=node_modules --style expanded --source-map --embed-sources --no-error-css plone.scss:../static/plone.css" -``` + ```{tip} + See all the available [Barceloneta SCSS files](https://github.com/plone/plonetheme.barceloneta/tree/master/scss), and import the ones that you want to use. + ``` -```{tip} -Look at [plonetheme.barcelonta package.json](https://github.com/plone/plonetheme.barceloneta/blob/master/package.json) -for a few more scripts to prefix and minify your CSS to get a production ready bundle. -``` - -Run the compilation: +- Add `@plone/plonetheme-barceloneta-base` as a dependency. -```shell -yarn run css-compile-main -``` + ```shell + yarn add @plone/plonetheme-barceloneta-base + ``` + +- Add a script in {file}`package.json` to compile the CSS. + + ```json + "css-compile-main": "sass --load-path=node_modules --style expanded --source-map --embed-sources --no-error-css plone.scss:../static/plone.css" + ``` + + ```{tip} + Look at [`plonetheme.barcelonta`'s {file}`package.json`](https://github.com/plone/plonetheme.barceloneta/blob/master/package.json) for a few more scripts that can prefix and minify your CSS and get a bundle for use in production. + ``` + +- Run the compilation. + + ```shell + yarn run css-compile-main + ``` + +- Finally, {ref}`register the bundle `. -Finally, register the bundle: {ref}`classic-ui-from-scratch-bundle-registration-label`. +With this guide, you will save yourself quite some work on styling the toolbar, the add and edit forms, and control panels, while keeping the rest of your theming separate. -With this, you will save yourself quite some work on styling the toolbar, the add/edit forms and controlpanels, -while keeping the rest of your theming on your own. #### Templates From eb9274017488d25d94b5ad3136c941fcd36fd0b8 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 14 Dec 2023 01:35:38 -0800 Subject: [PATCH 053/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index d5b83a67b..cab38fe22 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit d5b83a67b5a894b7985c67e6c2ae0c9eb1034fd6 +Subproject commit cab38fe22aa6918969c1703ce99e68b9bae1af26 diff --git a/submodules/volto b/submodules/volto index 936f5ea65..b8cb12763 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 936f5ea6562a777abfcff90812793321eacf2b06 +Subproject commit b8cb127631f9297ac625eabc65cae6b2c59e210d From fd3f240904e7d10c4680d7701fa9ddf93650209f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 17 Dec 2023 05:15:51 +0100 Subject: [PATCH 054/810] Fix GitHub redirects --- docs/contributing/first-time.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/contributing/first-time.md b/docs/contributing/first-time.md index 65ed984c1..b88cb7b04 100644 --- a/docs/contributing/first-time.md +++ b/docs/contributing/first-time.md @@ -153,9 +153,9 @@ You will pull code from the upstream Plone repository, push your work from your _Plone git workflow_ ```` -1. Start by [forking the project's repository](https://docs.github.com/en/get-started/quickstart/fork-a-repo) to your account through the GitHub interface. -1. [Clone your forked repository](https://docs.github.com/en/get-started/quickstart/fork-a-repo#cloning-your-forked-repository). -1. [Configure git to sync your fork with the upstream repository](https://docs.github.com/en/get-started/quickstart/fork-a-repo#configuring-git-to-sync-your-fork-with-the-upstream-repository). +1. Start by [forking the project's repository](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) to your account through the GitHub interface. +1. [Clone your forked repository](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo#cloning-your-forked-repository). +1. [Configure git to sync your fork with the upstream repository](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo#configuring-git-to-sync-your-fork-with-the-upstream-repository). (write-code-label)= From cd826c644508560bfd621bea9ac28b383fbd8f4b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 17 Dec 2023 05:30:41 +0100 Subject: [PATCH 055/810] Try explicit pin --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index f0b170ef2..efd4380a5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ graphviz lesscpy linkify-it-py myst-parser -pydata-sphinx-theme<=0.8.99 # Build fails in 0.9.0. See https://github.com/plone/documentation/issues/1297 +pydata-sphinx-theme==0.8.1 # Build fails in 0.9.0. See https://github.com/plone/documentation/issues/1297 sphinx-autobuild sphinx-book-theme==0.3.3 # Temporary pin until we can sort out HTML refactoring. sphinx-copybutton From 056b29ad589e7b5f67d301ca517505f0b49f50fe Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 17 Dec 2023 05:39:45 +0100 Subject: [PATCH 056/810] Update tips submodules/plone.api submodules/volto --- submodules/plone.api | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index 91825e34b..4a4c1c2a7 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit 91825e34bd2703256a397efa6dc07ddd7d93d910 +Subproject commit 4a4c1c2a7c6d015ae34d2aa18cc5c09269bce565 diff --git a/submodules/volto b/submodules/volto index b8cb12763..10014f810 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit b8cb127631f9297ac625eabc65cae6b2c59e210d +Subproject commit 10014f810c325c6571859e0d6ce931e425355d4f From 1a075e1321ee9aed71912d378d9c46cd5e96e70b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 18 Dec 2023 10:26:28 +0100 Subject: [PATCH 057/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 10014f810..075001d45 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 10014f810c325c6571859e0d6ce931e425355d4f +Subproject commit 075001d4525ba60df3baceda70d51f4950ca6bbc From 5f103267eb5b5678abc0d16d36f1e4bcb155abb7 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 22 Dec 2023 01:19:19 +0100 Subject: [PATCH 058/810] Fix redirects --- docs/install/install-from-packages.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install/install-from-packages.md b/docs/install/install-from-packages.md index f832aab56..94eb64220 100644 --- a/docs/install/install-from-packages.md +++ b/docs/install/install-from-packages.md @@ -99,7 +99,7 @@ Adapt them for your flavor of shell. ```{seealso} See the [`nvm` install and update script documentation](https://github.com/nvm-sh/nvm#install--update-script). -For the `fish` shell, see [`nvm.fish`](https://github.com/jorgebucaran/nvm.fish). +For the `fish` shell, see [`nvm.fish`](https://github.com/foldmap/nvm.fish). ``` 1. Create your shell profile, if it does not exist. From 77c2244edb166cbe67ac9d0062b5dd3b04edccdc Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 22 Dec 2023 11:03:38 +0100 Subject: [PATCH 059/810] Bump Plone docker image patch version --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index e2751d945..782d34daf 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -322,7 +322,7 @@ def source_replace(app, docname, source): # Dict of replacements. source_replacements = { "{PLONE_BACKEND_MINOR_VERSION}": "6.0", - "{PLONE_BACKEND_PATCH_VERSION}": "6.0.8", + "{PLONE_BACKEND_PATCH_VERSION}": "6.0.9", "{NVM_VERSION}": "0.39.5", "{SUPPORTED_PYTHON_VERSIONS}": "3.8, 3.9, 3.10, or 3.11", } From 3b56a76fc97a56d20fa0525f0a40a661b64f8118 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 22 Dec 2023 11:59:18 +0100 Subject: [PATCH 060/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 075001d45..e159b8cff 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 075001d4525ba60df3baceda70d51f4950ca6bbc +Subproject commit e159b8cffebd66f2272f29aa3775abf8ceae8fd4 From 437fa47ce3922960473880bd26ad6105badff921 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 23 Dec 2023 23:18:27 +0100 Subject: [PATCH 061/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index e159b8cff..e794843c7 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit e159b8cffebd66f2272f29aa3775abf8ceae8fd4 +Subproject commit e794843c73a236e74cef33d302d2118ecc0ac34a From 49d2344a9bb6fa52ab51b19e38dede1e3b3c6394 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 23 Dec 2023 23:35:51 +0100 Subject: [PATCH 062/810] Fix redirect for nvm.fish --- docs/install/install-from-packages.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install/install-from-packages.md b/docs/install/install-from-packages.md index 94eb64220..4026d6d03 100644 --- a/docs/install/install-from-packages.md +++ b/docs/install/install-from-packages.md @@ -99,7 +99,7 @@ Adapt them for your flavor of shell. ```{seealso} See the [`nvm` install and update script documentation](https://github.com/nvm-sh/nvm#install--update-script). -For the `fish` shell, see [`nvm.fish`](https://github.com/foldmap/nvm.fish). +For the `fish` shell, see [`nvm.fish`](https://github.com/joxji/nvm.fish). ``` 1. Create your shell profile, if it does not exist. From b2d7d36202cd0327982bf6a4b368697f252cbf26 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 24 Dec 2023 01:23:08 +0100 Subject: [PATCH 063/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index e794843c7..41ca6772a 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit e794843c73a236e74cef33d302d2118ecc0ac34a +Subproject commit 41ca6772ac6fbd1b5e093ecc2d0191c8257f7de8 From 55c373ff4fe4c2eaae2e538f8be965b0d2c4e6d9 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 24 Dec 2023 09:40:10 +0100 Subject: [PATCH 064/810] Use includes for installation of prerequisites --- docs/conf.py | 3 ++ docs/install/install-from-packages.md | 57 +++------------------------ 2 files changed, 9 insertions(+), 51 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 782d34daf..e9bd981e1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -127,6 +127,9 @@ "plone.restapi/performance", "plone.restapi/src", "volto/contributing/branch-policy.md", + "volto/contributing/install-nvm.md", + "volto/contributing/install-nodejs.md", + "volto/contributing/install-make.md", ] suppress_warnings = [ diff --git a/docs/install/install-from-packages.md b/docs/install/install-from-packages.md index 4026d6d03..04bc12935 100644 --- a/docs/install/install-from-packages.md +++ b/docs/install/install-from-packages.md @@ -94,56 +94,16 @@ pip install pipx #### nvm -The following terminal session commands use `bash` for the shell. -Adapt them for your flavor of shell. - -```{seealso} -See the [`nvm` install and update script documentation](https://github.com/nvm-sh/nvm#install--update-script). -For the `fish` shell, see [`nvm.fish`](https://github.com/joxji/nvm.fish). +```{include} ../volto/contributing/install-nvm.md ``` -1. Create your shell profile, if it does not exist. - - ```shell - touch ~/.bash_profile - ``` - -2. Download and run the `nvm` install and update script, and pipe it into `bash`. - - ```shell - curl -o- https://raw.githubusercontent.com/creationix/nvm/v{NVM_VERSION}/install.sh | bash - ``` - -3. Source your profile. - Alternatively close the session and open a new one. - - ```shell - source ~/.bash_profile - ``` - -4. Verify that the `nvm` version is that which you just installed or updated: - - ```shell - nvm --version - ``` - (install-prerequisites-nodejs-label)= #### Node.js -1. Install or update the supported LTS versions of Node.js, then activate the version supported in Volto. - - ```shell - nvm install "lts/*" - nvm use 20 - ``` - -2. Verify that the supported version of Node.js is activated. - - ```shell - node -v - ``` +```{include} ../volto/contributing/install-nodejs.md +``` (install-prerequisites-yeoman-label)= @@ -185,25 +145,20 @@ Install the latest Yarn 3 version (not the Classic 1.x one) using `npm`. ``` If the version doesn't change, you can try deleting the {file}`yarn.lock` file, setting the version, and installing again. + ```shell rm yarn.lock yarn set version 3.x yarn install ``` - (install-prerequisites-make-label)= #### Make -{term}`Make` comes installed on most Linux distributions. -On macOS, you must first [install Xcode](https://developer.apple.com/xcode/resources/), then install its command line tools. -On Windows, it is strongly recommended to [Install Linux on Windows with WSL](https://learn.microsoft.com/en-us/windows/wsl/install), which will include `make`. - -Finally, it is a good idea to update your system's version of `make`, because some distributions, especially macOS, have an outdated version. -Use your favorite search engine or trusted online resource for how to update `make`. - +```{include} ../volto/contributing/install-make.md +``` (install-prerequisites-docker-label)= From c41d3438965b9c53a2876c171e085e34cab7158a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 24 Dec 2023 10:11:52 +0100 Subject: [PATCH 065/810] Revert include of install-nvm.md because substitutions do not work through includes. Copy-pasta is the only option. --- docs/conf.py | 1 - docs/install/install-from-packages.md | 32 ++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index e9bd981e1..a5875a0a3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -127,7 +127,6 @@ "plone.restapi/performance", "plone.restapi/src", "volto/contributing/branch-policy.md", - "volto/contributing/install-nvm.md", "volto/contributing/install-nodejs.md", "volto/contributing/install-make.md", ] diff --git a/docs/install/install-from-packages.md b/docs/install/install-from-packages.md index 04bc12935..992a97993 100644 --- a/docs/install/install-from-packages.md +++ b/docs/install/install-from-packages.md @@ -94,9 +94,39 @@ pip install pipx #### nvm -```{include} ../volto/contributing/install-nvm.md +The following terminal session commands use `bash` for the shell. +Adapt them for your flavor of shell. + +```{seealso} +See the [`nvm` install and update script documentation](https://github.com/nvm-sh/nvm#install--update-script). +For the `fish` shell, see [`nvm.fish`](https://github.com/joxji/nvm.fish). ``` +1. Create your shell profile, if it does not exist. + + ```shell + touch ~/.bash_profile + ``` + +2. Download and run the `nvm` install and update script, and pipe it into `bash`. + + ```shell + curl -o- https://raw.githubusercontent.com/creationix/nvm/v{NVM_VERSION}/install.sh | bash + ``` + +3. Source your profile. + Alternatively close the session and open a new one. + + ```shell + source ~/.bash_profile + ``` + +4. Verify that the `nvm` version is that which you just installed or updated: + + ```shell + nvm --version + ``` + (install-prerequisites-nodejs-label)= From 0e26e47ca6d0c68ac2c543e82ed6d9bc15f93543 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 24 Dec 2023 12:03:33 +0100 Subject: [PATCH 066/810] Add pnpm to Glossary --- docs/glossary.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/glossary.md b/docs/glossary.md index 175f35602..7260b4e87 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -671,4 +671,7 @@ intid WSL Windows Subsystem for Linux The [Windows Subsystem for Linux (WSL)](https://learn.microsoft.com/en-us/windows/wsl/install) lets developers install a Linux distribution (such as Ubuntu, OpenSUSE, Kali, Debian, or Arch Linux) and use Linux applications, utilities, and Bash command-line tools directly on Windows, unmodified, without the overhead of a traditional virtual machine or dualboot setup. + +pnpm + [pnpm](https://pnpm.io/) is a fast, disk space efficient package manager. ``` From 42bd52fd751e0caac23e59380066c72b4aa44667 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 24 Dec 2023 12:05:47 +0100 Subject: [PATCH 067/810] Move operating system pre-requisite into an included file --- docs/conf.py | 1 + docs/install/install-from-packages.md | 10 ++-------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index a5875a0a3..16efb32ea 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -127,6 +127,7 @@ "plone.restapi/performance", "plone.restapi/src", "volto/contributing/branch-policy.md", + "volto/contributing/install-operating-system.md", "volto/contributing/install-nodejs.md", "volto/contributing/install-make.md", ] diff --git a/docs/install/install-from-packages.md b/docs/install/install-from-packages.md index 992a97993..a121ef713 100644 --- a/docs/install/install-from-packages.md +++ b/docs/install/install-from-packages.md @@ -51,14 +51,8 @@ To avoid RAM and disk swap limitations, we recommend either temporarily resizing ### Pre-requisites for installation -- An operating system that runs all the requirements mentioned above. - Most UNIX-based operating systems are supported, including many Linux distributions, macOS, or {term}`Windows Subsystem for Linux` (WSL) on Windows. - A UNIX-based operating system is recommended. - - ```{important} - Windows alone is not recommended because it does not support {term}`GNU make`. - If you get Plone to run on Windows alone, please feel free to document and share your process. - ``` +```{include} ../volto/contributing/install-operating-system.md +``` - Python {SUPPORTED_PYTHON_VERSIONS} - {term}`pipx` From 962365b39e3a6d2f7ae7bf7c20f28b8ed0cde9d4 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 24 Dec 2023 19:18:20 +0100 Subject: [PATCH 068/810] Make a distinction between developing a project using Plone and developing Plone and its packages in the installation introduction --- docs/install/index.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/install/index.md b/docs/install/index.md index fbfaf8545..53cf103e6 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -11,7 +11,9 @@ myst: # Install -In this part of the documentation, you can find how to try Plone and how to choose an installation method if you want to develop in Plone. +In this part of the documentation, you can find how to try Plone and how to choose an installation method for developing a project using Plone. + +For developing Plone and its packages as open source software contributions, see the package's contributing guide. (install-index-getting-started-label)= From de0270f9401bff4b43e34c9c9c88995cb5db30d7 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 24 Dec 2023 19:42:07 +0100 Subject: [PATCH 069/810] Move Docker pre-requisite to an include, and add as a requirement to develop in Volto core. --- docs/install/install-from-packages.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/install/install-from-packages.md b/docs/install/install-from-packages.md index a121ef713..f5277f10a 100644 --- a/docs/install/install-from-packages.md +++ b/docs/install/install-from-packages.md @@ -184,12 +184,13 @@ Install the latest Yarn 3 version (not the Classic 1.x one) using `npm`. ```{include} ../volto/contributing/install-make.md ``` + (install-prerequisites-docker-label)= #### Install Docker -Install [Docker Desktop](https://docs.docker.com/get-docker/) for your operating system. -Docker Desktop includes all Docker tools. +```{include} ../volto/contributing/install-docker.md +``` (install-packages-install-label)= From 5708d29a4f18ae3eb67484de3d3d254ed84670c6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 24 Dec 2023 21:35:29 +0100 Subject: [PATCH 070/810] Fix redirect yet again, wtf fish? make up your mind! --- docs/install/install-from-packages.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install/install-from-packages.md b/docs/install/install-from-packages.md index f5277f10a..96add506e 100644 --- a/docs/install/install-from-packages.md +++ b/docs/install/install-from-packages.md @@ -93,7 +93,7 @@ Adapt them for your flavor of shell. ```{seealso} See the [`nvm` install and update script documentation](https://github.com/nvm-sh/nvm#install--update-script). -For the `fish` shell, see [`nvm.fish`](https://github.com/joxji/nvm.fish). +For the `fish` shell, see [`nvm.fish`](https://github.com/jorgebucaran/nvm.fish). ``` 1. Create your shell profile, if it does not exist. From 31544d225b51f1e56a05beb6073b5d95bb878e59 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 25 Dec 2023 23:13:01 +0100 Subject: [PATCH 071/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 41ca6772a..5acf6f37c 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 41ca6772ac6fbd1b5e093ecc2d0191c8257f7de8 +Subproject commit 5acf6f37c2c6f0f9b9171acec06a57b0e37363df From a5922d30e08c8c653976d471359302ae955f641e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 26 Dec 2023 17:22:57 +0100 Subject: [PATCH 072/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 5acf6f37c..21749fc5f 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 5acf6f37c2c6f0f9b9171acec06a57b0e37363df +Subproject commit 21749fc5fbc520b4fd46248e00d4ab07d07a71f3 From 55ceb65343b51f7bb844ea23103337f6d7c7497b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 26 Dec 2023 17:41:05 +0100 Subject: [PATCH 073/810] Added "Don't ask if an issue is open" to things not to do as a first-timer, with tips of how to figure it out yourself --- docs/contributing/first-time.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/contributing/first-time.md b/docs/contributing/first-time.md index b88cb7b04..cbfa72679 100644 --- a/docs/contributing/first-time.md +++ b/docs/contributing/first-time.md @@ -87,6 +87,18 @@ Learn from their mistakes, and don't commit them yourself. It also sends notifications to hundreds of developers, informing them that you have not read this guide, and annoying many of them. You should instead learn how to {ref}`work-with-github-issues-label` and {ref}`run tests and code quality checks locally `. +4. **Don't ask if an issue is open.** + Instead you can determine whether an issue is open by doing your own research using the following tips. + + - Check the issue's status indicator for a green label of {guilabel}`Open`. + - Look for linked open pull requests in the issue's history. + - Search open pull requests for the issue. + Sometimes contributors fail to link their pull request to an open issue. + - Review unreleased change log entries in the package's {guilabel}`news` directory. + Each pull request must have a change log entry, and these entries end up here when pull requests are merged and closed. + - Search release notes to see whether the issue has been resolved. + On rare occasions, contributors forget to close the original issue. + (plone-contributors-team-label)= @@ -221,9 +233,14 @@ Once you have completed, tested, and linted your code, and created a {ref}`contr - Make both your title and description descriptive. Reviewers look at many pull requests, and need to quickly understand the context. A lazily written phrase such as "Fixes bug" is meaningless. - - Include "Fixes #" and the related issue number in the description. + - Include "Fixes #ISSUE-NUMBER" in the description. This enables automatic closing of the related issue when the pull request is merged. This also creates a hyperlink to the original issue for easy reference. + + ```{seealso} + [Linking a pull request to an issue using a keyword](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) + ``` + 1. **Request a review.** Identify who you should ask by either checking the history of the files you edit, or viewing the project's list of contributors for an active member. If you have write access to the repository, [request a review](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/requesting-a-pull-request-review) from other team members. From 9fc70e93186b66bdda0e2e427f8732d7cb206399 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 26 Dec 2023 19:24:38 +0100 Subject: [PATCH 074/810] Add start Plone to attempt to reproduce issue --- docs/contributing/first-time.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/contributing/first-time.md b/docs/contributing/first-time.md index cbfa72679..b5ae9daf2 100644 --- a/docs/contributing/first-time.md +++ b/docs/contributing/first-time.md @@ -90,6 +90,7 @@ Learn from their mistakes, and don't commit them yourself. 4. **Don't ask if an issue is open.** Instead you can determine whether an issue is open by doing your own research using the following tips. + - Start Plone or its specific package, follow the steps to attempt to reproduce the issue, and see if it still exists. - Check the issue's status indicator for a green label of {guilabel}`Open`. - Look for linked open pull requests in the issue's history. - Search open pull requests for the issue. From c86b29a7ae6df5ae7bdeda67ae1e11fd2a35a3ea Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 2 Jan 2024 12:55:49 -0800 Subject: [PATCH 075/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 21749fc5f..71ffb00ec 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 21749fc5fbc520b4fd46248e00d4ab07d07a71f3 +Subproject commit 71ffb00eca92b796487d5cda31e025d9ec811991 From f4498da265b0ea6126bd6e080aee66d1fedd2741 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 4 Jan 2024 11:07:22 -0800 Subject: [PATCH 076/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 71ffb00ec..2bce3a31d 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 71ffb00eca92b796487d5cda31e025d9ec811991 +Subproject commit 2bce3a31d37be6794ceae70d8aeb577977bad448 From 5044e4aae6ad20ede5716708ca90854443e97261 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 5 Jan 2024 12:21:26 -0800 Subject: [PATCH 077/810] Add important admonition to avoid using Plone core package names when running the cookiecutter. Include troubleshooting tip and error message. See https://github.com/collective/cookiecutter-plone-starter/issues/114 --- docs/install/install-from-packages.md | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/install/install-from-packages.md b/docs/install/install-from-packages.md index 96add506e..bd16803ce 100644 --- a/docs/install/install-from-packages.md +++ b/docs/install/install-from-packages.md @@ -222,6 +222,13 @@ You will be presented with a series of prompts. You can accept the default values in square brackets (`[default-option]`) by hitting the {kbd}`Enter` key, or enter your preferred values. For ease of documentation, we will use the default values. +(avoid-plone-core-package-names)= + +```{important} +For {guilabel}`Project Slug`, you must not use any of the Plone core package names listed in [`constraints.txt`](https://dist.plone.org/release/6.0-latest/constraints.txt). +Note that pip normalizes these names, so `plone.volto` and `plone-volto` are the same package. +``` + ```console % pipx run cookiecutter gh:collective/cookiecutter-plone-starter @@ -336,6 +343,30 @@ First the backend, then the frontend will be installed. When the process completes successfully, it will exit with no message. +````{note} +If you used a Plone core package name, then `make install` will return an error message such as the following. + +```console +ERROR: Cannot install plone-volto 1.0.0a1 (from /home/username/projects/volto/plone-volto/backend/src/plone_volto) because these package versions have conflicting dependencies. + +The conflict is caused by: + The user requested plone-volto 1.0.0a1 (from /home/username/projects/volto/plone-volto/backend/src/plone_volto) + The user requested (constraint) plone-volto==4.2.0 + +To fix this you could try to: +1. loosen the range of package versions you've specified +2. remove package versions to allow pip attempt to solve the dependency conflict + +ERROR: ResolutionImpossible: for help visit +make[2]: *** [Makefile:112: build-dev] Error 1 +make[2]: Leaving directory '/home/username/projects/volto/plone-volto/backend' +make[1]: *** [Makefile:46: install-backend] Error 2 +make[1]: Leaving directory '/home/username/projects/volto/plone-volto' +``` + +You must delete your project, {ref}`follow the important note `, and run the cookiecutter again. +```` + (install-packages-start-plone-label)= From 3c27a1cb5faa2ab80e7d9921ba008e8f04270176 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 8 Jan 2024 05:58:52 -0800 Subject: [PATCH 078/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index cab38fe22..16325f20b 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit cab38fe22aa6918969c1703ce99e68b9bae1af26 +Subproject commit 16325f20b927f28ff03762687862dcaea9944da5 diff --git a/submodules/volto b/submodules/volto index 2bce3a31d..0fcacc2a9 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 2bce3a31d37be6794ceae70d8aeb577977bad448 +Subproject commit 0fcacc2a937002079d3e1bbf7be7eccf4e453468 From bb4dc1d13a0946e6537300124030f203c87e1760 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 14 Jan 2024 01:19:59 -0800 Subject: [PATCH 079/810] Clarify install methods - Closes #1598 --- docs/install/containers/index.md | 9 +- docs/install/create-project.md | 457 ++++++++++++++++++++++++++ docs/install/index.md | 91 ++--- docs/install/install-from-packages.md | 448 +------------------------ 4 files changed, 491 insertions(+), 514 deletions(-) create mode 100644 docs/install/create-project.md diff --git a/docs/install/containers/index.md b/docs/install/containers/index.md index f776b2651..f8bd11f77 100644 --- a/docs/install/containers/index.md +++ b/docs/install/containers/index.md @@ -11,7 +11,14 @@ myst: # Containers -Using containers is the easiest way to try out and deploy Plone 6. +The Plone 6 images have all the system requirements, pre-requisites, and Plone 6 already installed, except those requirements needed for running the container engine itself. + +Using containers is the easiest way to deploy Plone 6. +Containers may also be used when {doc}`creating a Plone project <../create-project>` and {doc}`contributing to Plone `. + +The Plone 6 container images are compliant with the [Open Container Initiative (OCI)](https://opencontainers.org/). +They should work with any OCI-compliant container engine for developing, managing, and running Plone 6 images. +Two popular options include [podman](https://podman.io/) and [Docker](https://www.docker.com/products/docker-desktop/). The community provides official images that could be used for standalone Plone installations. These images support a variety of installation options. diff --git a/docs/install/create-project.md b/docs/install/create-project.md new file mode 100644 index 000000000..df722c776 --- /dev/null +++ b/docs/install/create-project.md @@ -0,0 +1,457 @@ +--- +myst: + html_meta: + "description": "Create a Plone project" + "property=og:description": "Create a Plone project" + "property=og:title": "Create a Plone project" + "keywords": "Plone, Plone 6, create, project, install, cookiecutter" +--- + + +(install-packages-1-label)= + +# Create a project + +This chapter describes how you can create a web application project using Plone, with full control over development and deployment. + + +(install-packages-system-requirements-label)= + +## System requirements + +Plone 6 has both hardware requirements and software pre-requisites. + + +(install-packages-hardware-requirements-label)= + +### Hardware requirements + +The hardware requirements below give a rough estimate of the minimum hardware setup needed for a Plone server. + +A single Plone installation is able to run many Plone sites. + +- Installation of the Plone backend and Classic UI frontend requires a minimum of 256 MB of RAM and 2GB of disk swap space. +- Installation of the Volto frontend requires a minimum of 2GB of RAM. +- After installation, running Plone requires a minimum of 256 MB RAM and 512 MB of disk swap space per Plone site. + 2 GB or more RAM per Plone site is recommended. +- Minimum 512 MB hard disk space is required. + 40 GB or more hard disk space is recommended. + + +````{warning} +{term}`Add-on` products and caching solutions may also increase RAM and disk swap space requirements. +To avoid RAM and disk swap limitations, we recommend either temporarily resizing your remote machine to accommodate the build, or build your images locally and upload them to an image store, such as [Docker Hub](https://hub.docker.com/) or [GitHub Packages](https://github.com/features/packages). +```{seealso} +[How much RAM is required to build a Volto front end?](https://community.plone.org/t/how-much-ram-is-required-to-build-a-volto-front-end/17949) and [Dealing with heap exhaustion while building Volto 17 on limited-RAM host](https://community.plone.org/t/dealing-with-heap-exhaustion-while-building-volto-17-on-limited-ram-host/18078). +``` +```` + + +(install-packages-prerequisites-label)= + +### Pre-requisites for installation + +```{include} ../volto/contributing/install-operating-system.md +``` + +- Python {SUPPORTED_PYTHON_VERSIONS} +- {term}`pipx` +- {term}`nvm` +- {term}`Node.js` LTS 20.x +- {term}`Yeoman` +- {term}`Yarn` +- {term}`GNU make` +- {term}`Docker` + + +(install-prerequisites-python-label)= + +#### Python + +Installing Python is beyond the scope of this documentation. +However, it is recommended to use a Python version manager, {term}`pyenv` that allows you to install multiple versions of Python on your development environment without destroying your system's Python. +Plone requires Python version {SUPPORTED_PYTHON_VERSIONS}. + + +(install-prerequisites-pipx-label)= + +#### pipx + +Install {term}`pipx`. + +```shell +pip install pipx +``` + + +(install-prerequisites-nvm-label)= + +#### nvm + +The following terminal session commands use `bash` for the shell. +Adapt them for your flavor of shell. + +```{seealso} +See the [`nvm` install and update script documentation](https://github.com/nvm-sh/nvm#install--update-script). +For the `fish` shell, see [`nvm.fish`](https://github.com/jorgebucaran/nvm.fish). +``` + +1. Create your shell profile, if it does not exist. + + ```shell + touch ~/.bash_profile + ``` + +2. Download and run the `nvm` install and update script, and pipe it into `bash`. + + ```shell + curl -o- https://raw.githubusercontent.com/creationix/nvm/v{NVM_VERSION}/install.sh | bash + ``` + +3. Source your profile. + Alternatively close the session and open a new one. + + ```shell + source ~/.bash_profile + ``` + +4. Verify that the `nvm` version is that which you just installed or updated: + + ```shell + nvm --version + ``` + + +(install-prerequisites-nodejs-label)= + +#### Node.js + +```{include} ../volto/contributing/install-nodejs.md +``` + + +(install-prerequisites-yeoman-label)= + +#### Yeoman + +Install {term}`Yeoman`. + +```shell +npm install -g yo +``` + + +(install-prerequisites-yarn-label)= + +#### Yarn 3 + +Install the latest Yarn 3 version (not the Classic 1.x one) using `npm`. + +1. Open a terminal and type: + + ```shell + npm install yarn@3 + ``` + +2. Verify that Yarn v3.x.x is installed and activated. + + ```shell + yarn -v + ``` + ```console + 3.2.3 + ``` + + If you do not see a version of Yarn 3, then try the following to set the active version. + + ```shell + yarn set version 3.x + ``` + + If the version doesn't change, you can try deleting the {file}`yarn.lock` file, setting the version, and installing again. + + ```shell + rm yarn.lock + yarn set version 3.x + yarn install + ``` + + +(install-prerequisites-make-label)= + +#### Make + +```{include} ../volto/contributing/install-make.md +``` + + +(install-prerequisites-docker-label)= + +#### Install Docker + +```{include} ../volto/contributing/install-docker.md +``` + + +(install-packages-install-label)= + +## Install Plone 6 + +We install Plone 6 with {term}`pipx`, {term}`Cookiecutter`, {term}`mxdev`, {term}`make`, and other developer tools. + +```{note} +We do not maintain documentation for installing Plone 6 or later with `buildout`. +For Plone 5, `buildout` was the preferred installation method. +You can read the [documentation of how to install Plone 5 with `buildout`](https://5.docs.plone.org/manage/installing/installation_minimal_buildout.html), and adapt it to your needs for Plone 6. +``` + +Create a new directory to hold your project, and make it your current directory. + +```shell +mkdir my_project +cd my_project +``` + +Issue the following command to install or update `cookiecutter`, then run it to create a Plone project skeleton using the Cookiecutter {term}`cookiecutter-plone-starter`. + +```shell +pipx run cookiecutter gh:collective/cookiecutter-plone-starter +``` + +You will be presented with a series of prompts. +You can accept the default values in square brackets (`[default-option]`) by hitting the {kbd}`Enter` key, or enter your preferred values. +For ease of documentation, we will use the default values. + +(avoid-plone-core-package-names)= + +```{important} +For {guilabel}`Project Slug`, you must not use any of the Plone core package names listed in [`constraints.txt`](https://dist.plone.org/release/6.0-latest/constraints.txt). +Note that pip normalizes these names, so `plone.volto` and `plone-volto` are the same package. +``` + +```console +% pipx run cookiecutter gh:collective/cookiecutter-plone-starter + + +Cookiecutter Plone Starter +================================================================================ + +Sanity checks +-------------------------------------------------------------------------------- + [1/5] Python: ✓ + [2/5] Node: ✓ + [3/5] yo: ✓ + [4/5] Docker: ✓ + [5/5] git: ✓ + +Project details +-------------------------------------------------------------------------------- + + [1/19] Project Title (Project Title): Plone Conference Website 2070 + [2/19] Project Description (A new project using Plone 6.): + [3/19] Project Slug (Used for repository id) (plone-conference-website-2070): + [4/19] Project URL (without protocol) (plone-conference-website-2070.example.com): + [5/19] Author (Plone Foundation): Elli + [6/19] Author E-mail (collective@plone.org): elli@plone.org + [7/19] Python Package Name (plone_conference_website_2070): + [8/19] Volto Addon Name (volto-plone-conference-website-2070): + [9/19] Choose a Python Test Framework + 1 - pytest + 2 - unittest + Choose from [1/2] (1): + [10/19] Plone Version (6.0.8): + [11/19] Should we use Volto Alpha Versions? (No): yes + [12/19] Volto Version (18.0.0-alpha.1): + [13/19] Volto Generator Version (8.0.0): + [14/19] Language + 1 - English + 2 - Deutsch + 3 - Español + 4 - Português (Brasil) + 5 - Nederlands + 6 - Suomi + Choose from [1/2/3/4/5/6] (1): + [15/19] GitHub Username or Organization (collective): ellizurigo + [16/19] Container Registry + 1 - GitHub Container Registry + 2 - Docker Hub + Choose from [1/2] (1): + [17/19] Should we setup a caching server? + 1 - Yes + 2 - No + Choose from [1/2] (1): 2 + [18/19] Add Ansible playbooks? + 1 - Yes + 2 - No + Choose from [1/2] (1): + [19/19] Add GitHub Action to Deploy this project? + 1 - Yes + 2 - No + Choose from [1/2] (1): + +Plone Conference Website 2070 generation +-------------------------------------------------------------------------------- + +Summary: + - Plone version: 6.0.8 + - Volto version: 18.0.0-alpha.1 + - Volto Generator version: 8.0.0 + - Output folder: /Users/katjasuss/Desktop/_temp/scratch_cookiecutter_plone/plone-conference-website-2070 + +Frontend codebase: + - Installing required npm packages + - Generate frontend application with @plone/volto 18.0.0-alpha.1 + +Backend codebase + - Remove folder src/plone_conference_website_2070/src/plone_conference_website_2070/tests not used by pytest + - Format generated code in the backend + +================================================================================ + +Project "Plone Conference Website 2070" was generated +-------------------------------------------------------------------------------- +Now, code it, create a git repository, push to your organization. + +Sorry for the convenience, +The Plone Community. + +================================================================================ +``` + +Change to your project directory {file}`plone-conference-website-2070`. + +```shell +cd plone-conference-website-2070 +``` + +Next you switch to using `make`. +To see all available commands and their descriptions, enter the following command. + +```shell +make help +``` + +To install both the Plone backend and frontend, use the following command. + +```shell +make install +``` + +This will take a few minutes. +☕️ +First the backend, then the frontend will be installed. + +When the process completes successfully, it will exit with no message. + +````{note} +If you used a Plone core package name, then `make install` will return an error message such as the following. + +```console +ERROR: Cannot install plone-volto 1.0.0a1 (from /home/username/projects/volto/plone-volto/backend/src/plone_volto) because these package versions have conflicting dependencies. + +The conflict is caused by: + The user requested plone-volto 1.0.0a1 (from /home/username/projects/volto/plone-volto/backend/src/plone_volto) + The user requested (constraint) plone-volto==4.2.0 + +To fix this you could try to: +1. loosen the range of package versions you've specified +2. remove package versions to allow pip attempt to solve the dependency conflict + +ERROR: ResolutionImpossible: for help visit +make[2]: *** [Makefile:112: build-dev] Error 1 +make[2]: Leaving directory '/home/username/projects/volto/plone-volto/backend' +make[1]: *** [Makefile:46: install-backend] Error 2 +make[1]: Leaving directory '/home/username/projects/volto/plone-volto' +``` + +You must delete your project, {ref}`follow the important note `, and run the cookiecutter again. +```` + + +(install-packages-start-plone-label)= + +## Start Plone + +Plone 6 has two servers: one for the frontend, and one for the backend. +As such, we need to maintain two active shell sessions, one for each server, to start your Plone site. + + +(install-packages-start-plone-backend-label)= + +### Start Plone backend + +In the currently open session, issue the following command. + +```shell +make start-backend +``` + +The Plone backend server starts up and emits messages to the console. + +```console +2022-09-24 01:30:17,799 WARNING [ZODB.FileStorage:411][MainThread] Ignoring index for //my_project/project-title/backend/instance/var/filestorage/Data.fs +2022-09-24 01:30:19,639 INFO [chameleon.config:38][MainThread] directory cache: //my_project/project-title/backend/instance/var/cache. +2022-09-24 01:30:23,680 INFO [plone.volto:22][MainThread] Aliasing collective.folderish classes to plone.volto classes. +2022-09-24 01:30:24,935 INFO [Zope:42][MainThread] Ready to handle requests +Starting server in PID 92714. +2022-09-24 01:30:24,940 INFO [waitress:486][MainThread] Serving on http://[::1]:8080 +2022-09-24 01:30:24,940 INFO [waitress:486][MainThread] Serving on http://127.0.0.1:8080 +``` + + +(install-packages-start-plone-frontend-label)= + +### Start Plone frontend + +Create a second shell session in a new window. +Change your current working directory to {file}`project-title`. +Start the Plone frontend with the following command. + +```shell +make start-frontend +``` + +The Plone frontend server starts up and emits messages to the console. + +```console + WAIT Compiling... + + +✔ Client + Compiled successfully in 864.83ms + +✔ Server + Compiled successfully in 9.62s + +✅ Server-side HMR Enabled! +sswp> Handling Hot Module Reloading +Volto is running in SEAMLESS mode +Using internal proxy: http://localhost:3000 -> http://localhost:8080/Plone +🎭 Volto started at 0.0.0.0:3000 🚀 +``` + +Note that the Plone frontend uses an internal proxy server to connect with the Plone backend. +Open a browser at the following URL to visit your Plone site. + +http://localhost:3000 + +You will see a page similar to the following. + +```{image} /_static/plone-home-page.png +:alt: Plone home page +:class: figure +``` + +Select the {guilabel}`Login` link to visit the login form, and enter the following credentials. + +- {guilabel}`Login name`: `admin` +- {guilabel}`Password`: `admin` + +```{image} /_static/plone-login-page.png +:alt: Plone login page +:class: figure +``` + +Now you can edit content or configure your Plone site. + +You can stop the site with {kbd}`ctrl-c`. diff --git a/docs/install/index.md b/docs/install/index.md index 53cf103e6..c938c0e36 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -11,96 +11,53 @@ myst: # Install -In this part of the documentation, you can find how to try Plone and how to choose an installation method for developing a project using Plone. +In this part of the documentation, you can find how to {ref}`try Plone ` or how to install Plone to either {doc}`Create a Plone project ` or {doc}`Contribute to a Plone package `. -For developing Plone and its packages as open source software contributions, see the package's contributing guide. +(install-index-try-plone-label)= -(install-index-getting-started-label)= - -## Getting started +## Try a Plone demo -::::{grid} 1 2 2 2 -:gutter: 1 1 1 2 - -:::{grid-item-card} {octicon}`browser;1.5em;sd-mr-1` Try a demo - -Choose a version. +Choose a version to demo. - [Plone 6 with Volto frontend](https://demo.plone.org/) -- [Plone 6 Classic UI (nightly build)](https://classic.demo.plone.org/login?came_from=/en) -::: +- [Plone 6 with Classic UI](https://classic.demo.plone.org/login?came_from=/en) -:::{grid-item-card} {octicon}`download;1.5em;sd-mr-1` Install - -Developers may choose to install Plone from either [the official container images](containers/index) or [packages](install-from-packages). -+++ -Help me [choose an installation method](install-index-choose-installation-method-label). -::: - -:::: - - -(install-index-choose-installation-method-label)= - -## Choose an installation method - -Developers may choose to install Plone from either [the official container images](containers/index) or [packages](install-from-packages). +(install-index-getting-started-label)= -### Containers +## Getting started -The Plone 6 container images are compliant with the [Open Container Initiative (OCI)](https://opencontainers.org/). -They should work with any OCI-compliant container engine for developing, managing, and running Plone 6 images. -Two popular options include [podman](https://podman.io/) and [Docker](https://www.docker.com/products/docker-desktop/). +Choose an option to get started with Plone. +If you are following a [Plone training](https://training.plone.org/), it should specify which option to choose. -The Plone 6 images have all the system requirements, pre-requisites, and Plone 6 already installed, except those requirements needed for running the container engine itself. +::::{grid} 1 2 2 2 +:gutter: 1 1 1 2 -This option is the quickest method to install and develop for Plone 6 and its packages. +:::{grid-item-card} {octicon}`browser;1.5em;sd-mr-1` Create a project +:link: create-project +:link-type: doc -:::{card} -:link: containers/index -:link-type: any -{octicon}`container;1.5em;sd-mr-1` [Use containers to install Plone](containers/index) +This option is for developers who want to create a web application using Plone. +See {doc}`create-project`. ::: +:::{grid-item-card} {octicon}`repo-push;1.5em;sd-mr-1` Contribute to a Plone package +:link: plone:contributing/index +:link-type: doc -### Packages - -There may be some cases where using a Plone 6 image and containers is not practical or desired. - -- You use an SQL database that is not PostgreSQL. -- You develop custom applications, themes, and add-ons for Plone. -- You use a deployment workflow that has specific requirements. - -For these situations, Plone 6 may be installed from its packages. - -It might be a challenge if you bump up against system requirements, or need to resolve conflicts between required packages. - -This method takes longer than using containers. - -:::{card} -:link: install-from-packages -:link-type: any -{octicon}`package;1.5em;sd-mr-1` [Install Plone from its packages](install-from-packages) +This option is for developers who want to contribute to Plone and its packages. +See {doc}`plone:contributing/index`. ::: - -(install-index-system-requirements-label)= - -## System Requirements - -System requirements depend upon your choice of installation method. - -- [Container system requirements](install-containers-index-system-requirements-label) -- [Packages system requirements](install-packages-system-requirements-label) +:::: ```{toctree} :maxdepth: 2 :hidden: true -containers/index -install-from-packages +create-project manage-add-ons-packages +containers/index ``` diff --git a/docs/install/install-from-packages.md b/docs/install/install-from-packages.md index bd16803ce..4e2bf4b6a 100644 --- a/docs/install/install-from-packages.md +++ b/docs/install/install-from-packages.md @@ -1,4 +1,5 @@ --- +orphan: true myst: html_meta: "description": "How to install Plone 6 from its packages." @@ -7,453 +8,8 @@ myst: "keywords": "Plone, Plone 6, install, pip, packages, source, cookiecutter" --- - (install-packages-1-label)= # Install Plone from its packages - -When you want full control over development or deployment, installing Plone from its packages is a good option. - - -(install-packages-system-requirements-label)= - -## System requirements - -Plone 6 has both hardware requirements and software pre-requisites. - - -(install-packages-hardware-requirements-label)= - -### Hardware requirements - -The hardware requirements below give a rough estimate of the minimum hardware setup needed for a Plone server. - -A single Plone installation is able to run many Plone sites. - -- Installation of the Plone backend and Classic UI frontend requires a minimum of 256 MB of RAM and 2GB of disk swap space. -- Installation of the Volto frontend requires a minimum of 2GB of RAM. -- After installation, running Plone requires a minimum of 256 MB RAM and 512 MB of disk swap space per Plone site. - 2 GB or more RAM per Plone site is recommended. -- Minimum 512 MB hard disk space is required. - 40 GB or more hard disk space is recommended. - - -````{warning} -{term}`Add-on` products and caching solutions may also increase RAM and disk swap space requirements. -To avoid RAM and disk swap limitations, we recommend either temporarily resizing your remote machine to accommodate the build, or build your images locally and upload them to an image store, such as [Docker Hub](https://hub.docker.com/) or [GitHub Packages](https://github.com/features/packages). -```{seealso} -[How much RAM is required to build a Volto front end?](https://community.plone.org/t/how-much-ram-is-required-to-build-a-volto-front-end/17949) and [Dealing with heap exhaustion while building Volto 17 on limited-RAM host](https://community.plone.org/t/dealing-with-heap-exhaustion-while-building-volto-17-on-limited-ram-host/18078). -``` -```` - - -(install-packages-prerequisites-label)= - -### Pre-requisites for installation - -```{include} ../volto/contributing/install-operating-system.md -``` - -- Python {SUPPORTED_PYTHON_VERSIONS} -- {term}`pipx` -- {term}`nvm` -- {term}`Node.js` LTS 20.x -- {term}`Yeoman` -- {term}`Yarn` -- {term}`GNU make` -- {term}`Docker` - - -(install-prerequisites-python-label)= - -#### Python - -Installing Python is beyond the scope of this documentation. -However, it is recommended to use a Python version manager, {term}`pyenv` that allows you to install multiple versions of Python on your development environment without destroying your system's Python. -Plone requires Python version {SUPPORTED_PYTHON_VERSIONS}. - - -(install-prerequisites-pipx-label)= - -#### pipx - -Install {term}`pipx`. - -```shell -pip install pipx -``` - - -(install-prerequisites-nvm-label)= - -#### nvm - -The following terminal session commands use `bash` for the shell. -Adapt them for your flavor of shell. - -```{seealso} -See the [`nvm` install and update script documentation](https://github.com/nvm-sh/nvm#install--update-script). -For the `fish` shell, see [`nvm.fish`](https://github.com/jorgebucaran/nvm.fish). -``` - -1. Create your shell profile, if it does not exist. - - ```shell - touch ~/.bash_profile - ``` - -2. Download and run the `nvm` install and update script, and pipe it into `bash`. - - ```shell - curl -o- https://raw.githubusercontent.com/creationix/nvm/v{NVM_VERSION}/install.sh | bash - ``` - -3. Source your profile. - Alternatively close the session and open a new one. - - ```shell - source ~/.bash_profile - ``` - -4. Verify that the `nvm` version is that which you just installed or updated: - - ```shell - nvm --version - ``` - - -(install-prerequisites-nodejs-label)= - -#### Node.js - -```{include} ../volto/contributing/install-nodejs.md -``` - - -(install-prerequisites-yeoman-label)= - -#### Yeoman - -Install {term}`Yeoman`. - -```shell -npm install -g yo -``` - - -(install-prerequisites-yarn-label)= - -#### Yarn 3 - -Install the latest Yarn 3 version (not the Classic 1.x one) using `npm`. - -1. Open a terminal and type: - - ```shell - npm install yarn@3 - ``` - -2. Verify that Yarn v3.x.x is installed and activated. - - ```shell - yarn -v - ``` - ```console - 3.2.3 - ``` - - If you do not see a version of Yarn 3, then try the following to set the active version. - - ```shell - yarn set version 3.x - ``` - - If the version doesn't change, you can try deleting the {file}`yarn.lock` file, setting the version, and installing again. - - ```shell - rm yarn.lock - yarn set version 3.x - yarn install - ``` - - -(install-prerequisites-make-label)= - -#### Make - -```{include} ../volto/contributing/install-make.md -``` - - -(install-prerequisites-docker-label)= - -#### Install Docker - -```{include} ../volto/contributing/install-docker.md -``` - - -(install-packages-install-label)= - -## Install Plone 6 - -We install Plone 6 with {term}`pipx`, {term}`Cookiecutter`, {term}`mxdev`, {term}`make`, and other developer tools. - -```{note} -We do not maintain documentation for installing Plone 6 or later with `buildout`. -For Plone 5, `buildout` was the preferred installation method. -You can read the [documentation of how to install Plone 5 with `buildout`](https://5.docs.plone.org/manage/installing/installation_minimal_buildout.html), and adapt it to your needs for Plone 6. -``` - -Create a new directory to hold your project, and make it your current directory. - -```shell -mkdir my_project -cd my_project -``` - -Issue the following command to install or update `cookiecutter`, then run it to create a Plone project skeleton using the Cookiecutter {term}`cookiecutter-plone-starter`. - -```shell -pipx run cookiecutter gh:collective/cookiecutter-plone-starter -``` - -You will be presented with a series of prompts. -You can accept the default values in square brackets (`[default-option]`) by hitting the {kbd}`Enter` key, or enter your preferred values. -For ease of documentation, we will use the default values. - -(avoid-plone-core-package-names)= - -```{important} -For {guilabel}`Project Slug`, you must not use any of the Plone core package names listed in [`constraints.txt`](https://dist.plone.org/release/6.0-latest/constraints.txt). -Note that pip normalizes these names, so `plone.volto` and `plone-volto` are the same package. -``` - -```console -% pipx run cookiecutter gh:collective/cookiecutter-plone-starter - - -Cookiecutter Plone Starter -================================================================================ - -Sanity checks --------------------------------------------------------------------------------- - [1/5] Python: ✓ - [2/5] Node: ✓ - [3/5] yo: ✓ - [4/5] Docker: ✓ - [5/5] git: ✓ - -Project details --------------------------------------------------------------------------------- - - [1/19] Project Title (Project Title): Plone Conference Website 2070 - [2/19] Project Description (A new project using Plone 6.): - [3/19] Project Slug (Used for repository id) (plone-conference-website-2070): - [4/19] Project URL (without protocol) (plone-conference-website-2070.example.com): - [5/19] Author (Plone Foundation): Elli - [6/19] Author E-mail (collective@plone.org): elli@plone.org - [7/19] Python Package Name (plone_conference_website_2070): - [8/19] Volto Addon Name (volto-plone-conference-website-2070): - [9/19] Choose a Python Test Framework - 1 - pytest - 2 - unittest - Choose from [1/2] (1): - [10/19] Plone Version (6.0.8): - [11/19] Should we use Volto Alpha Versions? (No): yes - [12/19] Volto Version (18.0.0-alpha.1): - [13/19] Volto Generator Version (8.0.0): - [14/19] Language - 1 - English - 2 - Deutsch - 3 - Español - 4 - Português (Brasil) - 5 - Nederlands - 6 - Suomi - Choose from [1/2/3/4/5/6] (1): - [15/19] GitHub Username or Organization (collective): ellizurigo - [16/19] Container Registry - 1 - GitHub Container Registry - 2 - Docker Hub - Choose from [1/2] (1): - [17/19] Should we setup a caching server? - 1 - Yes - 2 - No - Choose from [1/2] (1): 2 - [18/19] Add Ansible playbooks? - 1 - Yes - 2 - No - Choose from [1/2] (1): - [19/19] Add GitHub Action to Deploy this project? - 1 - Yes - 2 - No - Choose from [1/2] (1): - -Plone Conference Website 2070 generation --------------------------------------------------------------------------------- - -Summary: - - Plone version: 6.0.8 - - Volto version: 18.0.0-alpha.1 - - Volto Generator version: 8.0.0 - - Output folder: /Users/katjasuss/Desktop/_temp/scratch_cookiecutter_plone/plone-conference-website-2070 - -Frontend codebase: - - Installing required npm packages - - Generate frontend application with @plone/volto 18.0.0-alpha.1 - -Backend codebase - - Remove folder src/plone_conference_website_2070/src/plone_conference_website_2070/tests not used by pytest - - Format generated code in the backend - -================================================================================ - -Project "Plone Conference Website 2070" was generated --------------------------------------------------------------------------------- -Now, code it, create a git repository, push to your organization. - -Sorry for the convenience, -The Plone Community. - -================================================================================ -``` - -Change to your project directory {file}`plone-conference-website-2070`. - -```shell -cd plone-conference-website-2070 -``` - -Next you switch to using `make`. -To see all available commands and their descriptions, enter the following command. - -```shell -make help -``` - -To install both the Plone backend and frontend, use the following command. - -```shell -make install -``` - -This will take a few minutes. -☕️ -First the backend, then the frontend will be installed. - -When the process completes successfully, it will exit with no message. - -````{note} -If you used a Plone core package name, then `make install` will return an error message such as the following. - -```console -ERROR: Cannot install plone-volto 1.0.0a1 (from /home/username/projects/volto/plone-volto/backend/src/plone_volto) because these package versions have conflicting dependencies. - -The conflict is caused by: - The user requested plone-volto 1.0.0a1 (from /home/username/projects/volto/plone-volto/backend/src/plone_volto) - The user requested (constraint) plone-volto==4.2.0 - -To fix this you could try to: -1. loosen the range of package versions you've specified -2. remove package versions to allow pip attempt to solve the dependency conflict - -ERROR: ResolutionImpossible: for help visit -make[2]: *** [Makefile:112: build-dev] Error 1 -make[2]: Leaving directory '/home/username/projects/volto/plone-volto/backend' -make[1]: *** [Makefile:46: install-backend] Error 2 -make[1]: Leaving directory '/home/username/projects/volto/plone-volto' -``` - -You must delete your project, {ref}`follow the important note `, and run the cookiecutter again. -```` - - -(install-packages-start-plone-label)= - -## Start Plone - -Plone 6 has two servers: one for the frontend, and one for the backend. -As such, we need to maintain two active shell sessions, one for each server, to start your Plone site. - - -(install-packages-start-plone-backend-label)= - -### Start Plone backend - -In the currently open session, issue the following command. - -```shell -make start-backend -``` - -The Plone backend server starts up and emits messages to the console. - -```console -2022-09-24 01:30:17,799 WARNING [ZODB.FileStorage:411][MainThread] Ignoring index for //my_project/project-title/backend/instance/var/filestorage/Data.fs -2022-09-24 01:30:19,639 INFO [chameleon.config:38][MainThread] directory cache: //my_project/project-title/backend/instance/var/cache. -2022-09-24 01:30:23,680 INFO [plone.volto:22][MainThread] Aliasing collective.folderish classes to plone.volto classes. -2022-09-24 01:30:24,935 INFO [Zope:42][MainThread] Ready to handle requests -Starting server in PID 92714. -2022-09-24 01:30:24,940 INFO [waitress:486][MainThread] Serving on http://[::1]:8080 -2022-09-24 01:30:24,940 INFO [waitress:486][MainThread] Serving on http://127.0.0.1:8080 -``` - - -(install-packages-start-plone-frontend-label)= - -### Start Plone frontend - -Create a second shell session in a new window. -Change your current working directory to {file}`project-title`. -Start the Plone frontend with the following command. - -```shell -make start-frontend -``` - -The Plone frontend server starts up and emits messages to the console. - -```console - WAIT Compiling... - - -✔ Client - Compiled successfully in 864.83ms - -✔ Server - Compiled successfully in 9.62s - -✅ Server-side HMR Enabled! -sswp> Handling Hot Module Reloading -Volto is running in SEAMLESS mode -Using internal proxy: http://localhost:3000 -> http://localhost:8080/Plone -🎭 Volto started at 0.0.0.0:3000 🚀 -``` - -Note that the Plone frontend uses an internal proxy server to connect with the Plone backend. -Open a browser at the following URL to visit your Plone site. - -http://localhost:3000 - -You will see a page similar to the following. - -```{image} /_static/plone-home-page.png -:alt: Plone home page -:class: figure -``` - -Select the {guilabel}`Login` link to visit the login form, and enter the following credentials. - -- {guilabel}`Login name`: `admin` -- {guilabel}`Password`: `admin` - -```{image} /_static/plone-login-page.png -:alt: Plone login page -:class: figure -``` - -Now you can edit content or configure your Plone site. - -You can stop the site with {kbd}`ctrl-c`. -Enjoy! +This page has been moved and renamed to {doc}`create-project`. From a2b15b281fee2947b0ad29ec47eb40278d21357b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 14 Jan 2024 01:34:04 -0800 Subject: [PATCH 080/810] Fix label --- docs/install/create-project.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install/create-project.md b/docs/install/create-project.md index df722c776..a23d271ad 100644 --- a/docs/install/create-project.md +++ b/docs/install/create-project.md @@ -8,7 +8,7 @@ myst: --- -(install-packages-1-label)= +(create-a-project-label)= # Create a project From eb376be85ed939394fe15ed7b707aae3533defb6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 14 Jan 2024 01:52:56 -0800 Subject: [PATCH 081/810] Pin vale to 2.30.0 until we can upgrade to v3.x --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index efd4380a5..63353856a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,4 +16,4 @@ sphinxcontrib.httpdomain # plone.restapi sphinxcontrib.httpexample # plone.restapi sphinxcontrib-video sphinxext-opengraph -vale +vale==2.30.0 From 464dcc822200c01a68e9ec88c8485f62ff2a0f65 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 14 Jan 2024 02:35:32 -0800 Subject: [PATCH 082/810] Remove duplicate contributing navigation - Fixes #1582 --- docs/contributing/index.md | 6 +++--- docs/contributing/plone-api.md | 12 ++++++++++++ docs/contributing/plone-restapi.md | 12 ++++++++++++ docs/contributing/volto.md | 12 ++++++++++++ 4 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 docs/contributing/plone-api.md create mode 100644 docs/contributing/plone-restapi.md create mode 100644 docs/contributing/volto.md diff --git a/docs/contributing/index.md b/docs/contributing/index.md index a0ad44213..98d049600 100644 --- a/docs/contributing/index.md +++ b/docs/contributing/index.md @@ -181,8 +181,8 @@ hidden: true first-time documentation/index -../plone.api/contribute/index -../plone.restapi/docs/source/contributing/index -../volto/contributing/index +plone-api +plone-restapi +volto github-administration ``` diff --git a/docs/contributing/plone-api.md b/docs/contributing/plone-api.md new file mode 100644 index 000000000..f567f0a6c --- /dev/null +++ b/docs/contributing/plone-api.md @@ -0,0 +1,12 @@ +--- +myst: + html_meta: + "description": "How to contribute to plone.api" + "property=og:description": "How to contribute to plone.api" + "property=og:title": "Contributing to plone.api" + "keywords": "Plone, API, development, contribute" +--- + +# Contributing to `plone.api` + +See {doc}`/plone.api/contribute/index` under {guilabel}`Backend > plone.api`. diff --git a/docs/contributing/plone-restapi.md b/docs/contributing/plone-restapi.md new file mode 100644 index 000000000..e53eca27c --- /dev/null +++ b/docs/contributing/plone-restapi.md @@ -0,0 +1,12 @@ +--- +myst: + html_meta: + "description": "Contributing to plone.restapi" + "property=og:description": "Contributing to plone.restapi" + "property=og:title": "Contributing to plone.restapi" + "keywords": "Plone, plone.restapi, REST, API, Contributing, documentation" +--- + +# Contributing to `plone.restapi` + +See {doc}`/plone.restapi/docs/source/contributing/index` under {guilabel}`REST API`. diff --git a/docs/contributing/volto.md b/docs/contributing/volto.md new file mode 100644 index 000000000..2b3b8777c --- /dev/null +++ b/docs/contributing/volto.md @@ -0,0 +1,12 @@ +--- +myst: + html_meta: + "description": "How to contribute to Volto, the frontend for Plone." + "property=og:description": "How to contribute to Volto, the frontend for Plone." + "property=og:title": "How to contribute to Volto, the frontend for Plone." + "keywords": "Plone, Volto, contributing, developer, guidelines" +--- + +# Contributing to Volto + +See {doc}`/volto/contributing/index` under {guilabel}`Frontend`. From a2c12c65b80ca77f578595bd23f6c60ef37e6c59 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 15 Jan 2024 06:08:31 -0800 Subject: [PATCH 083/810] Use sphinx-reredirects instead of milestone --- docs/conf.py | 8 ++++++++ docs/install/install-from-packages.md | 15 --------------- requirements.txt | 1 + 3 files changed, 9 insertions(+), 15 deletions(-) delete mode 100644 docs/install/install-from-packages.md diff --git a/docs/conf.py b/docs/conf.py index 16efb32ea..26660fcd6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -49,6 +49,7 @@ "sphinx.ext.todo", "sphinx_copybutton", "sphinx_design", + "sphinx_reredirects", "sphinx_sitemap", "sphinxcontrib.httpdomain", # plone.restapi "sphinxcontrib.httpexample", # plone.restapi @@ -219,6 +220,13 @@ notfound_template = "404.html" +# -- sphinx-reredirects configuration ---------------------------------- +# https://documatt.com/sphinx-reredirects/usage.html +redirects = { + "install/install-from-packages": "/install/create-project.html", +} + + # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for diff --git a/docs/install/install-from-packages.md b/docs/install/install-from-packages.md deleted file mode 100644 index 4e2bf4b6a..000000000 --- a/docs/install/install-from-packages.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -orphan: true -myst: - html_meta: - "description": "How to install Plone 6 from its packages." - "property=og:description": "How to install Plone 6 from its packages." - "property=og:title": "Install Plone from its packages" - "keywords": "Plone, Plone 6, install, pip, packages, source, cookiecutter" ---- - -(install-packages-1-label)= - -# Install Plone from its packages - -This page has been moved and renamed to {doc}`create-project`. diff --git a/requirements.txt b/requirements.txt index 63353856a..639f4b484 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,6 +10,7 @@ sphinx-book-theme==0.3.3 # Temporary pin until we can sort out HTML refactoring sphinx-copybutton sphinx-design # Documentation only sphinx-notfound-page # Documentation only +sphinx-reredirects sphinx-sitemap sphinx-togglebutton sphinxcontrib.httpdomain # plone.restapi From 070ea528e971db53ff56d08b1ce7e4a5406bd5ff Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 15 Jan 2024 06:13:47 -0800 Subject: [PATCH 084/810] Add cross-references to install Plone for contributing versus creating a project --- docs/contributing/index.md | 2 ++ docs/install/create-project.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/docs/contributing/index.md b/docs/contributing/index.md index a0ad44213..007e60ba9 100644 --- a/docs/contributing/index.md +++ b/docs/contributing/index.md @@ -13,6 +13,8 @@ myst: This part of the documentation describes how to contribute to Plone, including all its projects and repositories under the Plone GitHub organization. +If instead you want to create a web application project using Plone, see {doc}`/install/create-project`. + To contribute to any project in Plone, you must follow the policies of the [Plone Foundation](https://plone.org/foundation), [Plone GitHub organization](https://github.com/plone/) and the specific project. This chapter covers policies that apply to all Plone projects. diff --git a/docs/install/create-project.md b/docs/install/create-project.md index a23d271ad..a3ead1073 100644 --- a/docs/install/create-project.md +++ b/docs/install/create-project.md @@ -14,6 +14,8 @@ myst: This chapter describes how you can create a web application project using Plone, with full control over development and deployment. +If instead you want to contribute to a Plone package, see {doc}`/contributing/index`. + (install-packages-system-requirements-label)= From 629e66a422deb00c5e86a94612ab7d84caacc345 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 15 Jan 2024 06:32:28 -0800 Subject: [PATCH 085/810] Change voice in heading --- docs/install/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install/index.md b/docs/install/index.md index c938c0e36..2cdb8af20 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -26,7 +26,7 @@ Choose a version to demo. (install-index-getting-started-label)= -## Getting started +## Get started Choose an option to get started with Plone. If you are following a [Plone training](https://training.plone.org/), it should specify which option to choose. From 1d80cc097884566431f140cd534359955bd0eaa5 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 15 Jan 2024 06:59:47 -0800 Subject: [PATCH 086/810] Add sphinx_reredirects --- docs/conf.py | 10 ++++++++++ requirements.txt | 1 + 2 files changed, 11 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index 16efb32ea..d489e27ea 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -49,6 +49,7 @@ "sphinx.ext.todo", "sphinx_copybutton", "sphinx_design", + "sphinx_reredirects", "sphinx_sitemap", "sphinxcontrib.httpdomain", # plone.restapi "sphinxcontrib.httpexample", # plone.restapi @@ -219,6 +220,15 @@ notfound_template = "404.html" +# -- sphinx-reredirects configuration ---------------------------------- +# https://documatt.com/sphinx-reredirects/usage.html +redirects = { + "contributing/plone-api": "/plone.api/contribute/index.html", + "contributing/plone-restapi": "/plone.restapi/docs/source/contributing/index.html", + "contributing/volto": "/volto/contributing/index.html", +} + + # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for diff --git a/requirements.txt b/requirements.txt index efd4380a5..4431b5276 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,6 +10,7 @@ sphinx-book-theme==0.3.3 # Temporary pin until we can sort out HTML refactoring sphinx-copybutton sphinx-design # Documentation only sphinx-notfound-page # Documentation only +sphinx-reredirects sphinx-sitemap sphinx-togglebutton sphinxcontrib.httpdomain # plone.restapi From 2731fe3f49b0f7c759f573413030a818a6c008bf Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 15 Jan 2024 13:26:21 -0800 Subject: [PATCH 087/810] Temporarily pin sphinxcontrib-*help to get through build and deploy, due to recent Sphinx upgrade --- requirements.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/requirements.txt b/requirements.txt index 639f4b484..1cbcdb3e3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,6 +15,11 @@ sphinx-sitemap sphinx-togglebutton sphinxcontrib.httpdomain # plone.restapi sphinxcontrib.httpexample # plone.restapi +sphinxcontrib-applehelp==1.0.4 # https://github.com/plone/documentation/issues/1604 +sphinxcontrib-devhelp==1.0.2 # https://github.com/plone/documentation/issues/1604 +sphinxcontrib-htmlhelp==2.0.1 # https://github.com/plone/documentation/issues/1604 +sphinxcontrib-qthelp==1.0.3 # https://github.com/plone/documentation/issues/1604 +sphinxcontrib-serializinghtml==1.1.5 # https://github.com/plone/documentation/issues/1604 sphinxcontrib-video sphinxext-opengraph vale==2.30.0 From af4be1474391f378881be5c8e97711202a9afe0b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 16 Jan 2024 05:08:14 -0800 Subject: [PATCH 088/810] Update tips submodules/plone.restapi submodules/plone.restapi --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 16325f20b..799f5acd0 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 16325f20b927f28ff03762687862dcaea9944da5 +Subproject commit 799f5acd09687c837436fa0c19d1612e41089c36 diff --git a/submodules/volto b/submodules/volto index 0fcacc2a9..3d967f903 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 0fcacc2a937002079d3e1bbf7be7eccf4e453468 +Subproject commit 3d967f90366f79cf73a8cd2e845604fccb11773c From fdb340d34ce9eac3bd9154b1a79664ab93edf213 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 16 Jan 2024 13:02:21 -0800 Subject: [PATCH 089/810] Use corepack to install yarn --- docs/install/create-project.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/install/create-project.md b/docs/install/create-project.md index a3ead1073..57dc753ad 100644 --- a/docs/install/create-project.md +++ b/docs/install/create-project.md @@ -147,35 +147,34 @@ npm install -g yo #### Yarn 3 -Install the latest Yarn 3 version (not the Classic 1.x one) using `npm`. +Install the latest Yarn 3 version (not the Classic 1.x one). 1. Open a terminal and type: ```shell - npm install yarn@3 + corepack enable ``` 2. Verify that Yarn v3.x.x is installed and activated. ```shell + yarn set version 3.x yarn -v ``` ```console 3.2.3 ``` - - If you do not see a version of Yarn 3, then try the following to set the active version. - - ```shell - yarn set version 3.x - ``` - If the version doesn't change, you can try deleting the {file}`yarn.lock` file, setting the version, and installing again. + If you see a version that is not v3.x.x, you can try deleting the {file}`yarn.lock` file, and installing again. ```shell rm yarn.lock + corepack enable yarn set version 3.x - yarn install + yarn -v + ``` + ```console + 3.2.3 ``` From 5f305b55f39d3264ae9c7a111d6909021ef06604 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 17 Jan 2024 13:17:31 -0800 Subject: [PATCH 090/810] Clarify the Plone Contributor Agreement process We get too many impatient newcomers who don't read the text beneath the button. --- docs/contributing/index.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/contributing/index.md b/docs/contributing/index.md index cccde61d6..6c4305ac6 100644 --- a/docs/contributing/index.md +++ b/docs/contributing/index.md @@ -30,15 +30,19 @@ Plone uses the [GNU General Public License, version 2](https://github.com/plone/ A few other projects use the [modified BSD license](https://opensource.org/license/bsd-3-clause/), [MIT License](https://opensource.org/license/mit/), or [Creative Commons Attribution-ShareAlike 4.0 International license](https://creativecommons.org/licenses/by-sa/4.0/). You grant permission by signing and returning the Plone Contributor Agreement. +A volunteer member of the Plone Foundation will review your signed agreement. + +If accepted, your GitHub account will be added to a team in the Plone GitHub organization with appropriate access, and you will simultaneously receive an email notification from GitHub. + +Allow up to one week for processing. +Contact the Plone Foundation by its email address for further information, including the status of your request. + ```{button-link} https://plone.org/foundation/contributors-agreement :color: primary Sign the Plone Contributor Agreement ``` -After a member of the Plone Foundation reviews and accepts your signed agreement, your GitHub account will be added to a team in the Plone GitHub organization with appropriate access. -This process may take a few business days. - ```{seealso} - [Plone License FAQ](https://plone.org/foundation/copyright-licensing-logo/license-faq) - [Plone Framework Components Relicensing Policy, Framework Components Available Under a BSD License](https://plone.org/foundation/about/materials/foundation-resolutions/plone-framework-components-relicensing-policy#3b050ad2-361a-46de-b5c6-9b90f8947eb7) From 2a07a733a2a63d47e892787daafb974cc3f81d10 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 17 Jan 2024 23:05:59 -0800 Subject: [PATCH 091/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 3d967f903..ee11dbf9a 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 3d967f90366f79cf73a8cd2e845604fccb11773c +Subproject commit ee11dbf9af7c466707803cd74e06f68423d82f44 From 683e1d904a9b0df940f67564eb066a8a9158998c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 19 Jan 2024 04:35:09 -0800 Subject: [PATCH 092/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index ee11dbf9a..30bfda317 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit ee11dbf9af7c466707803cd74e06f68423d82f44 +Subproject commit 30bfda317829784494eb24f6bbb5482e662e8dd4 From 7939382d129ba17b21eb7156d4390a8f428db01d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 20 Jan 2024 11:32:23 -0800 Subject: [PATCH 093/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 30bfda317..3259626ea 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 30bfda317829784494eb24f6bbb5482e662e8dd4 +Subproject commit 3259626ea2c08bf954899b6ec42a388c016e66ca From cd0bf7f0750d18676a6f88a00d9239a2b2fca708 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 20 Jan 2024 22:05:16 -0800 Subject: [PATCH 094/810] Improve how to set up and build the documentation for Windows users --- docs/contributing/documentation/index.md | 4 ++++ .../contributing/documentation/setup-build.md | 22 +++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/docs/contributing/documentation/index.md b/docs/contributing/documentation/index.md index dec4a4246..851ea7de3 100644 --- a/docs/contributing/documentation/index.md +++ b/docs/contributing/documentation/index.md @@ -15,6 +15,10 @@ This document describes how to contribute to Plone Documentation. Contributions to the Plone Documentation are welcome. +```{seealso} +To set up and build the documentation locally, see {doc}`setup-build`. +``` + (contributing-permission-to-publish-label)= diff --git a/docs/contributing/documentation/setup-build.md b/docs/contributing/documentation/setup-build.md index 3e56b0318..e39d3e728 100644 --- a/docs/contributing/documentation/setup-build.md +++ b/docs/contributing/documentation/setup-build.md @@ -11,7 +11,7 @@ myst: # Building and checking the quality of documentation -This document covers how to build the Plone Documentation and check it for quality. +This document covers how to set up and build the Plone Documentation and check it for quality. (setup-build-installation-label)= @@ -20,14 +20,28 @@ This document covers how to build the Plone Documentation and check it for quali Installation of Plone 6 Documentation includes pre-requisites and the repository itself. +```{include} ../../volto/contributing/install-operating-system.md +``` +- {ref}`setup-build-installation-python-label` {SUPPORTED_PYTHON_VERSIONS} +- {ref}`setup-build-installation-gnu-make-label` +- {ref}`setup-build-installation-graphviz-label` + (setup-build-installation-python-label)= ### Python -Python 3.8 or later is required. -A more recent Python is preferred. -Use your system's package manager or [pyenv](https://github.com/pyenv/pyenv) to install an appropriate version of Python. +Installing Python is beyond the scope of this documentation. +However, it is recommended to use a Python version manager, {term}`pyenv` that allows you to install multiple versions of Python on your development environment without destroying your system's Python. +Plone requires Python version {SUPPORTED_PYTHON_VERSIONS}. + + +(setup-build-installation-gnu-make-label)= + +### GNU make + +```{include} ../../volto/contributing/install-make.md +``` (setup-build-installation-graphviz-label)= From 9db0fe9ea76acc2b2e9a7fdf2fd5308c096a3bc8 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 21 Jan 2024 00:24:12 -0800 Subject: [PATCH 095/810] Add glossary terms Guillotina and Nick --- docs/glossary.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/glossary.md b/docs/glossary.md index 7260b4e87..2c361e5a6 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -674,4 +674,10 @@ Windows Subsystem for Linux pnpm [pnpm](https://pnpm.io/) is a fast, disk space efficient package manager. + +Guillotina + [Guillotina](https://guillotina.io/) is a full-stack data framework built on [AsyncIO](https://docs.python.org/3/library/asyncio.html). + +Nick + [Nick](https://nickcms.org/) is a headless content management system {term}`CMS` built with {term}`Node.js`. ``` From 19ac175affad03c5332266abeabfe659ed5fdeb1 Mon Sep 17 00:00:00 2001 From: David Ichim Date: Sun, 21 Jan 2024 12:10:08 +0200 Subject: [PATCH 096/810] Added links to issue labels in first-time.md --- docs/contributing/first-time.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/contributing/first-time.md b/docs/contributing/first-time.md index b5ae9daf2..c41594a63 100644 --- a/docs/contributing/first-time.md +++ b/docs/contributing/first-time.md @@ -128,9 +128,9 @@ Please don't be "that person". 1. **Find issues that you want to work on.** You can filter GitHub issues by labels. - Working on documentation or on issues labeled with either `33 needs: docs` or `41 lvl: easy` are the two best ways for first-time contributors to contribute. + Working on documentation or on issues labeled with either [`33 needs: docs`](https://github.com/search?q=user%3Aplone+label%3A%2233+needs%3A+docs%22&type=issues&ref=advsearch) or [`41 lvl: easy`](https://github.com/search?q=user%3Aplone+label%3A%2241+lvl%3A+easy%22&type=Issues&ref=advsearch) are the two best ways for first-time contributors to contribute. This is because first-timers have a fresh perspective that might be overlooked by old-timers. - Issues labeled `42 lvl: moderate`, `43 lvl: complex`, or `03 type: feature (plip)` are not suitable for first-timers because of their complexity. + Issues labeled [`42 lvl: moderate`](https://github.com/search?q=user%3Aplone+label%3A%2242+lvl%3A+moderate%22&type=issues&ref=advsearch), [`43 lvl: complex`](https://github.com/search?q=user%3Aplone+label%3A%2243+lvl%3A+complex%22&type=issues&ref=advsearch), or [`03 type: feature (plip)`](https://github.com/search?q=user%3Aplone+label%3A%2203+type%3A+feature+%28plip%29%22&type=issues&ref=advsearch) are not suitable for first-timers because of their complexity. Issues with these labels may take weeks to complete. 1. **Discuss whether you should perform any work.** First see {ref}`Avoid duplicate effort `. From c4c86e760ddf143a830ffe261781caaed9220f75 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 21 Jan 2024 02:38:55 -0800 Subject: [PATCH 097/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 3259626ea..0d80d0ec8 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 3259626ea2c08bf954899b6ec42a388c016e66ca +Subproject commit 0d80d0ec8af4c553acb9f2bff9f4496ae20446ae From 5a731e0beb572b97c1d0fd6b37ec5cbaaf4faf2d Mon Sep 17 00:00:00 2001 From: David Ichim Date: Sun, 21 Jan 2024 17:20:44 +0200 Subject: [PATCH 098/810] Keep links only to the issues that we want newbies to attempt to work on --- docs/contributing/first-time.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/first-time.md b/docs/contributing/first-time.md index c41594a63..3ea7f9670 100644 --- a/docs/contributing/first-time.md +++ b/docs/contributing/first-time.md @@ -130,7 +130,7 @@ Please don't be "that person". You can filter GitHub issues by labels. Working on documentation or on issues labeled with either [`33 needs: docs`](https://github.com/search?q=user%3Aplone+label%3A%2233+needs%3A+docs%22&type=issues&ref=advsearch) or [`41 lvl: easy`](https://github.com/search?q=user%3Aplone+label%3A%2241+lvl%3A+easy%22&type=Issues&ref=advsearch) are the two best ways for first-time contributors to contribute. This is because first-timers have a fresh perspective that might be overlooked by old-timers. - Issues labeled [`42 lvl: moderate`](https://github.com/search?q=user%3Aplone+label%3A%2242+lvl%3A+moderate%22&type=issues&ref=advsearch), [`43 lvl: complex`](https://github.com/search?q=user%3Aplone+label%3A%2243+lvl%3A+complex%22&type=issues&ref=advsearch), or [`03 type: feature (plip)`](https://github.com/search?q=user%3Aplone+label%3A%2203+type%3A+feature+%28plip%29%22&type=issues&ref=advsearch) are not suitable for first-timers because of their complexity. + Issues labeled `42 lvl: moderate`, `43 lvl: complex`, or `03 type: feature (plip)` are not suitable for first-timers because of their complexity. Issues with these labels may take weeks to complete. 1. **Discuss whether you should perform any work.** First see {ref}`Avoid duplicate effort `. From b6c09c62030d7c5b377bf8741a16805903d256d6 Mon Sep 17 00:00:00 2001 From: David Ichim Date: Sun, 21 Jan 2024 17:32:57 +0200 Subject: [PATCH 099/810] Bring back full stop otherwise the phrase is too long --- docs/contributing/first-time.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/contributing/first-time.md b/docs/contributing/first-time.md index 3ea7f9670..a0a66b237 100644 --- a/docs/contributing/first-time.md +++ b/docs/contributing/first-time.md @@ -129,6 +129,7 @@ Please don't be "that person". 1. **Find issues that you want to work on.** You can filter GitHub issues by labels. Working on documentation or on issues labeled with either [`33 needs: docs`](https://github.com/search?q=user%3Aplone+label%3A%2233+needs%3A+docs%22&type=issues&ref=advsearch) or [`41 lvl: easy`](https://github.com/search?q=user%3Aplone+label%3A%2241+lvl%3A+easy%22&type=Issues&ref=advsearch) are the two best ways for first-time contributors to contribute. + This is because first-timers have a fresh perspective that might be overlooked by old-timers. Issues labeled `42 lvl: moderate`, `43 lvl: complex`, or `03 type: feature (plip)` are not suitable for first-timers because of their complexity. Issues with these labels may take weeks to complete. From 9de464631bb6d9cc3e5a98610307c868a24d5661 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 21 Jan 2024 12:09:59 -0800 Subject: [PATCH 100/810] Move sentence to previous paragraph --- docs/contributing/first-time.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/first-time.md b/docs/contributing/first-time.md index a0a66b237..ce5f3c070 100644 --- a/docs/contributing/first-time.md +++ b/docs/contributing/first-time.md @@ -129,8 +129,8 @@ Please don't be "that person". 1. **Find issues that you want to work on.** You can filter GitHub issues by labels. Working on documentation or on issues labeled with either [`33 needs: docs`](https://github.com/search?q=user%3Aplone+label%3A%2233+needs%3A+docs%22&type=issues&ref=advsearch) or [`41 lvl: easy`](https://github.com/search?q=user%3Aplone+label%3A%2241+lvl%3A+easy%22&type=Issues&ref=advsearch) are the two best ways for first-time contributors to contribute. - This is because first-timers have a fresh perspective that might be overlooked by old-timers. + Issues labeled `42 lvl: moderate`, `43 lvl: complex`, or `03 type: feature (plip)` are not suitable for first-timers because of their complexity. Issues with these labels may take weeks to complete. 1. **Discuss whether you should perform any work.** From 9a3d73d1e334f0e6a9723fa625b9b366ad3b3762 Mon Sep 17 00:00:00 2001 From: tanya_ Date: Tue, 23 Jan 2024 23:15:44 +0530 Subject: [PATCH 101/810] Fixed a small typo error --- .github/ISSUE_TEMPLATE/new-issue-form.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/new-issue-form.yml b/.github/ISSUE_TEMPLATE/new-issue-form.yml index ec0be7e16..92f61cdc3 100644 --- a/.github/ISSUE_TEMPLATE/new-issue-form.yml +++ b/.github/ISSUE_TEMPLATE/new-issue-form.yml @@ -17,6 +17,6 @@ body: id: description attributes: label: Description - description: Include include screenshots and any other helpful information. + description: Include screenshots and any other helpful information. validations: required: true From b42d035711c74304e8ce52ffe60741b61465e115 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 24 Jan 2024 02:29:45 -0800 Subject: [PATCH 102/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 0d80d0ec8..bc5345634 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 0d80d0ec8af4c553acb9f2bff9f4496ae20446ae +Subproject commit bc5345634c69fa37e264aa3a8d734521fa0bf955 From ad06798fd3d09ca391ceb21f110b01bd03a630a2 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 24 Jan 2024 03:00:43 -0800 Subject: [PATCH 103/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index bc5345634..8e3eced80 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit bc5345634c69fa37e264aa3a8d734521fa0bf955 +Subproject commit 8e3eced80d5c517ee54fa55dad53c7bdb0133853 From d7b0e10c7de579ddb22a14b01fe961af481c232d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 26 Jan 2024 01:03:44 -0800 Subject: [PATCH 104/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 799f5acd0..af1d2235e 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 799f5acd09687c837436fa0c19d1612e41089c36 +Subproject commit af1d2235ead9762e5274eb69a710336918d9085a diff --git a/submodules/volto b/submodules/volto index 8e3eced80..7e731a70b 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 8e3eced80d5c517ee54fa55dad53c7bdb0133853 +Subproject commit 7e731a70b19411b862458713e180394c0c37a715 From 4662aace4e4e1b3c2ba81f49b592d44a3eddc924 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 26 Jan 2024 02:32:28 -0800 Subject: [PATCH 105/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 7e731a70b..4bb07b9b7 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 7e731a70b19411b862458713e180394c0c37a715 +Subproject commit 4bb07b9b7392879e7aed72b871f73936f2187f5c From d84c8ba1635740a0227d6915b45745608fbbcb78 Mon Sep 17 00:00:00 2001 From: vivek kumar Date: Fri, 26 Jan 2024 19:37:08 +0530 Subject: [PATCH 106/810] Fix: Quote paths in SPHINXBUILD and SPHINXAUTOBUILD variables --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 9f58ea24d..a0f2d9cda 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,8 @@ SPHINXOPTS ?= PAPER ?= # Internal variables. -SPHINXBUILD = $(realpath bin/sphinx-build) -SPHINXAUTOBUILD = $(realpath bin/sphinx-autobuild) +SPHINXBUILD = "$(realpath bin/sphinx-build)" +SPHINXAUTOBUILD = "$(realpath bin/sphinx-autobuild)" DOCS_DIR = ./docs/ BUILDDIR = ../_build PAPEROPT_a4 = -D latex_paper_size=a4 From 5137797436f1d2ca6a0b55f0ac7ed0a66d6694d6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 29 Jan 2024 15:13:01 -0800 Subject: [PATCH 107/810] Create a new section, For students and learners - promote read and followed guidance - warn against quick contributors --- docs/contributing/first-time.md | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/docs/contributing/first-time.md b/docs/contributing/first-time.md index ce5f3c070..25ec6f892 100644 --- a/docs/contributing/first-time.md +++ b/docs/contributing/first-time.md @@ -13,17 +13,38 @@ myst: This chapter provides guidance to first-time contributors to Plone and all its projects and repositories under the Plone GitHub organization. + +(for-students-and-learners)= + +## For students and learners + +```{important} +**We do not offer training, guidance, or mentoring to students or learners on GitHub.** +Don't ask for it. +The Plone organization may delete comments, lock conversations, or block GitHub users who ignore this. +``` + +If you are a student or learner of Plone, you probably are not a contributor. +See the next section, {ref}`expectations-of-first-time-contributors`, to determine whether you are in fact a contributor. + +For free support, training, guidance, or mentoring, you should work through some trainings, use the [Plone Community Forum](https://community.plone.org/), participate in an [event](https://plone.org/news-and-events/events), and **not use GitHub**. + + +(expectations-of-first-time-contributors)= + +## Expectations of first-time contributors + As a first-time contributor to Plone on GitHub, we expect that you have: - {doc}`installed Plone <../install/index>` on your development machine - worked on a Plone project, even if it is just for fun +- read and followed the guidance on the pages under {doc}`/contributing/index` both for Plone in general and for the specific project to which you want to contribute, as well as all the guidance on this page - worked through some trainings, such as the recommended: - {doc}`training:mastering-plone/index` - {doc}`training:voltohandson/index` - {doc}`training:voltoaddons/index` - {doc}`training:volto_customization/index` - {doc}`training:plone-deployment/index` -- read the chapters of {doc}`/index` relevant to your contribution - a sincere interest to contribute to Plone and become an ongoing contributing member of our organization - a GitHub account - basic knowledge of using git and GitHub @@ -34,9 +55,8 @@ As a first-time contributor on GitHub, your expectations should align with ours, Plone has a very large and complex code base. It takes a significant amount of time to learn how to develop Plone. -As members of the Plone organization, we volunteer our free time to develop Plone on GitHub. -We do not offer support, training, or mentoring on GitHub. -For free support, training, or mentoring, you should use the [Plone Community Forum](https://community.plone.org/) or participate in an [event](https://plone.org/news-and-events/events), and not use GitHub. +If you want to quickly pad your résumé, satisfy a "contribute to open source" school assignment, or get recognition for participating in events such as Hacktoberfest, then Plone may not be the open source software project for you. +Such motivation behind these contributions usually results in poor quality breaking code, and drains limited volunteer time to triage. ``` From eb96f31822dcf90325a48a609a70a681bad18212 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 29 Jan 2024 15:26:34 -0800 Subject: [PATCH 108/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 4bb07b9b7..4ad70c684 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 4bb07b9b7392879e7aed72b871f73936f2187f5c +Subproject commit 4ad70c684253607788af10768b68471da8859676 From 3503cbb3d627c46a0b937e4948e8a4494ddabc91 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 1 Feb 2024 02:43:53 -0800 Subject: [PATCH 109/810] Use a custom robots.txt and set headers to block indexing on Netlify preview builds --- Makefile | 1 + docs/netlify_robots.txt | 3 +++ netlify.toml | 4 ++++ 3 files changed, 8 insertions(+) create mode 100644 docs/netlify_robots.txt diff --git a/Makefile b/Makefile index a0f2d9cda..3bfeb4e8d 100644 --- a/Makefile +++ b/Makefile @@ -236,6 +236,7 @@ netlify: ln -s ../submodules/plone.restapi ./docs/plone.restapi ln -s ../submodules/plone.api/docs ./docs/plone.api cd $(DOCS_DIR) && sphinx-build -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + cp netlify_robots.txt $(BUILDDIR)/html/robots.txt .PHONY: storybook storybook: diff --git a/docs/netlify_robots.txt b/docs/netlify_robots.txt new file mode 100644 index 000000000..0a875a487 --- /dev/null +++ b/docs/netlify_robots.txt @@ -0,0 +1,3 @@ +# Disallow all user agents from indexing pages and links in the site on Netlify only. +User-agent: * +Disallow: / diff --git a/netlify.toml b/netlify.toml index 7661f9b40..ebdd9ef6e 100644 --- a/netlify.toml +++ b/netlify.toml @@ -1,2 +1,6 @@ [build.environment] PYTHON_VERSION = "3.8" +[[headers]] + for = "/*" + [[headers.values]] + X-Robots-Tag = "none" From fb5bc1a354371d55ae8eda04fd50c35ea9113105 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 1 Feb 2024 02:51:28 -0800 Subject: [PATCH 110/810] Try fiddling with the path --- Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3bfeb4e8d..dd72fec8c 100644 --- a/Makefile +++ b/Makefile @@ -235,8 +235,7 @@ netlify: ln -s ../submodules/volto/docs/source ./docs/volto ln -s ../submodules/plone.restapi ./docs/plone.restapi ln -s ../submodules/plone.api/docs ./docs/plone.api - cd $(DOCS_DIR) && sphinx-build -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - cp netlify_robots.txt $(BUILDDIR)/html/robots.txt + cd $(DOCS_DIR) && sphinx-build -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html && cp ./netlify_robots.txt $(BUILDDIR)/html/robots.txt .PHONY: storybook storybook: From ede0c106fbfcf0b96786b2b5865d0a91b38e84a4 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 1 Feb 2024 04:46:56 -0800 Subject: [PATCH 111/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 4ad70c684..ecc290e39 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 4ad70c684253607788af10768b68471da8859676 +Subproject commit ecc290e39f035fca08cf5f8d33dc74e986d0afef From b2fb144fd69c7dd09bbab828c7e2293cfb55fa84 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 2 Feb 2024 23:34:14 -0800 Subject: [PATCH 112/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index af1d2235e..a2ba813d5 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit af1d2235ead9762e5274eb69a710336918d9085a +Subproject commit a2ba813d56a7701e9e5b6de5fddf9e908b69a14c diff --git a/submodules/volto b/submodules/volto index ecc290e39..71decc8ae 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit ecc290e39f035fca08cf5f8d33dc74e986d0afef +Subproject commit 71decc8ae0d7c53c72733d07ffcff7e45ca9ed66 From 9c37a9341b26b58b0a921274ca712b8aa6a20df7 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 10 Feb 2024 14:12:06 -0800 Subject: [PATCH 113/810] Update tips submodules/plone.api submodules/plone.restapi submodules/volto --- submodules/plone.api | 2 +- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index 4a4c1c2a7..7205d49ac 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit 4a4c1c2a7c6d015ae34d2aa18cc5c09269bce565 +Subproject commit 7205d49ac14e79c70746bb9df369b9294df22510 diff --git a/submodules/plone.restapi b/submodules/plone.restapi index a2ba813d5..56d00c06b 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit a2ba813d56a7701e9e5b6de5fddf9e908b69a14c +Subproject commit 56d00c06bbf3c6463795588b5c617ac7244d05b5 diff --git a/submodules/volto b/submodules/volto index 71decc8ae..4421eede7 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 71decc8ae0d7c53c72733d07ffcff7e45ca9ed66 +Subproject commit 4421eede752553cf26a6084f3881059aaad80b53 From 7ec215a8608b66cfb81b4440234490cf2dfb9cd2 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 11 Feb 2024 02:36:37 -0800 Subject: [PATCH 114/810] Fix broken demo link --- docs/install/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install/index.md b/docs/install/index.md index 2cdb8af20..fbe83381b 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -21,7 +21,7 @@ In this part of the documentation, you can find how to {ref}`try Plone Date: Sun, 11 Feb 2024 03:19:45 -0800 Subject: [PATCH 115/810] Bump the linkcheck timeout to 10 seconds from 5. https://github.com/zopefoundation/z3c.form/tree/master/src/z3c/form/browser takes about 8 seconds to load. The longer timeout should allow it to pass going forward. --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 4d88c8ebd..bc0809ade 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -97,7 +97,7 @@ r"https://www.youtube.com/playlist", # volto, TODO remove after installing sphinxcontrib.youtube ] linkcheck_anchors = True -linkcheck_timeout = 5 +linkcheck_timeout = 10 linkcheck_retries = 1 # The suffix of source filenames. From 29ca7fa1c262a03b745bec991d6c3660dc5d65cd Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 11 Feb 2024 14:12:51 -0800 Subject: [PATCH 116/810] Clarify location change log entries in the Volto monorepo --- docs/contributing/index.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/contributing/index.md b/docs/contributing/index.md index 6c4305ac6..7dec72ed1 100644 --- a/docs/contributing/index.md +++ b/docs/contributing/index.md @@ -86,7 +86,10 @@ When a package is released with a new version, the release manager runs `towncri Because the log file is automatically generated, you should not edit it directly, except to make corrections, such as broken links. To create a change log entry or news item, create a file in the `news` directory, located in the root of the package. -Its format must be `###.type`, where `###` is the referenced GitHub issue or pull request number, `.` is the literal extension delimiter, and `type` is one of the following strings. +For Volto, its repository is in a monorepo structure, consisting of several packages in the `packages` folder. +Thus for Volto and its packages, change log entries should be created in `packages/PACKAGE_NAME/news/`, which is the root of the package. + +The change log entry's format must be `###.type`, where `###` is the referenced GitHub issue or pull request number, `.` is the literal extension delimiter, and `type` is one of the following strings. - `breaking` for breaking changes - `bugfix` for bug fixes From 88b5f27148eede4526d727c964560f5de0699e9c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 12 Feb 2024 22:04:31 -0800 Subject: [PATCH 117/810] Update tips submodules/plone.api submodules/plone.restapi submodules/volto --- submodules/plone.api | 2 +- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index 7205d49ac..44c900695 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit 7205d49ac14e79c70746bb9df369b9294df22510 +Subproject commit 44c900695a79e21d1bd1c452b9dadb385823a04d diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 56d00c06b..7833026a1 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 56d00c06bbf3c6463795588b5c617ac7244d05b5 +Subproject commit 7833026a16b0c9a4bfb7230dece8c531e9a02eff diff --git a/submodules/volto b/submodules/volto index 4421eede7..364232011 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 4421eede752553cf26a6084f3881059aaad80b53 +Subproject commit 364232011e71166881ea3d2b057dd361035b3038 From 6cb54cddfaee6499cdd1e054941af8bfbcdd15e8 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 13 Feb 2024 02:00:08 -0800 Subject: [PATCH 118/810] Update tips submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 364232011..3a071a857 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 364232011e71166881ea3d2b057dd361035b3038 +Subproject commit 3a071a8578aa131f31888ca18096b0d1ecf8224b From def90de65f961131a29e9965f385eaae4f8968ea Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Tue, 13 Feb 2024 17:14:39 +0100 Subject: [PATCH 119/810] improve docs for classicui-images: direction parameter --- docs/classic-ui/images.md | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/docs/classic-ui/images.md b/docs/classic-ui/images.md index fe41c130c..c86908688 100644 --- a/docs/classic-ui/images.md +++ b/docs/classic-ui/images.md @@ -237,17 +237,36 @@ image_scale = scaling_util.publishTraverse(context.REQUEST, groups[1]) ## Scaling `direction` -The default direction is `thumbnail`. +If an images is scaled the direction parameter can be used to control the scaling output. +Either width or height - or both - must be given too. -Other options are: +This is all about scaling for the display in a web browser. -* `down` -* `keep` -* `scale-crop-to-fill` -* `scale-crop-to-fit` -* `thumbnail` -* `up` +Three different scaling options are supported. +They correspond to the CSS background-size values (see [background-size documentation of mdn web docs](https://developer.mozilla.org/en-US/docs/Web/CSS/background-size)) +The default direction is `scale`. + +Possible options are: + +* `scale`: + Scales to the requested dimensions without cropping. + The resulting image may have a different size than requested. + This option requires both width and height to be specified. + Does not scale up. + + Deprecated spellings: `keep`, `thumbnail`. + +* `contain`: + Starts by scaling the relatively smallest dimension to the required size and crops the other dimension if needed. + + Deprecated spellings: `scale-crop-to-fit`, `down`. + +* `cover`: + Scales the relatively largest dimension up to the required size. + Despite the deprecated spelling, there is no cropping happening. + + Deprecated spellings: `scale-crop-to-fill`, `up`. (classic-ui-images-permissions-label)= From e41cb94ef3d80de78d78f0ddd323570554b95920 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 13 Feb 2024 14:42:59 -0800 Subject: [PATCH 120/810] Add writing reference for documentation authors --- docs/contributing/documentation/authors.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/contributing/documentation/authors.md b/docs/contributing/documentation/authors.md index 35a121c3f..38b71bd99 100644 --- a/docs/contributing/documentation/authors.md +++ b/docs/contributing/documentation/authors.md @@ -298,4 +298,5 @@ The Plone Documentation Team adopted additional guidelines. ## General documentation writing references - [Write the Docs - Documentation Guide](https://www.writethedocs.org/guide/) +- [Creating effective technical documentation](https://developer.mozilla.org/en-US/blog/technical-writing/), Dipika Bhattacharya, Technical Writer at Mozilla Developer Network - [A Guide to Em Dashes, En Dashes, and Hyphens](https://www.merriam-webster.com/grammar/em-dash-en-dash-how-to-use) From 4d2788d7a96535dcf8b8f09efa461411cb007a0c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 13 Feb 2024 23:20:56 -0800 Subject: [PATCH 121/810] Fix linkcheck --- docs/classic-ui/theming/barceloneta.md | 2 +- docs/conf.py | 2 ++ docs/install/manage-add-ons-packages.md | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/classic-ui/theming/barceloneta.md b/docs/classic-ui/theming/barceloneta.md index 977315a86..ea26643c3 100644 --- a/docs/classic-ui/theming/barceloneta.md +++ b/docs/classic-ui/theming/barceloneta.md @@ -25,7 +25,7 @@ To create an add-on package with a Plone Classic UI theme, you need to install t - [Python (>=3.8)](https://www.python.org/) - [plonecli](https://pypi.org/project/plonecli/) -Read more about how to install pre-requisites in {doc}`/install/install-from-packages`. +Read more about how to install pre-requisites in {doc}`/install/create-project`. (classic-ui-theming-barceloneta-create-a-classic-ui-theme-add-on-package-label)= diff --git a/docs/conf.py b/docs/conf.py index bc0809ade..7067a94ad 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -95,6 +95,8 @@ # Ignore unreliable sites r"https://web.archive.org/", # volto r"https://www.youtube.com/playlist", # volto, TODO remove after installing sphinxcontrib.youtube + r"https://chromewebstore.google.com/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi", # TODO retest with latest Sphinx when upgrading theme. chromewebstore recently changed its URL and has "too many redirects". + r"https://chromewebstore.google.com/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd", # TODO retest with latest Sphinx when upgrading theme. chromewebstore recently changed its URL and has "too many redirects". ] linkcheck_anchors = True linkcheck_timeout = 10 diff --git a/docs/install/manage-add-ons-packages.md b/docs/install/manage-add-ons-packages.md index 5a49254d1..2d1be7eed 100644 --- a/docs/install/manage-add-ons-packages.md +++ b/docs/install/manage-add-ons-packages.md @@ -12,7 +12,7 @@ myst: # Manage add-ons and packages -This chapter assumes you have previously {doc}`installed Plone from its packages `. +This chapter assumes you have previously followed {doc}`create-project`. In this section, we discuss details of the installation process so that you can customize your Plone installation. It also covers routine management tasks that a developer might perform. From f87437aa22c4255c72492b3618edb413cfd5cb4f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 14 Feb 2024 00:13:24 -0800 Subject: [PATCH 122/810] Reformat for MyST, fix grammar --- docs/classic-ui/images.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/classic-ui/images.md b/docs/classic-ui/images.md index c86908688..3aa7c4937 100644 --- a/docs/classic-ui/images.md +++ b/docs/classic-ui/images.md @@ -237,36 +237,36 @@ image_scale = scaling_util.publishTraverse(context.REQUEST, groups[1]) ## Scaling `direction` -If an images is scaled the direction parameter can be used to control the scaling output. -Either width or height - or both - must be given too. +Scaling is intended for the optimal display of images in a web browser. -This is all about scaling for the display in a web browser. +To scale an image, you can use the `direction` parameter to control the scaling output. +You must use either `width` or `height`, or both. Three different scaling options are supported. -They correspond to the CSS background-size values (see [background-size documentation of mdn web docs](https://developer.mozilla.org/en-US/docs/Web/CSS/background-size)) +They correspond to the CSS [`background-size`](https://developer.mozilla.org/en-US/docs/Web/CSS/background-size) values. -The default direction is `scale`. +The possible options for `direction` are listed below, where the default option is `scale`. -Possible options are: +`scale` +: This is the default option. + `scale` scales to the requested dimensions without cropping. + The resulting image may have a different size than requested. + This option requires both `width` and `height` to be specified. + It does not scale up. -* `scale`: - Scales to the requested dimensions without cropping. - The resulting image may have a different size than requested. - This option requires both width and height to be specified. - Does not scale up. + Deprecated spellings: `keep`, `thumbnail`. - Deprecated spellings: `keep`, `thumbnail`. +`contain` +: `contain` starts by scaling the image either to the smaller dimension when you give both `width` and `height`, or to the only given dimension, then crops to the other dimension if needed. -* `contain`: - Starts by scaling the relatively smallest dimension to the required size and crops the other dimension if needed. + Deprecated spellings: `scale-crop-to-fit`, `down`. - Deprecated spellings: `scale-crop-to-fit`, `down`. +`cover` +: `cover` scales the image either to the larger dimension when you give both `width` and `height`, or to the only given dimension, up to the size you specify. + Despite the deprecated spelling, it does not crop. -* `cover`: - Scales the relatively largest dimension up to the required size. - Despite the deprecated spelling, there is no cropping happening. + Deprecated spellings: `scale-crop-to-fill`, `up`. - Deprecated spellings: `scale-crop-to-fill`, `up`. (classic-ui-images-permissions-label)= From c1d7b6c6a5b5f667ada2c2741aa82413cb2065dc Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 14 Feb 2024 00:17:55 -0800 Subject: [PATCH 123/810] Update tips submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 3a071a857..d036535c6 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 3a071a8578aa131f31888ca18096b0d1ecf8224b +Subproject commit d036535c6350f2afbf3086e14f6eaf8628314161 From 468498f8cca61c6325a60e5fd31c7a42e763f5f0 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 14 Feb 2024 01:49:18 -0800 Subject: [PATCH 124/810] Rename spelling to option name --- docs/classic-ui/images.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/classic-ui/images.md b/docs/classic-ui/images.md index 3aa7c4937..21c97177f 100644 --- a/docs/classic-ui/images.md +++ b/docs/classic-ui/images.md @@ -254,18 +254,18 @@ The possible options for `direction` are listed below, where the default option This option requires both `width` and `height` to be specified. It does not scale up. - Deprecated spellings: `keep`, `thumbnail`. + Deprecated option names: `keep`, `thumbnail`. `contain` : `contain` starts by scaling the image either to the smaller dimension when you give both `width` and `height`, or to the only given dimension, then crops to the other dimension if needed. - Deprecated spellings: `scale-crop-to-fit`, `down`. + Deprecated option names: `scale-crop-to-fit`, `down`. `cover` : `cover` scales the image either to the larger dimension when you give both `width` and `height`, or to the only given dimension, up to the size you specify. - Despite the deprecated spelling, it does not crop. + Despite the deprecated option name, it does not crop. - Deprecated spellings: `scale-crop-to-fill`, `up`. + Deprecated option names: `scale-crop-to-fill`, `up`. (classic-ui-images-permissions-label)= From 8adb2494197d19acc9c925710383a77865b5c606 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 14 Feb 2024 01:49:30 -0800 Subject: [PATCH 125/810] Add versionchanged admonition --- docs/classic-ui/images.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/classic-ui/images.md b/docs/classic-ui/images.md index 21c97177f..7329140b6 100644 --- a/docs/classic-ui/images.md +++ b/docs/classic-ui/images.md @@ -237,6 +237,10 @@ image_scale = scaling_util.publishTraverse(context.REQUEST, groups[1]) ## Scaling `direction` +```{versionchanged} 6.0 +Added new option names to align with CSS `background-size` values, and deprecated previous names. +``` + Scaling is intended for the optimal display of images in a web browser. To scale an image, you can use the `direction` parameter to control the scaling output. From 85aa43615e58a281589d13bb3e4a6651b5ef86a1 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 14 Feb 2024 03:16:38 -0800 Subject: [PATCH 126/810] `direction` is deprecated and replaced by `mode`, whose new default is `scale`, not `thumbnail` --- docs/classic-ui/images.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/classic-ui/images.md b/docs/classic-ui/images.md index 7329140b6..c21df14cc 100644 --- a/docs/classic-ui/images.md +++ b/docs/classic-ui/images.md @@ -114,7 +114,7 @@ tag = scale_util.tag( scale=None, height=None, width=None, - direction="thumbnail" + mode="scale" ) ``` @@ -233,9 +233,9 @@ image_scale = scaling_util.publishTraverse(context.REQUEST, groups[1]) ``` -(classic-ui-images-scaling-direction-label)= +(classic-ui-images-scaling-mode-label)= -## Scaling `direction` +## Scaling `mode` ```{versionchanged} 6.0 Added new option names to align with CSS `background-size` values, and deprecated previous names. @@ -243,13 +243,13 @@ Added new option names to align with CSS `background-size` values, and deprecate Scaling is intended for the optimal display of images in a web browser. -To scale an image, you can use the `direction` parameter to control the scaling output. +To scale an image, you can use the `mode` parameter to control the scaling output. You must use either `width` or `height`, or both. Three different scaling options are supported. They correspond to the CSS [`background-size`](https://developer.mozilla.org/en-US/docs/Web/CSS/background-size) values. -The possible options for `direction` are listed below, where the default option is `scale`. +The possible options for `mode` are listed below, where the default option is `scale`. `scale` : This is the default option. From 0363feb2073c1b06d8b9d0a1c98217359cc7ce8a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 14 Feb 2024 03:19:18 -0800 Subject: [PATCH 127/810] Update admonition --- docs/classic-ui/images.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/classic-ui/images.md b/docs/classic-ui/images.md index c21df14cc..6bfd771c1 100644 --- a/docs/classic-ui/images.md +++ b/docs/classic-ui/images.md @@ -238,7 +238,8 @@ image_scale = scaling_util.publishTraverse(context.REQUEST, groups[1]) ## Scaling `mode` ```{versionchanged} 6.0 -Added new option names to align with CSS `background-size` values, and deprecated previous names. +Added `mode` to replace the deprecated `direction`. +Added new option names for `mode` to align with CSS `background-size` values, and deprecated previous names `keep`, `thumbnail`, `scale-crop-to-fit`, `down`, `scale-crop-to-fill`, and `up`. ``` Scaling is intended for the optimal display of images in a web browser. From d281d0c04fba7e54c0949ea20965129e82585b31 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 14 Feb 2024 23:35:16 -0800 Subject: [PATCH 128/810] Update tips submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index d036535c6..8d4e72b71 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit d036535c6350f2afbf3086e14f6eaf8628314161 +Subproject commit 8d4e72b71eef78453f85d278dfbec085513786bf From 6aa9e1d46c56603a5934e1f5053fe4fa853aca71 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 15 Feb 2024 05:06:47 -0800 Subject: [PATCH 129/810] Add Mockup landing page to docs --- docs/classic-ui/index.md | 1 + docs/classic-ui/mockup.md | 18 ++++++++++++++++++ docs/glossary.md | 14 ++++++++++++-- 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 docs/classic-ui/mockup.md diff --git a/docs/classic-ui/index.md b/docs/classic-ui/index.md index 0e8995bc5..c33d48757 100644 --- a/docs/classic-ui/index.md +++ b/docs/classic-ui/index.md @@ -53,6 +53,7 @@ forms icons images layers +mockup portlets recipes static-resources diff --git a/docs/classic-ui/mockup.md b/docs/classic-ui/mockup.md new file mode 100644 index 000000000..8f756c006 --- /dev/null +++ b/docs/classic-ui/mockup.md @@ -0,0 +1,18 @@ +--- +myst: + html_meta: + "description": "Mockup together with Patternslib are used to create Classic UI, a frontend for Plone." + "property=og:description": "Mockup together with Patternslib are used to create Classic UI, a frontend for Plone." + "property=og:title": "Mockup" + "keywords": "Mockup, Patternslib, Classic UI, frontend, Plone" +--- + +(mockup-label)= + +# Mockup + +{term}`Mockup` together with {term}`Patternslib` are used to create {term}`Classic UI`, a frontend for Plone. + +View a [demo of Mockup](https://plone.github.io/mockup/). + +For more information, visit the [Mockup repository on GitHub](https://github.com/plone/mockup). diff --git a/docs/glossary.md b/docs/glossary.md index 2c361e5a6..31c6691fd 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -406,11 +406,21 @@ Classic UI It is integrated with [Products.CMFPlone](https://github.com/plone/Products.CMFPlone/). Its theme is named [Barceloneta](https://github.com/plone/plonetheme.barceloneta/). It is based on Twitter Bootstrap 5. - It uses [Mockup](https://github.com/plone/mockup/) as its JavaScript stack. - [View Mockup's patterns](https://plone.github.io/mockup/). + It uses {term}`Mockup` as its JavaScript stack. The other frontend is {term}`Volto`. +Mockup + [Mockup](https://github.com/plone/mockup/) is a package that, together with {term}`Patternslib`, are used to create {term}`Classic UI`, a frontend for Plone. + Mockup provides the JavaScript stack for Classic UI. + [View Mockup's patterns](https://plone.github.io/mockup/), based on Patternslib. + +Patterns +Patternslib + [Patterns](https://patternslib.com/), or Patternslib, is a toolkit that enables designers to build rich interactive prototypes without the need for writing any JavaScript. + All functionality is triggered by classes and other attributes in the HTML, without abusing the HTML as a programming language. + Accessibility, SEO, and well-structured HTML are core values of Patterns. + Slate [Slate.js](https://docs.slatejs.org/) is a highly customizable platform for creating rich-text editors, also known as `WYSIWYG` editors. It enables you to create powerful, intuitive editors similar to those you've probably used in Medium, Dropbox Paper, or Google Docs. From 33196e181c0aaeeb54ac70a595df18e652143ee6 Mon Sep 17 00:00:00 2001 From: Maik Derstappen Date: Thu, 15 Feb 2024 15:36:03 +0200 Subject: [PATCH 130/810] Update mockup.md --- docs/classic-ui/mockup.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/classic-ui/mockup.md b/docs/classic-ui/mockup.md index 8f756c006..fc3982f37 100644 --- a/docs/classic-ui/mockup.md +++ b/docs/classic-ui/mockup.md @@ -1,8 +1,8 @@ --- myst: html_meta: - "description": "Mockup together with Patternslib are used to create Classic UI, a frontend for Plone." - "property=og:description": "Mockup together with Patternslib are used to create Classic UI, a frontend for Plone." + "description": "Mockup together with Patternslib building the UI toolkit for Classic UI, a frontend for Plone." + "property=og:description": "Mockup together with Patternslib building the UI toolkit for Classic UI, a frontend for Plone." "property=og:title": "Mockup" "keywords": "Mockup, Patternslib, Classic UI, frontend, Plone" --- @@ -11,8 +11,8 @@ myst: # Mockup -{term}`Mockup` together with {term}`Patternslib` are used to create {term}`Classic UI`, a frontend for Plone. +{term}`Mockup` together with {term}`Patternslib` building the UI toolkit for {term}`Classic UI`, a frontend for Plone. -View a [demo of Mockup](https://plone.github.io/mockup/). +View the [interactive documentation of Mockup](https://plone.github.io/mockup/). For more information, visit the [Mockup repository on GitHub](https://github.com/plone/mockup). From d4ea0d2e1a8457a07ca4b2ec3ccb9cee6263236b Mon Sep 17 00:00:00 2001 From: Maik Derstappen Date: Thu, 15 Feb 2024 15:37:52 +0200 Subject: [PATCH 131/810] Update Mockup description in glossary.md --- docs/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/glossary.md b/docs/glossary.md index 31c6691fd..e7091d97a 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -411,7 +411,7 @@ Classic UI The other frontend is {term}`Volto`. Mockup - [Mockup](https://github.com/plone/mockup/) is a package that, together with {term}`Patternslib`, are used to create {term}`Classic UI`, a frontend for Plone. + [Mockup](https://github.com/plone/mockup/) is a package that, together with {term}`Patternslib`, builds the UI toolkit for {term}`Classic UI`, a frontend for Plone. Mockup provides the JavaScript stack for Classic UI. [View Mockup's patterns](https://plone.github.io/mockup/), based on Patternslib. From c9e3a006f0cfb139c67f7928dc6e3af0987a4a67 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 15 Feb 2024 06:12:37 -0800 Subject: [PATCH 132/810] Grammar fixes --- docs/classic-ui/mockup.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/classic-ui/mockup.md b/docs/classic-ui/mockup.md index fc3982f37..e053303e8 100644 --- a/docs/classic-ui/mockup.md +++ b/docs/classic-ui/mockup.md @@ -1,8 +1,8 @@ --- myst: html_meta: - "description": "Mockup together with Patternslib building the UI toolkit for Classic UI, a frontend for Plone." - "property=og:description": "Mockup together with Patternslib building the UI toolkit for Classic UI, a frontend for Plone." + "description": "Mockup together with Patternslib are used to build the UI toolkit for Classic UI, a frontend for Plone." + "property=og:description": "Mockup together with Patternslib are used to build the UI toolkit for Classic UI, a frontend for Plone." "property=og:title": "Mockup" "keywords": "Mockup, Patternslib, Classic UI, frontend, Plone" --- @@ -11,7 +11,7 @@ myst: # Mockup -{term}`Mockup` together with {term}`Patternslib` building the UI toolkit for {term}`Classic UI`, a frontend for Plone. +{term}`Mockup` together with {term}`Patternslib` are used to build the UI toolkit for {term}`Classic UI`, a frontend for Plone. View the [interactive documentation of Mockup](https://plone.github.io/mockup/). From 9002a23509d47956e8b59f9abe3a3bd5fb1c9dcb Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 15 Feb 2024 06:19:39 -0800 Subject: [PATCH 133/810] Remove extra space --- docs/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/glossary.md b/docs/glossary.md index e7091d97a..ea1b5b605 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -411,7 +411,7 @@ Classic UI The other frontend is {term}`Volto`. Mockup - [Mockup](https://github.com/plone/mockup/) is a package that, together with {term}`Patternslib`, builds the UI toolkit for {term}`Classic UI`, a frontend for Plone. + [Mockup](https://github.com/plone/mockup/) is a package that, together with {term}`Patternslib`, builds the UI toolkit for {term}`Classic UI`, a frontend for Plone. Mockup provides the JavaScript stack for Classic UI. [View Mockup's patterns](https://plone.github.io/mockup/), based on Patternslib. From d1c24c7cd996c58fe7023da944c38d24c5946b2e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 16 Feb 2024 01:07:51 -0800 Subject: [PATCH 134/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 7833026a1..618218551 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 7833026a16b0c9a4bfb7230dece8c531e9a02eff +Subproject commit 6182185513ee76861c91514e35feb94cbba3d0d9 diff --git a/submodules/volto b/submodules/volto index 8d4e72b71..7a5aece8d 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 8d4e72b71eef78453f85d278dfbec085513786bf +Subproject commit 7a5aece8da4905a05621335c64025ed96d8f2ba9 From 30762c5fc6cef715c759663e963a3d4ee4536b5e Mon Sep 17 00:00:00 2001 From: Victor Fernandez de Alba Date: Sat, 17 Feb 2024 15:18:47 +0100 Subject: [PATCH 135/810] Fix yarn installation --- docs/install/create-project.md | 95 ++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 45 deletions(-) diff --git a/docs/install/create-project.md b/docs/install/create-project.md index 57dc753ad..ef99ca4dc 100644 --- a/docs/install/create-project.md +++ b/docs/install/create-project.md @@ -11,7 +11,7 @@ myst: (create-a-project-label)= # Create a project - + This chapter describes how you can create a web application project using Plone, with full control over development and deployment. If instead you want to contribute to a Plone package, see {doc}`/contributing/index`. @@ -62,6 +62,7 @@ To avoid RAM and disk swap limitations, we recommend either temporarily resizing - {term}`Node.js` LTS 20.x - {term}`Yeoman` - {term}`Yarn` +- {term}`git` - {term}`GNU make` - {term}`Docker` @@ -134,20 +135,17 @@ For the `fish` shell, see [`nvm.fish`](https://github.com/jorgebucaran/nvm.fish) (install-prerequisites-yeoman-label)= -#### Yeoman +#### Yeoman and the Volto boilerplate generator -Install {term}`Yeoman`. +Install {term}`Yeoman` and the Volto boilerplate generator ```shell -npm install -g yo +npm install -g yo @plone/generator-volto ``` - (install-prerequisites-yarn-label)= -#### Yarn 3 - -Install the latest Yarn 3 version (not the Classic 1.x one). +#### Yarn 1. Open a terminal and type: @@ -155,28 +153,35 @@ Install the latest Yarn 3 version (not the Classic 1.x one). corepack enable ``` -2. Verify that Yarn v3.x.x is installed and activated. - - ```shell - yarn set version 3.x - yarn -v - ``` - ```console - 3.2.3 - ``` - - If you see a version that is not v3.x.x, you can try deleting the {file}`yarn.lock` file, and installing again. - - ```shell - rm yarn.lock - corepack enable - yarn set version 3.x - yarn -v - ``` - ```console - 3.2.3 - ``` - +From that moment on, `yarn` will be available for you to use in your system. +This is thanks that `yarn` is shipped with NodeJS since Node 16 (along with other common package managers). +The version shipped is v1 (classic `yarn`). +Volto makes sure that you are using the correct version of `yarn` at runtime. +This is because it's pinned in the Volto boilerplate to use the right version. +So from this moment on, you don't have to worry about the version of `yarn` you are using, it will adapt to the project's needs. + +````important +These instructions will not work if you have used another package manager, such as Homebrew on macOS, to install Yarn. +You can verify where you installed Yarn and its version. +Make sure that you are using the yarn version provided by NodeJS by default +```shell +which yarn +``` +```console +/opt/homebrew/bin/yarn +``` +```shell +yarn -v +``` +```console +3.2.3 +``` +If the console includes `homebrew` in the path, and the version of Yarn is not supported, then you must uninstall it. +```shell +brew uninstall yarn +``` +Now the instructions should work. +```` (install-prerequisites-make-label)= @@ -234,7 +239,7 @@ Note that pip normalizes these names, so `plone.volto` and `plone-volto` are the % pipx run cookiecutter gh:collective/cookiecutter-plone-starter -Cookiecutter Plone Starter +Cookiecutter Plone Starter ================================================================================ Sanity checks @@ -249,21 +254,21 @@ Project details -------------------------------------------------------------------------------- [1/19] Project Title (Project Title): Plone Conference Website 2070 - [2/19] Project Description (A new project using Plone 6.): - [3/19] Project Slug (Used for repository id) (plone-conference-website-2070): - [4/19] Project URL (without protocol) (plone-conference-website-2070.example.com): + [2/19] Project Description (A new project using Plone 6.): + [3/19] Project Slug (Used for repository id) (plone-conference-website-2070): + [4/19] Project URL (without protocol) (plone-conference-website-2070.example.com): [5/19] Author (Plone Foundation): Elli [6/19] Author E-mail (collective@plone.org): elli@plone.org - [7/19] Python Package Name (plone_conference_website_2070): - [8/19] Volto Addon Name (volto-plone-conference-website-2070): + [7/19] Python Package Name (plone_conference_website_2070): + [8/19] Volto Addon Name (volto-plone-conference-website-2070): [9/19] Choose a Python Test Framework 1 - pytest 2 - unittest - Choose from [1/2] (1): - [10/19] Plone Version (6.0.8): + Choose from [1/2] (1): + [10/19] Plone Version (6.0.8): [11/19] Should we use Volto Alpha Versions? (No): yes - [12/19] Volto Version (18.0.0-alpha.1): - [13/19] Volto Generator Version (8.0.0): + [12/19] Volto Version (18.0.0-alpha.1): + [13/19] Volto Generator Version (8.0.0): [14/19] Language 1 - English 2 - Deutsch @@ -271,12 +276,12 @@ Project details 4 - Português (Brasil) 5 - Nederlands 6 - Suomi - Choose from [1/2/3/4/5/6] (1): + Choose from [1/2/3/4/5/6] (1): [15/19] GitHub Username or Organization (collective): ellizurigo [16/19] Container Registry 1 - GitHub Container Registry 2 - Docker Hub - Choose from [1/2] (1): + Choose from [1/2] (1): [17/19] Should we setup a caching server? 1 - Yes 2 - No @@ -284,11 +289,11 @@ Project details [18/19] Add Ansible playbooks? 1 - Yes 2 - No - Choose from [1/2] (1): + Choose from [1/2] (1): [19/19] Add GitHub Action to Deploy this project? 1 - Yes 2 - No - Choose from [1/2] (1): + Choose from [1/2] (1): Plone Conference Website 2070 generation -------------------------------------------------------------------------------- @@ -358,7 +363,7 @@ To fix this you could try to: 1. loosen the range of package versions you've specified 2. remove package versions to allow pip attempt to solve the dependency conflict -ERROR: ResolutionImpossible: for help visit +ERROR: ResolutionImpossible: for help visit make[2]: *** [Makefile:112: build-dev] Error 1 make[2]: Leaving directory '/home/username/projects/volto/plone-volto/backend' make[1]: *** [Makefile:46: install-backend] Error 2 From 8417c20a43a0f084213daf4f490d307e743bea98 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Feb 2024 15:30:26 -0800 Subject: [PATCH 136/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 7a5aece8d..27fa95575 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 7a5aece8da4905a05621335c64025ed96d8f2ba9 +Subproject commit 27fa955759e213ea82d0ccc7a4bdd4771413935b From c302a1dc3b21932aca739c82a0a51b297de4bc6d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Feb 2024 16:18:09 -0800 Subject: [PATCH 137/810] Add Corepack to Glossary, and expand Yarn definition. --- docs/glossary.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/glossary.md b/docs/glossary.md index ea1b5b605..4d2421424 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -280,7 +280,14 @@ mrs-developer As a byproduct of its update operations, it also automatically adjusts `jsconfig.json`, which is used by Volto to configure webpack aliases. Yarn - [Yarn](https://yarnpkg.com/) is a JavaScript package manager. + [Yarn](https://yarnpkg.com/) is both a JavaScript package manager and project manager. + +Corepack + [Corepack](https://github.com/nodejs/corepack) is a zero-runtime-dependency Node.js script that acts as a bridge between Node.js projects and the package managers they are intended to be used with during development. + In practical terms, Corepack lets you use {term}`Yarn`, {term}`npm`, and {term}`pnpm` without having to install them. + + Corepack is distributed by default with all recent Node.js versions. + Run `corepack enable` to install the required Yarn and pnpm binaries on your path. Hydration After loading an HTML page generated with {term}`SSR` in the browser, React can populate the existing {term}`DOM` elements, and recreate and attach their coresponding components. From 072200090dc3e72a3dbd9c83a420f1aae7a26f1c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Feb 2024 16:20:33 -0800 Subject: [PATCH 138/810] - Move explanation to Glossary, referring to Corepack. - Condense code block - Make a guess about how Volto pins the Yarn version. Need to confirm with @sneridagh. --- docs/install/create-project.md | 37 +++++++++++++++------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/docs/install/create-project.md b/docs/install/create-project.md index ef99ca4dc..ad1a4ca04 100644 --- a/docs/install/create-project.md +++ b/docs/install/create-project.md @@ -137,50 +137,45 @@ For the `fish` shell, see [`nvm.fish`](https://github.com/jorgebucaran/nvm.fish) #### Yeoman and the Volto boilerplate generator -Install {term}`Yeoman` and the Volto boilerplate generator +Install {term}`Yeoman` and the Volto boilerplate generator. ```shell npm install -g yo @plone/generator-volto ``` + (install-prerequisites-yarn-label)= #### Yarn +Use {term}`Corepack` to enable Yarn, which was already installed with the {ref}`supported version of Node.js `. + 1. Open a terminal and type: ```shell corepack enable ``` -From that moment on, `yarn` will be available for you to use in your system. -This is thanks that `yarn` is shipped with NodeJS since Node 16 (along with other common package managers). -The version shipped is v1 (classic `yarn`). -Volto makes sure that you are using the correct version of `yarn` at runtime. -This is because it's pinned in the Volto boilerplate to use the right version. -So from this moment on, you don't have to worry about the version of `yarn` you are using, it will adapt to the project's needs. - -````important -These instructions will not work if you have used another package manager, such as Homebrew on macOS, to install Yarn. -You can verify where you installed Yarn and its version. -Make sure that you are using the yarn version provided by NodeJS by default +In your generated Volto project from the previous step, you can find the pinned version of Yarn in its {file}`.yarnrc.yml`. + +````{important} +The preceding instructions will not work if you have used another package manager, such as Homebrew on macOS, to install Yarn. +You can verify where you installed Yarn and its version, and compare that to the pinned value of Yarn in your generated Volto project's {file}`.yarnrc.yml`. + ```shell which yarn -``` -```console -/opt/homebrew/bin/yarn -``` -```shell +# /opt/homebrew/bin/yarn yarn -v +# 3.2.3 ``` -```console -3.2.3 -``` + If the console includes `homebrew` in the path, and the version of Yarn is not supported, then you must uninstall it. + ```shell brew uninstall yarn ``` -Now the instructions should work. + +Now the instructions to install Yarn should work. ```` (install-prerequisites-make-label)= From 07f76dab395be4c561f5d73b225e8fc3caca56c6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Feb 2024 17:53:00 -0800 Subject: [PATCH 139/810] Add Git section and Glossary entry --- docs/glossary.md | 3 +++ docs/install/create-project.md | 12 ++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/glossary.md b/docs/glossary.md index 4d2421424..e8d9ce6c3 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -289,6 +289,9 @@ Corepack Corepack is distributed by default with all recent Node.js versions. Run `corepack enable` to install the required Yarn and pnpm binaries on your path. +Git + [Git](https://git-scm.com/) is a free and open source distributed version control system. + Hydration After loading an HTML page generated with {term}`SSR` in the browser, React can populate the existing {term}`DOM` elements, and recreate and attach their coresponding components. diff --git a/docs/install/create-project.md b/docs/install/create-project.md index ad1a4ca04..329efe017 100644 --- a/docs/install/create-project.md +++ b/docs/install/create-project.md @@ -62,9 +62,9 @@ To avoid RAM and disk swap limitations, we recommend either temporarily resizing - {term}`Node.js` LTS 20.x - {term}`Yeoman` - {term}`Yarn` -- {term}`git` - {term}`GNU make` - {term}`Docker` +- {term}`Git` (install-prerequisites-python-label)= @@ -188,12 +188,20 @@ Now the instructions to install Yarn should work. (install-prerequisites-docker-label)= -#### Install Docker +#### Docker ```{include} ../volto/contributing/install-docker.md ``` +(install-prerequisites-git-label)= + +#### Git + +```{include} ../volto/contributing/install-git.md +``` + + (install-packages-install-label)= ## Install Plone 6 From 2d6c5ab03d255d97cfb2b6fa71eb6966a56ac0c8 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Feb 2024 17:54:37 -0800 Subject: [PATCH 140/810] Exclude includes from source scanning --- docs/conf.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 7067a94ad..1e9805a3d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -130,9 +130,11 @@ "plone.restapi/performance", "plone.restapi/src", "volto/contributing/branch-policy.md", - "volto/contributing/install-operating-system.md", - "volto/contributing/install-nodejs.md", + "volto/contributing/install-docker.md", + "volto/contributing/install-git.md", "volto/contributing/install-make.md", + "volto/contributing/install-nodejs.md", + "volto/contributing/install-operating-system.md", ] suppress_warnings = [ From 527e7a0fe72133c037278df21d1705c873080659 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Feb 2024 22:47:47 -0800 Subject: [PATCH 141/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 27fa95575..dd7cd168c 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 27fa955759e213ea82d0ccc7a4bdd4771413935b +Subproject commit dd7cd168cb4eb3706d795dd300346c6d05601871 From 3507f95b55ff5f299ecd2196cd2d3f1ef9a752ef Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Feb 2024 22:48:57 -0800 Subject: [PATCH 142/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 27fa95575..dd7cd168c 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 27fa955759e213ea82d0ccc7a4bdd4771413935b +Subproject commit dd7cd168cb4eb3706d795dd300346c6d05601871 From cf167b78568ad21c93b787bfbb0f6f38cb10a692 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 18 Feb 2024 14:45:59 -0800 Subject: [PATCH 143/810] Simplify, as the system Yarn version is misleading. Why? Only seasoned JavaScript developers know, lol, I'm a n00b! --- docs/install/create-project.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/install/create-project.md b/docs/install/create-project.md index 329efe017..311af5403 100644 --- a/docs/install/create-project.md +++ b/docs/install/create-project.md @@ -156,20 +156,16 @@ Use {term}`Corepack` to enable Yarn, which was already installed with the {ref}` corepack enable ``` -In your generated Volto project from the previous step, you can find the pinned version of Yarn in its {file}`.yarnrc.yml`. - ````{important} The preceding instructions will not work if you have used another package manager, such as Homebrew on macOS, to install Yarn. -You can verify where you installed Yarn and its version, and compare that to the pinned value of Yarn in your generated Volto project's {file}`.yarnrc.yml`. +You can verify where you installed Yarn. ```shell which yarn # /opt/homebrew/bin/yarn -yarn -v -# 3.2.3 ``` -If the console includes `homebrew` in the path, and the version of Yarn is not supported, then you must uninstall it. +If the console includes `homebrew` in the path, then you must uninstall it. ```shell brew uninstall yarn @@ -178,6 +174,7 @@ brew uninstall yarn Now the instructions to install Yarn should work. ```` + (install-prerequisites-make-label)= #### Make From d840b774c0c62298ef7b3366cd5ba2b1b8abb630 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 22 Feb 2024 01:29:19 -0800 Subject: [PATCH 144/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index dd7cd168c..4e0f9097c 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit dd7cd168cb4eb3706d795dd300346c6d05601871 +Subproject commit 4e0f9097c900fb81f98a5fd54dbd01e532df371f From f25fa57519d38efcfec5b057edb00f0fde87062f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 22 Feb 2024 01:46:01 -0800 Subject: [PATCH 145/810] Add predicate to glossary See https://github.com/plone/volto/pull/5775 --- docs/glossary.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/glossary.md b/docs/glossary.md index ea1b5b605..155288139 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -690,4 +690,7 @@ Guillotina Nick [Nick](https://nickcms.org/) is a headless content management system {term}`CMS` built with {term}`Node.js`. + +predicate + In programming, a predicate is a test which returns `true` or `false`. ``` From 444348d02d46621876104224556b1de627b57b77 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 22 Feb 2024 02:04:42 -0800 Subject: [PATCH 146/810] Add https://stackoverflow.com to ignore in linkcheck, and sort entries --- docs/conf.py | 5 +++-- docs/glossary.md | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 7067a94ad..c679a1aba 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -93,10 +93,11 @@ r"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors#Identifying_the_issue", r"https://docs.cypress.io/guides/references/migration-guide#Migrating-to-Cypress-version-10-0", # volto # Ignore unreliable sites - r"https://web.archive.org/", # volto - r"https://www.youtube.com/playlist", # volto, TODO remove after installing sphinxcontrib.youtube r"https://chromewebstore.google.com/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi", # TODO retest with latest Sphinx when upgrading theme. chromewebstore recently changed its URL and has "too many redirects". r"https://chromewebstore.google.com/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd", # TODO retest with latest Sphinx when upgrading theme. chromewebstore recently changed its URL and has "too many redirects". + r"https://stackoverflow.com", # volto and documentation # TODO retest with latest Sphinx. + r"https://web.archive.org/", # volto + r"https://www.youtube.com/playlist", # volto, TODO remove after installing sphinxcontrib.youtube ] linkcheck_anchors = True linkcheck_timeout = 10 diff --git a/docs/glossary.md b/docs/glossary.md index 155288139..d0f72efa2 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -692,5 +692,6 @@ Nick [Nick](https://nickcms.org/) is a headless content management system {term}`CMS` built with {term}`Node.js`. predicate +predicates In programming, a predicate is a test which returns `true` or `false`. ``` From 790fc864b51da34fbe8cc3189999d1223c0a77ed Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 26 Feb 2024 02:44:20 -0800 Subject: [PATCH 147/810] Update tips submodules/plone.api submodules/plone.restapi submodules/volto --- submodules/plone.api | 2 +- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index 44c900695..08884b755 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit 44c900695a79e21d1bd1c452b9dadb385823a04d +Subproject commit 08884b755450cdc5290d640b826d3f659025179f diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 618218551..1f97c6a57 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 6182185513ee76861c91514e35feb94cbba3d0d9 +Subproject commit 1f97c6a576d9136057ecf829b0f758fcd1e753ca diff --git a/submodules/volto b/submodules/volto index 4e0f9097c..351da3363 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 4e0f9097c900fb81f98a5fd54dbd01e532df371f +Subproject commit 351da33637da1122b50a4e37fa4582a93c78e2f3 From c43639e1666210ee90b22cfda4b2ac8ac37135e5 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 28 Feb 2024 05:56:18 -0800 Subject: [PATCH 148/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 1f97c6a57..1771c9c43 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 1f97c6a576d9136057ecf829b0f758fcd1e753ca +Subproject commit 1771c9c43b63dd0a6b29ab1339b6e8d6330876ab diff --git a/submodules/volto b/submodules/volto index 351da3363..4de0ce2ff 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 351da33637da1122b50a4e37fa4582a93c78e2f3 +Subproject commit 4de0ce2ff115d709a0a1aa41d5c1031b324114c3 From f18bd58988f712c7686fe51ddd5a1504e77645e8 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 28 Feb 2024 06:44:05 -0800 Subject: [PATCH 149/810] Refactor volto/recipes to volto/development See https://github.com/plone/volto/pull/5809 --- docs/i18n-l10n/index.md | 2 +- docs/i18n-l10n/language-negotiation-volto.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/i18n-l10n/index.md b/docs/i18n-l10n/index.md index 58c3cf7cc..4f68a17d5 100644 --- a/docs/i18n-l10n/index.md +++ b/docs/i18n-l10n/index.md @@ -128,7 +128,7 @@ In general, the process of internationalization and localization of a Plone appl Depending on which part of your Plone application that you internationalize and localize, there are different implementation details and tools that are used. These differences depend upon the programming language, either Python or JavaScript, being used by that part. -- For the Plone 6 frontend {term}`Volto`, see {doc}`/volto/recipes/i18n`. +- For the Plone 6 frontend {term}`Volto`, see {doc}`/volto/development/i18n`. Volto is based on the JavaScript library React, and uses both {term}`react-intl` and {term}`gettext`. - For the rest of Plone 6, see {doc}`translating-text-strings`. This is based on Python, and uses {term}`gettext`. diff --git a/docs/i18n-l10n/language-negotiation-volto.md b/docs/i18n-l10n/language-negotiation-volto.md index d62d6665f..542b08e9f 100644 --- a/docs/i18n-l10n/language-negotiation-volto.md +++ b/docs/i18n-l10n/language-negotiation-volto.md @@ -31,4 +31,4 @@ If the site is not configured to be multilingual, Volto doesn't do any redirect. ## Overriding the default behavior -To do so, you need to provide your own `MultilingualRedirector` component {doc}`customizing it `. +To do so, you need to provide your own `MultilingualRedirector` component {doc}`customizing it `. From 4fb6e314b13efcf596a091e3ec6294db2dbb4104 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 28 Feb 2024 14:27:02 -0800 Subject: [PATCH 150/810] Bump PLONE_BACKEND_PATCH_VERSION for docker image --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 83cb6fab2..655d0e714 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -341,7 +341,7 @@ def source_replace(app, docname, source): # Dict of replacements. source_replacements = { "{PLONE_BACKEND_MINOR_VERSION}": "6.0", - "{PLONE_BACKEND_PATCH_VERSION}": "6.0.9", + "{PLONE_BACKEND_PATCH_VERSION}": "6.0.10.1", "{NVM_VERSION}": "0.39.5", "{SUPPORTED_PYTHON_VERSIONS}": "3.8, 3.9, 3.10, or 3.11", } From 4bbef41e98a489812094429ccc884b197c70c660 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 28 Feb 2024 14:55:21 -0800 Subject: [PATCH 151/810] Add support for Python 3.12 Co-authored-by: Maurits van Rees --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 655d0e714..64df6bca1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -343,7 +343,7 @@ def source_replace(app, docname, source): "{PLONE_BACKEND_MINOR_VERSION}": "6.0", "{PLONE_BACKEND_PATCH_VERSION}": "6.0.10.1", "{NVM_VERSION}": "0.39.5", - "{SUPPORTED_PYTHON_VERSIONS}": "3.8, 3.9, 3.10, or 3.11", + "{SUPPORTED_PYTHON_VERSIONS}": "3.8, 3.9, 3.10, 3.11, or 3.12", } From 5305c2ab43dfda1c675fa16d49bee138e4176d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Katja=20Su=CC=88ss?= Date: Thu, 29 Feb 2024 08:40:10 +0100 Subject: [PATCH 152/810] Fix for plone/cookiecutter-zope-instance 2.x --- docs/install/manage-add-ons-packages.md | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/docs/install/manage-add-ons-packages.md b/docs/install/manage-add-ons-packages.md index 2d1be7eed..c53564be4 100644 --- a/docs/install/manage-add-ons-packages.md +++ b/docs/install/manage-add-ons-packages.md @@ -176,11 +176,7 @@ Add it to {file}`instance.yaml` to let Zope know that this add-on should be load ```{code-block} yaml :emphasize-lines: 3-6 default_context: - load_zcml: - package_includes: [ - 'project_title', - 'collective.easyform', - ] + zcml_package_includes: project_title, collective.easyform ``` Stop the backend with {kbd}`ctrl-c`. @@ -221,11 +217,7 @@ Add it to {file}`instance.yaml` to let Zope know that this add-on should be load ```yaml default_context: - load_zcml: - package_includes: [ - 'project_title', - 'collective.easyform', - ] + zcml_package_includes: project_title, collective.easyform ``` Stop the backend with {kbd}`ctrl-c`. @@ -265,11 +257,7 @@ Add it to {file}`instance.yaml` to let Zope know that this add-on should be load ```yaml default_context: - load_zcml: - package_includes: [ - 'project_title', - 'collective.easyform', - ] + zcml_package_includes: project_title, collective.easyform ``` Stop the backend with {kbd}`ctrl-c`. From 7b7dcae73f20b8da8eaad9f1f53b220e5dee1347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Katja=20Su=CC=88ss?= Date: Thu, 29 Feb 2024 08:42:37 +0100 Subject: [PATCH 153/810] Update manage-add-ons-packages.md --- docs/install/manage-add-ons-packages.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/install/manage-add-ons-packages.md b/docs/install/manage-add-ons-packages.md index c53564be4..e1b432dfe 100644 --- a/docs/install/manage-add-ons-packages.md +++ b/docs/install/manage-add-ons-packages.md @@ -173,8 +173,7 @@ collective.easyform Add it to {file}`instance.yaml` to let Zope know that this add-on should be loaded: -```{code-block} yaml -:emphasize-lines: 3-6 +```yaml default_context: zcml_package_includes: project_title, collective.easyform ``` From 192be28f4d3f0f0b486f6dcb8785fdffb47a114f Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Thu, 29 Feb 2024 18:05:23 +0100 Subject: [PATCH 154/810] Add Viewlets section to 6.0 backend upgrade guide. See also https://github.com/plone/Products.CMFPlone/issues/3911 --- .../upgrade-to-60.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md index 0eeddda3a..e57e33481 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md @@ -602,3 +602,40 @@ Please make sure you write valid JSON for the `template` option. ```{seealso} See also the [TinyMCE 4 to 5 upgrade guide](https://www.tiny.cloud/docs/migration-from-4x/). ``` + +## Viewlets + +Plone 6.0 renames various viewlets or moves them to a different viewlet manager. +The reason for renaming, is that some viewlet names contained the name of a viewlet manager. +This didn't always match the name of their actual viewlet manager, especially after moving them. +Plone 6.0 removes such references from the viewlet names, to avoid confusion. + +- Plone 6.0 removes the `plone.documentactions (IDocumentActions)` viewlet manager. In Plone 5.2 it was already empty. +- Plone 6.0 adds the `plone.belowcontentdescription (IBelowContentDescription)` viewlet manager. By default this has no viewlets. +- Plone 6.0 removes the `plone.header` viewlet from `plone.portaltop` manager, making it empty. +- Plone 6.0 renames the `plone.abovecontenttitle.documentactions` viewlet to `plone.documentactions` and moves it from manager `plone.belowcontentbody` to `plone.belowcontent`. +- Plone 6.0 renames the `plone.abovecontenttitle.socialtags` viewlet to `plone.socialtags`. It remains in manager `plone.abovecontenttitle`. +- Plone 6.0 renames the `plone.belowcontentbody.relateditems` viewlet to `plone.relateditems`. It remains in manager `plone.belowcontentbody`. +- Plone 6.0 removes the `plone.manage_portlets_fallback` viewlet from the `plone.belowcontent` manager. +- Plone 6.0 renames the `plone.belowcontenttitle.documentbyline` viewlet to `plone.documentbyline` . It remains in manager `plone.belowcontenttitle`. +- Plone 6.0 renames the `plone.belowcontenttitle.keywords` viewlet to `plone.keywords` and moves it from manager `plone.belowcontent` to `plone.belowcontentbody`. +- Plone 6.0 adds the `plone.rights` viewlet in manager `plone.belowcontentbody`. +- Plone 6.0 moves the `plone.footer` viewlet from `plone.app.layout/viewlets` to `plone.app.portlets`. The viewlet remains in manager `plone.portalfooter`. It renders the portlets from the `plone.footerportlets` portlet manager. + +This is the same information in table form. +You can toggle navigation to make more of the table visible. + +:::{table} Viewlet changes from 5.2 to 6.0 + +| 5.2 viewlet name | 5.2 viewlet manager | 6.0 viewlet name | 6.0 viewlet manager | +| ---------------- | ------------------- | ---------------- | ------------------- | +|| `plone.documentactions` | | | +|||| `plone.belowcontentdescription` | +| `plone.header` | `plone.portaltop` | | `plone.portaltop` | +| `plone.abovecontenttitle.documentactions` | `plone.belowcontentbody` | `plone.documentactions` | `plone.belowcontent` | +| `plone.abovecontenttitle.socialtags` | `plone.abovecontenttitle` | `plone.socialtags` | `plone.abovecontenttitle` | +| `plone.belowcontentbody.relateditems` | `plone.belowcontentbody` | `plone.relateditems` | `plone.belowcontentbody` | +| `plone.manage_portlets_fallback` | `plone.belowcontent` | | `plone.belowcontent` | +| `plone.belowcontenttitle.documentbyline` | `plone.belowcontenttitle` | `plone.documentbyline` | `plone.belowcontenttitle` | +| `plone.belowcontenttitle.keywords` | `plone.belowcontent` | `plone.keywords` | `plone.belowcontentbody` | +| | `plone.belowcontentbody` | `plone.rights` | `plone.belowcontentbody` | From 9c5cf671381856c2034ca7f74b8236bc2a6ecc21 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 1 Mar 2024 01:02:53 -0800 Subject: [PATCH 155/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 4de0ce2ff..63a7997a1 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 4de0ce2ff115d709a0a1aa41d5c1031b324114c3 +Subproject commit 63a7997a1b7d55ccd86cead9f54cdece46cd7294 From f8bf5fc440c01d2e2de38315efc4e7be63d98d52 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 1 Mar 2024 01:31:18 -0800 Subject: [PATCH 156/810] Remove Linode from Glossary as there is no reference to it anywhere in the docs --- docs/glossary.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/glossary.md b/docs/glossary.md index 6d0156c05..f8de2d4a0 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -54,9 +54,6 @@ Grunt Less A dynamic stylesheet language that can be compiled into {term}`CSS` (Cascading Style Sheets). -Linode - [Linode.com](https://www.linode.com/) is an American privately owned virtual private server provider company based in Galloway, New Jersey, United States. - mxdev [mxdev](https://github.com/mxstack/mxdev) [mɪks dɛv] is a utility that makes it easy to work with Python projects containing lots of packages, and you want to develop only some of those packages. It is designed for developers who use stable version constraints, then layer their customizations on top of that base while using a version control system. From ceb5bdebde845431fd5512a1a7d5025147eac5f4 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 1 Mar 2024 01:50:13 -0800 Subject: [PATCH 157/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 63a7997a1..fe35958ba 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 63a7997a1b7d55ccd86cead9f54cdece46cd7294 +Subproject commit fe35958ba9feb7e37bda1443512229b471054eee From 25aaf25034c55105f1109d0a4dbdb422ef50ff68 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 3 Mar 2024 02:40:59 -0800 Subject: [PATCH 158/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 1771c9c43..ce7bfbef8 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 1771c9c43b63dd0a6b29ab1339b6e8d6330876ab +Subproject commit ce7bfbef8bb2d1fd7388bb8bb384eecb0dc81f81 diff --git a/submodules/volto b/submodules/volto index fe35958ba..7c74a4302 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit fe35958ba9feb7e37bda1443512229b471054eee +Subproject commit 7c74a4302e7ee51bbd8100ee9bbb73bb283de31e From 880777e996aea63e5e0cdc44c7ffc5d7f514cde0 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 4 Mar 2024 14:42:39 -0800 Subject: [PATCH 159/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 7c74a4302..8e08d5ae3 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 7c74a4302e7ee51bbd8100ee9bbb73bb283de31e +Subproject commit 8e08d5ae3327ade6e6d5a13c8efb71d247c8ad1c From f02b7606c47f61e407b97069b98bea634c833b79 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 4 Mar 2024 22:37:54 -0800 Subject: [PATCH 160/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 8e08d5ae3..0baba22c1 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 8e08d5ae3327ade6e6d5a13c8efb71d247c8ad1c +Subproject commit 0baba22c11769bded7eaf832c1650eb27cc22f33 From b24067c5161f8d3f45873aa9adfe4fd87b189965 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 5 Mar 2024 01:41:34 -0800 Subject: [PATCH 161/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 0baba22c1..d2ad25e48 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 0baba22c11769bded7eaf832c1650eb27cc22f33 +Subproject commit d2ad25e4860729e054804e357435979efbc956de From 47cb38112bc7ea6ae67e1bceb7598d6db9e6031d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 5 Mar 2024 02:45:57 -0800 Subject: [PATCH 162/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index d2ad25e48..a2fff7ff4 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit d2ad25e4860729e054804e357435979efbc956de +Subproject commit a2fff7ff4e7e89f6395b1d3c39ab955482bdd7e3 From aec5216f6f3ca5844d6c4be47c4b03f0c2563d46 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 5 Mar 2024 05:51:05 -0800 Subject: [PATCH 163/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index a2fff7ff4..8967cd8ae 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit a2fff7ff4e7e89f6395b1d3c39ab955482bdd7e3 +Subproject commit 8967cd8ae807fad2cf8314f11ad08fed095d3d61 From e320178bc8818b42323d07efb8e1d6927494e07a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 7 Mar 2024 02:23:08 -0800 Subject: [PATCH 164/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 8967cd8ae..7bc30cb15 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 8967cd8ae807fad2cf8314f11ad08fed095d3d61 +Subproject commit 7bc30cb15160b5a18a519c0959df8fb5af07c15a From c1365a7053392fd881a8f1a976c56dcba3fcfa17 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 7 Mar 2024 02:24:22 -0800 Subject: [PATCH 165/810] Update docs/backend/upgrading/version-specific-migration/upgrade-to-60.md --- .../upgrading/version-specific-migration/upgrade-to-60.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md index e57e33481..5149e6335 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md @@ -606,7 +606,7 @@ See also the [TinyMCE 4 to 5 upgrade guide](https://www.tiny.cloud/docs/migratio ## Viewlets Plone 6.0 renames various viewlets or moves them to a different viewlet manager. -The reason for renaming, is that some viewlet names contained the name of a viewlet manager. +This is because some viewlet names contained the name of a viewlet manager. This didn't always match the name of their actual viewlet manager, especially after moving them. Plone 6.0 removes such references from the viewlet names, to avoid confusion. From 113ccc7ea2d5b5aa74b22e727d18de7be1fb3c47 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 7 Mar 2024 02:24:34 -0800 Subject: [PATCH 166/810] Update docs/backend/upgrading/version-specific-migration/upgrade-to-60.md --- .../upgrading/version-specific-migration/upgrade-to-60.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md index 5149e6335..3193ecb1a 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md @@ -608,7 +608,7 @@ See also the [TinyMCE 4 to 5 upgrade guide](https://www.tiny.cloud/docs/migratio Plone 6.0 renames various viewlets or moves them to a different viewlet manager. This is because some viewlet names contained the name of a viewlet manager. This didn't always match the name of their actual viewlet manager, especially after moving them. -Plone 6.0 removes such references from the viewlet names, to avoid confusion. +Plone 6.0 removes such references from the viewlet names to avoid confusion. - Plone 6.0 removes the `plone.documentactions (IDocumentActions)` viewlet manager. In Plone 5.2 it was already empty. - Plone 6.0 adds the `plone.belowcontentdescription (IBelowContentDescription)` viewlet manager. By default this has no viewlets. From 2b5a548d9610422a9f2d1ded080e8247e5e0b050 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 7 Mar 2024 02:25:07 -0800 Subject: [PATCH 167/810] Update docs/backend/upgrading/version-specific-migration/upgrade-to-60.md --- .../upgrading/version-specific-migration/upgrade-to-60.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md index 3193ecb1a..a31ec5afe 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md @@ -610,7 +610,7 @@ This is because some viewlet names contained the name of a viewlet manager. This didn't always match the name of their actual viewlet manager, especially after moving them. Plone 6.0 removes such references from the viewlet names to avoid confusion. -- Plone 6.0 removes the `plone.documentactions (IDocumentActions)` viewlet manager. In Plone 5.2 it was already empty. +- Plone 6.0 removes the `plone.documentactions (IDocumentActions)` viewlet manager. In Plone 5.2 it was already empty. - Plone 6.0 adds the `plone.belowcontentdescription (IBelowContentDescription)` viewlet manager. By default this has no viewlets. - Plone 6.0 removes the `plone.header` viewlet from `plone.portaltop` manager, making it empty. - Plone 6.0 renames the `plone.abovecontenttitle.documentactions` viewlet to `plone.documentactions` and moves it from manager `plone.belowcontentbody` to `plone.belowcontent`. From a35bca324379b4c6ccf449d7495c371f23256346 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 7 Mar 2024 02:25:18 -0800 Subject: [PATCH 168/810] Update docs/backend/upgrading/version-specific-migration/upgrade-to-60.md --- .../upgrading/version-specific-migration/upgrade-to-60.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md index a31ec5afe..ec9fe8c65 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md @@ -617,7 +617,7 @@ Plone 6.0 removes such references from the viewlet names to avoid confusion. - Plone 6.0 renames the `plone.abovecontenttitle.socialtags` viewlet to `plone.socialtags`. It remains in manager `plone.abovecontenttitle`. - Plone 6.0 renames the `plone.belowcontentbody.relateditems` viewlet to `plone.relateditems`. It remains in manager `plone.belowcontentbody`. - Plone 6.0 removes the `plone.manage_portlets_fallback` viewlet from the `plone.belowcontent` manager. -- Plone 6.0 renames the `plone.belowcontenttitle.documentbyline` viewlet to `plone.documentbyline` . It remains in manager `plone.belowcontenttitle`. +- Plone 6.0 renames the `plone.belowcontenttitle.documentbyline` viewlet to `plone.documentbyline`. It remains in manager `plone.belowcontenttitle`. - Plone 6.0 renames the `plone.belowcontenttitle.keywords` viewlet to `plone.keywords` and moves it from manager `plone.belowcontent` to `plone.belowcontentbody`. - Plone 6.0 adds the `plone.rights` viewlet in manager `plone.belowcontentbody`. - Plone 6.0 moves the `plone.footer` viewlet from `plone.app.layout/viewlets` to `plone.app.portlets`. The viewlet remains in manager `plone.portalfooter`. It renders the portlets from the `plone.footerportlets` portlet manager. From cbe41150e63893590d627e8f066fc7336aae6426 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 7 Mar 2024 02:28:56 -0800 Subject: [PATCH 169/810] Tidy up fields.md --- docs/backend/fields.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/backend/fields.md b/docs/backend/fields.md index c87077fbd..02febe3cf 100644 --- a/docs/backend/fields.md +++ b/docs/backend/fields.md @@ -148,7 +148,7 @@ With `plone.autoform` and `plone.supermodel` we can use directives to add inform By default, fields are included in the form regardless of the user's permissions. Fields can be protected using the `read_permission` and `write_permission` directives. The read permission is checked when the field is in display mode, and the write permission is checked when the field is in input mode. -The permission should be given with its Zope 3-style name (such as `cmf.ManagePortal` instead of `Manage portal`). +The permission should be given with its Zope 3-style name, such as `cmf.ManagePortal` instead of `Manage portal`. In this example, the `secret` field is protected by the `cmf.ManagePortal` permission as both a read and write permission. This means that in both display and input modes, the field will only be included in the form for users who have that permission: @@ -165,7 +165,7 @@ class IMySchema(model.Schema): ) ``` -In supermodel XML the directives are `security:read-permission` and +In supermodel XML, the directives are `security:read-permission` and `security:write-permission`: ```xml From 2135a239236b4637efd181eabf7e773044f1544f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 7 Mar 2024 02:36:51 -0800 Subject: [PATCH 170/810] Tidy up schemas.md --- docs/backend/schemas.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/backend/schemas.md b/docs/backend/schemas.md index f51375631..f2169efd9 100644 --- a/docs/backend/schemas.md +++ b/docs/backend/schemas.md @@ -221,7 +221,7 @@ Note this won't have behavior fields added to it at this stage, only the fields ## Using schema directives -With `plone.autoform` and `plone.supermodel` we can use directives to add information to the schema fields. +With `plone.autoform` and `plone.supermodel`, we can use directives to add information to the schema fields. ### Omit fields @@ -269,13 +269,13 @@ In supermodel XML, this can be specified as: ``` -`form:omitted` may be either a single boolean value, or a space-separated list of form_interface:boolean pairs. +`form:omitted` may be either a single boolean value, or a space-separated list of `:` pairs. ### Reorder fields A field's position in the form can be influenced using the `order_before` and `order_after` directives. -In this example, the `not_last` field is placed before the `summary` field even though it is defined afterward: +In this example, the `not_last` field is placed before the `summary` field, even though it is defined afterward: ```{code-block} python :emphasize-lines: 12 @@ -298,10 +298,10 @@ class IMySchema(model.Schema): ) ``` -The value passed to the directive may be either `*` (indicating before or after all fields) or the name of another field. -Use `.fieldname` to refer to field in the current schema or a base schema. -Prefix with the schema name (e.g. `IDublinCore.title`) to refer to a field in another schema. -Use an unprefixed name to refer to a field in the current or the default schema for the form. +The value passed to the directive may be either `*`, indicating before or after all fields, or the name of another field. +Use `<.fieldname>` to refer to the field in the current schema or a base schema. +Prefix with the schema name, such as `IDublinCore.title`, to refer to a field in another schema. +Use an unprefixed name to refer to a field in either the current or default schema for the form. In supermodel XML, the directives are called `form:before` and `form:after`. For example: @@ -323,7 +323,7 @@ Fields can be grouped into fieldsets, which will be rendered within an HTML ` Date: Thu, 7 Mar 2024 02:41:41 -0800 Subject: [PATCH 171/810] Tidy up widgets.md --- docs/backend/widgets.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/backend/widgets.md b/docs/backend/widgets.md index c10786836..52686cb99 100644 --- a/docs/backend/widgets.md +++ b/docs/backend/widgets.md @@ -63,11 +63,11 @@ The main widgets are: - DateTime Picker -(backend-widgets-fields-display-label)= +(backend-widgets-change-a-fields-display-label)= ## Change a field's display mode -A field's widget can be displayed in several modes: +A field's widget can be displayed in several modes. `input` : Allows the user to enter data into the field @@ -81,6 +81,7 @@ A field's widget can be displayed in several modes: ### `plone.autoform` `mode` directive +In the following example, the mode for the `secret` field is set to `hidden` for most forms, but `input` for forms that provide the `IEditForm` interface. ```{code-block} python :emphasize-lines: 6,7 @@ -99,8 +100,6 @@ class IMySchema(model.Schema): ) ``` -In this case the mode for the `secret` field is set to 'hidden' for most forms, but 'input' for forms that provide the IEditForm interface. - The corresponding supermodel XML directive is `form:mode`: ```{code-block} xml @@ -114,7 +113,7 @@ The corresponding supermodel XML directive is `form:mode`: ``` -The mode can be specified briefly if it should be the same for all forms: +The mode can be specified briefly, if it should be the same for all forms: ```{code-block} xml :emphasize-lines: 3 @@ -127,10 +126,10 @@ The mode can be specified briefly if it should be the same for all forms: ``` -In other words, `form:mode` may be either a single mode, or a space-separated list of form_interface:mode pairs. +In other words, `form:mode` may be either a single mode, or a space-separated list of `:` pairs. -(backend-widgets-fields-widget-label)= +(backend-widgets-change-a-fields-widget-label)= ## Change a field's widget From aae510aebfa0871c4c1a671385162ba6a2fe5915 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 7 Mar 2024 02:49:29 -0800 Subject: [PATCH 172/810] Fix cross-references, and tidy up forms.md --- docs/backend/schemas.md | 2 +- docs/classic-ui/forms.md | 30 +++++++++++++----------------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/docs/backend/schemas.md b/docs/backend/schemas.md index f2169efd9..cb5e4237b 100644 --- a/docs/backend/schemas.md +++ b/docs/backend/schemas.md @@ -219,7 +219,7 @@ Note this won't have behavior fields added to it at this stage, only the fields (backend-schemas-directives-label)= -## Using schema directives +## Schema directives With `plone.autoform` and `plone.supermodel`, we can use directives to add information to the schema fields. diff --git a/docs/classic-ui/forms.md b/docs/classic-ui/forms.md index d10e44ae4..fcb35e8cc 100644 --- a/docs/classic-ui/forms.md +++ b/docs/classic-ui/forms.md @@ -120,7 +120,8 @@ schema = IMyForm If your form is not bound to an object (such as a Dexterity object), set `ignoreContext = True`. -(classic-ui-forms-autoform-label)= +(classic-ui-controlling-form-presentation-label)= + ## Controlling form presentation Directives can be specified in the schema to control aspects of form presentation. @@ -130,25 +131,18 @@ Directives can be specified in the schema to control aspects of form presentatio See the corresponding chapters to learn how to control field and widget presentation in a form. ```{seealso} -{ref}`Field permission ` -``` -```{seealso} -{ref}`Ordering, omitting, grouping ` -``` -```{seealso} -{ref}`Changing a field's display mode ` -``` -```{seealso} -{ref}`Changing a field's widget ` +- {ref}`backend-fields-schema-autoform-permission` +- {ref}`backend-schemas-directives-label` +- {ref}`backend-widgets-change-a-fields-display-label` +- {ref}`backend-widgets-change-a-fields-widget-label` ``` ### Display Forms - Sometimes rather than rendering a form for data entry, you want to display stored values based on the same schema. This can be done using a "display form". -The display form renders each field's widget in "display mode" which means that it shows the field value in read-only form rather than as a form input. +The display form renders each field's widget in "display mode", which means that it shows the field value in read-only form rather than as a form input. To use the display form, create a view that extends `WidgetsView` like this: @@ -158,8 +152,6 @@ from plone.autoform.view import WidgetsView class MyView(WidgetsView): schema = IMySchema additionalSchemata = (ISchemaOne, ISchemaTwo,) - - # ... ``` To render the form, do not override `__call__()`. @@ -167,8 +159,12 @@ Instead, either implement the `render()` method, set an `index` attribute to a p In the template, you can use the following variables: -- `view/w` is a dictionary of all widgets, including those from non-default fieldsets (by contrast, the `widgets` variable contains only those widgets in the default fieldset). The keys are the field names, and the values are widget instances. To render a widget (in display mode), you can do `tal:replace="structure view/w/myfield/render" />`. -- `view/fieldsets` is a dictionary of all fieldsets (not including the default fieldset, in other words, those widgets not placed into a fieldset. The keys are the fieldset names, and the values are the fieldset form instances, which in turn have variables like `widgets` given a list of all widgets. +- `view/w` is a dictionary of all widgets, including those from non-default fieldsets. + By contrast, the `widgets` variable contains only those widgets in the default fieldset. + The keys are the field names, and the values are widget instances. + To render a widget (in display mode), you can do `tal:replace="structure view/w/myfield/render" />`. +- `view/fieldsets` is a dictionary of all fieldsets not including the default fieldset, in other words, those widgets not placed into a fieldset. + The keys are the fieldset names, and the values are the fieldset form instances, which in turn have variables, such as `widgets`, given a list of all widgets. (classic-ui-forms-dexterity-add-edit-forms-label)= From 9beede2069c70259c1f94f45ba26f540163d20cc Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 7 Mar 2024 03:00:18 -0800 Subject: [PATCH 173/810] Tidy up syntax and style formatting --- .../upgrade-to-60.md | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md index ec9fe8c65..33ceac144 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md @@ -610,22 +610,29 @@ This is because some viewlet names contained the name of a viewlet manager. This didn't always match the name of their actual viewlet manager, especially after moving them. Plone 6.0 removes such references from the viewlet names to avoid confusion. -- Plone 6.0 removes the `plone.documentactions (IDocumentActions)` viewlet manager. In Plone 5.2 it was already empty. -- Plone 6.0 adds the `plone.belowcontentdescription (IBelowContentDescription)` viewlet manager. By default this has no viewlets. -- Plone 6.0 removes the `plone.header` viewlet from `plone.portaltop` manager, making it empty. -- Plone 6.0 renames the `plone.abovecontenttitle.documentactions` viewlet to `plone.documentactions` and moves it from manager `plone.belowcontentbody` to `plone.belowcontent`. -- Plone 6.0 renames the `plone.abovecontenttitle.socialtags` viewlet to `plone.socialtags`. It remains in manager `plone.abovecontenttitle`. -- Plone 6.0 renames the `plone.belowcontentbody.relateditems` viewlet to `plone.relateditems`. It remains in manager `plone.belowcontentbody`. -- Plone 6.0 removes the `plone.manage_portlets_fallback` viewlet from the `plone.belowcontent` manager. -- Plone 6.0 renames the `plone.belowcontenttitle.documentbyline` viewlet to `plone.documentbyline`. It remains in manager `plone.belowcontenttitle`. -- Plone 6.0 renames the `plone.belowcontenttitle.keywords` viewlet to `plone.keywords` and moves it from manager `plone.belowcontent` to `plone.belowcontentbody`. -- Plone 6.0 adds the `plone.rights` viewlet in manager `plone.belowcontentbody`. -- Plone 6.0 moves the `plone.footer` viewlet from `plone.app.layout/viewlets` to `plone.app.portlets`. The viewlet remains in manager `plone.portalfooter`. It renders the portlets from the `plone.footerportlets` portlet manager. +- Plone 6.0 removes the `plone.documentactions` (`IDocumentActions`) viewlet manager. + In Plone 5.2 it was already empty. +- Plone 6.0 adds the `plone.belowcontentdescription` (`IBelowContentDescription`) viewlet manager. + By default this has no viewlets. +- Plone 6.0 removes the `plone.header` viewlet from `plone.portaltop` manager, making it empty. +- Plone 6.0 renames the `plone.abovecontenttitle.documentactions` viewlet to `plone.documentactions`, and moves it from manager `plone.belowcontentbody` to `plone.belowcontent`. +- Plone 6.0 renames the `plone.abovecontenttitle.socialtags` viewlet to `plone.socialtags`. + It remains in manager `plone.abovecontenttitle`. +- Plone 6.0 renames the `plone.belowcontentbody.relateditems` viewlet to `plone.relateditems`. + It remains in manager `plone.belowcontentbody`. +- Plone 6.0 removes the `plone.manage_portlets_fallback` viewlet from the `plone.belowcontent` manager. +- Plone 6.0 renames the `plone.belowcontenttitle.documentbyline` viewlet to `plone.documentbyline`. + It remains in manager `plone.belowcontenttitle`. +- Plone 6.0 renames the `plone.belowcontenttitle.keywords` viewlet to `plone.keywords`, and moves it from manager `plone.belowcontent` to `plone.belowcontentbody`. +- Plone 6.0 adds the `plone.rights` viewlet in manager `plone.belowcontentbody`. +- Plone 6.0 moves the `plone.footer` viewlet from `plone.app.layout/viewlets` to `plone.app.portlets`. + The viewlet remains in manager `plone.portalfooter`. + It renders the portlets from the `plone.footerportlets` portlet manager. This is the same information in table form. You can toggle navigation to make more of the table visible. -:::{table} Viewlet changes from 5.2 to 6.0 +```{table} Viewlet changes from 5.2 to 6.0 | 5.2 viewlet name | 5.2 viewlet manager | 6.0 viewlet name | 6.0 viewlet manager | | ---------------- | ------------------- | ---------------- | ------------------- | @@ -639,3 +646,4 @@ You can toggle navigation to make more of the table visible. | `plone.belowcontenttitle.documentbyline` | `plone.belowcontenttitle` | `plone.documentbyline` | `plone.belowcontenttitle` | | `plone.belowcontenttitle.keywords` | `plone.belowcontent` | `plone.keywords` | `plone.belowcontentbody` | | | `plone.belowcontentbody` | `plone.rights` | `plone.belowcontentbody` | +``` \ No newline at end of file From a22db286ef58ac65ffcd73e544d0d49dfaf9ab4b Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Thu, 7 Mar 2024 12:45:49 +0100 Subject: [PATCH 174/810] Viewlets upgrade: move one item below the table, as it is a separate issue. --- .../version-specific-migration/upgrade-to-60.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md index 33ceac144..af5621429 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md @@ -625,9 +625,6 @@ Plone 6.0 removes such references from the viewlet names to avoid confusion. It remains in manager `plone.belowcontenttitle`. - Plone 6.0 renames the `plone.belowcontenttitle.keywords` viewlet to `plone.keywords`, and moves it from manager `plone.belowcontent` to `plone.belowcontentbody`. - Plone 6.0 adds the `plone.rights` viewlet in manager `plone.belowcontentbody`. -- Plone 6.0 moves the `plone.footer` viewlet from `plone.app.layout/viewlets` to `plone.app.portlets`. - The viewlet remains in manager `plone.portalfooter`. - It renders the portlets from the `plone.footerportlets` portlet manager. This is the same information in table form. You can toggle navigation to make more of the table visible. @@ -646,4 +643,8 @@ You can toggle navigation to make more of the table visible. | `plone.belowcontenttitle.documentbyline` | `plone.belowcontenttitle` | `plone.documentbyline` | `plone.belowcontenttitle` | | `plone.belowcontenttitle.keywords` | `plone.belowcontent` | `plone.keywords` | `plone.belowcontentbody` | | | `plone.belowcontentbody` | `plone.rights` | `plone.belowcontentbody` | -``` \ No newline at end of file +``` + +One final change is that Plone 6.0 moves the `plone.footer` viewlet from `plone.app.layout/viewlets` to `plone.app.portlets`. +The viewlet remains in manager `plone.portalfooter`. +It renders the portlets from the `plone.footerportlets` portlet manager. From 05e2274fe53564a610e983f95c0b15358061da85 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Thu, 7 Mar 2024 12:50:18 +0100 Subject: [PATCH 175/810] Viewlets upgrade: make table less wide by removing 'plone.' from all cells. --- .../upgrade-to-60.md | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md index af5621429..0d6d89bda 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md @@ -626,23 +626,25 @@ Plone 6.0 removes such references from the viewlet names to avoid confusion. - Plone 6.0 renames the `plone.belowcontenttitle.keywords` viewlet to `plone.keywords`, and moves it from manager `plone.belowcontent` to `plone.belowcontentbody`. - Plone 6.0 adds the `plone.rights` viewlet in manager `plone.belowcontentbody`. -This is the same information in table form. +The names in the following table have had the namespace `plone.` removed from them for display purposes only. +In your code, you should use the object's `plone.` namespace as a prefix. +This table show the same information, but in table form. You can toggle navigation to make more of the table visible. ```{table} Viewlet changes from 5.2 to 6.0 | 5.2 viewlet name | 5.2 viewlet manager | 6.0 viewlet name | 6.0 viewlet manager | | ---------------- | ------------------- | ---------------- | ------------------- | -|| `plone.documentactions` | | | -|||| `plone.belowcontentdescription` | -| `plone.header` | `plone.portaltop` | | `plone.portaltop` | -| `plone.abovecontenttitle.documentactions` | `plone.belowcontentbody` | `plone.documentactions` | `plone.belowcontent` | -| `plone.abovecontenttitle.socialtags` | `plone.abovecontenttitle` | `plone.socialtags` | `plone.abovecontenttitle` | -| `plone.belowcontentbody.relateditems` | `plone.belowcontentbody` | `plone.relateditems` | `plone.belowcontentbody` | -| `plone.manage_portlets_fallback` | `plone.belowcontent` | | `plone.belowcontent` | -| `plone.belowcontenttitle.documentbyline` | `plone.belowcontenttitle` | `plone.documentbyline` | `plone.belowcontenttitle` | -| `plone.belowcontenttitle.keywords` | `plone.belowcontent` | `plone.keywords` | `plone.belowcontentbody` | -| | `plone.belowcontentbody` | `plone.rights` | `plone.belowcontentbody` | +|| `documentactions` | | | +|||| `belowcontentdescription` | +| `header` | `portaltop` | | `portaltop` | +| `abovecontenttitle.documentactions` | `belowcontentbody` | `documentactions` | `belowcontent` | +| `abovecontenttitle.socialtags` | `abovecontenttitle` | `socialtags` | `abovecontenttitle` | +| `belowcontentbody.relateditems` | `belowcontentbody` | `relateditems` | `belowcontentbody` | +| `manage_portlets_fallback` | `belowcontent` | | `belowcontent` | +| `belowcontenttitle.documentbyline` | `belowcontenttitle` | `documentbyline` | `belowcontenttitle` | +| `belowcontenttitle.keywords` | `belowcontent` | `keywords` | `belowcontentbody` | +| | `belowcontentbody` | `rights` | `belowcontentbody` | ``` One final change is that Plone 6.0 moves the `plone.footer` viewlet from `plone.app.layout/viewlets` to `plone.app.portlets`. From 5dbcb72a115ce703945d36093c79c2e0b5afeaa2 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 7 Mar 2024 03:57:51 -0800 Subject: [PATCH 176/810] `u"string"` is not necessary in Python 3 --- docs/backend/fields.md | 2 +- docs/backend/schemas.md | 16 ++++++++-------- docs/backend/widgets.md | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/backend/fields.md b/docs/backend/fields.md index 02febe3cf..ec308576e 100644 --- a/docs/backend/fields.md +++ b/docs/backend/fields.md @@ -161,7 +161,7 @@ class IMySchema(model.Schema): form.read_permission(secret="cmf.ManagePortal") form.write_permission(secret="cmf.ManagePortal") secret = schema.TextLine( - title = u"Secret", + title = "Secret", ) ``` diff --git a/docs/backend/schemas.md b/docs/backend/schemas.md index cb5e4237b..a9f9318ed 100644 --- a/docs/backend/schemas.md +++ b/docs/backend/schemas.md @@ -241,13 +241,13 @@ class IMySchema(model.Schema): form.omitted("dummy") dummy = schema.Text( - title=u"Dummy" + title="Dummy" ) form.omitted("edit_only") form.no_omit(IEditForm, "edit_only") edit_only = schema.TextLine( - title = u"Only included on edit forms", + title = "Only included on edit forms", ) ``` @@ -287,14 +287,14 @@ from plone.autoform import directives as form class IMySchema(model.Schema): summary = schema.Text( - title=u"Summary", - description=u"Summary of the body", + title="Summary", + description="Summary of the body", readonly=True ) form.order_before(not_last="summary") not_last = schema.TextLine( - title=u"Not last", + title="Not last", ) ``` @@ -332,16 +332,16 @@ from plone.autoform import directives as form class IMySchema(model.Schema): model.fieldset("extra", - label=u"Extra info", + label="Extra info", fields=["footer", "dummy"] ) footer = schema.Text( - title=u"Footer text", + title="Footer text", ) dummy = schema.Text( - title=u"Dummy" + title="Dummy" ) ``` diff --git a/docs/backend/widgets.md b/docs/backend/widgets.md index 52686cb99..9e535b1d7 100644 --- a/docs/backend/widgets.md +++ b/docs/backend/widgets.md @@ -95,8 +95,8 @@ class IMySchema(model.Schema): form.mode(secret="hidden") form.mode(IEditForm, secret="input") secret = schema.TextLine( - title=u"Secret", - default=u"Secret stuff (except on edit forms)" + title="Secret", + default="Secret stuff (except on edit forms)" ) ``` From f2b36934ad759933dec63569189ad938bacd3bc9 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 7 Mar 2024 04:09:54 -0800 Subject: [PATCH 177/810] grammar --- .../upgrading/version-specific-migration/upgrade-to-60.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md index 0d6d89bda..75e4abe76 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md @@ -628,7 +628,7 @@ Plone 6.0 removes such references from the viewlet names to avoid confusion. The names in the following table have had the namespace `plone.` removed from them for display purposes only. In your code, you should use the object's `plone.` namespace as a prefix. -This table show the same information, but in table form. +This table shows the same information, but in tabular form. You can toggle navigation to make more of the table visible. ```{table} Viewlet changes from 5.2 to 6.0 From 64ad5a4cf0b423fa581e724ddcb371f78def56a1 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Thu, 7 Mar 2024 14:20:26 +0100 Subject: [PATCH 178/810] Viewlets upgrade: move viewlet manager changes below the table. --- .../upgrading/version-specific-migration/index.md | 1 + .../version-specific-migration/upgrade-to-60.md | 13 +++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/backend/upgrading/version-specific-migration/index.md b/docs/backend/upgrading/version-specific-migration/index.md index c210c3af0..7f94ce1f6 100644 --- a/docs/backend/upgrading/version-specific-migration/index.md +++ b/docs/backend/upgrading/version-specific-migration/index.md @@ -27,4 +27,5 @@ upgrade-to-python3 upgrade-zodb-to-python3 upgrade-to-60 migrate-to-volto +changelog ``` diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md index 75e4abe76..e875e1328 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md @@ -610,10 +610,6 @@ This is because some viewlet names contained the name of a viewlet manager. This didn't always match the name of their actual viewlet manager, especially after moving them. Plone 6.0 removes such references from the viewlet names to avoid confusion. -- Plone 6.0 removes the `plone.documentactions` (`IDocumentActions`) viewlet manager. - In Plone 5.2 it was already empty. -- Plone 6.0 adds the `plone.belowcontentdescription` (`IBelowContentDescription`) viewlet manager. - By default this has no viewlets. - Plone 6.0 removes the `plone.header` viewlet from `plone.portaltop` manager, making it empty. - Plone 6.0 renames the `plone.abovecontenttitle.documentactions` viewlet to `plone.documentactions`, and moves it from manager `plone.belowcontentbody` to `plone.belowcontent`. - Plone 6.0 renames the `plone.abovecontenttitle.socialtags` viewlet to `plone.socialtags`. @@ -635,8 +631,6 @@ You can toggle navigation to make more of the table visible. | 5.2 viewlet name | 5.2 viewlet manager | 6.0 viewlet name | 6.0 viewlet manager | | ---------------- | ------------------- | ---------------- | ------------------- | -|| `documentactions` | | | -|||| `belowcontentdescription` | | `header` | `portaltop` | | `portaltop` | | `abovecontenttitle.documentactions` | `belowcontentbody` | `documentactions` | `belowcontent` | | `abovecontenttitle.socialtags` | `abovecontenttitle` | `socialtags` | `abovecontenttitle` | @@ -647,6 +641,13 @@ You can toggle navigation to make more of the table visible. | | `belowcontentbody` | `rights` | `belowcontentbody` | ``` +Plone 6.0 makes changes to two viewlet managers: + +- Plone 6.0 removes the `plone.documentactions` (`IDocumentActions`) viewlet manager. + In Plone 5.2 it was already empty. +- Plone 6.0 adds the `plone.belowcontentdescription` (`IBelowContentDescription`) viewlet manager. + By default this has no viewlets. + One final change is that Plone 6.0 moves the `plone.footer` viewlet from `plone.app.layout/viewlets` to `plone.app.portlets`. The viewlet remains in manager `plone.portalfooter`. It renders the portlets from the `plone.footerportlets` portlet manager. From 998528d204339d3e7308eda102f0d4bf61105163 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Thu, 7 Mar 2024 14:21:45 +0100 Subject: [PATCH 179/810] Viewlets upgrade: no longer say how to make more of the table visible. It should be fully visible now. --- .../upgrading/version-specific-migration/upgrade-to-60.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md index e875e1328..434f68516 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md @@ -625,7 +625,6 @@ Plone 6.0 removes such references from the viewlet names to avoid confusion. The names in the following table have had the namespace `plone.` removed from them for display purposes only. In your code, you should use the object's `plone.` namespace as a prefix. This table shows the same information, but in tabular form. -You can toggle navigation to make more of the table visible. ```{table} Viewlet changes from 5.2 to 6.0 From aadc8cb73575e539b2462a194863e059d4d1b97e Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Thu, 7 Mar 2024 14:22:53 +0100 Subject: [PATCH 180/810] Removed mistakenly added changelog from upgrade guide. I was testing something out. --- docs/backend/upgrading/version-specific-migration/index.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/backend/upgrading/version-specific-migration/index.md b/docs/backend/upgrading/version-specific-migration/index.md index 7f94ce1f6..c210c3af0 100644 --- a/docs/backend/upgrading/version-specific-migration/index.md +++ b/docs/backend/upgrading/version-specific-migration/index.md @@ -27,5 +27,4 @@ upgrade-to-python3 upgrade-zodb-to-python3 upgrade-to-60 migrate-to-volto -changelog ``` From 816ee620e66bfd1c45dcba90088bd4054307088e Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Thu, 7 Mar 2024 14:26:13 +0100 Subject: [PATCH 181/810] Do not call virtualenv --clear in our Makefile. This would remove the current directory if called as fallback. This fixes https://github.com/plone/documentation/issues/1635 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dd72fec8c..ac8d6062a 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ distclean: ## Clean docs build directory and Python virtual environment bin/python: - python3 -m venv . || virtualenv --clear --python=python3 . + python3 -m venv . bin/pip install -r requirements-initial.txt bin/pip install -r requirements.txt From c3697915685853a7fc4b550501321507c42fbe7a Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Fri, 8 Mar 2024 12:36:59 +0100 Subject: [PATCH 182/810] feat(upgrade): mention the boolean fields changes See the context in https://github.com/zopefoundation/zope.schema/issues/104 --- .../upgrading/version-specific-migration/upgrade-to-60.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md index 434f68516..f5baf442e 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md @@ -650,3 +650,8 @@ Plone 6.0 makes changes to two viewlet managers: One final change is that Plone 6.0 moves the `plone.footer` viewlet from `plone.app.layout/viewlets` to `plone.app.portlets`. The viewlet remains in manager `plone.portalfooter`. It renders the portlets from the `plone.footerportlets` portlet manager. + +## Boolean fields + +Since `zope.schema==6.1.0` all `zope.schema.Bool` fields need to have a `required=False` attribute, +otherwise, you will not be able to save the form without marking the checkbox, which effectively turns that field to be always `True`. From 6f69a476c789309e5ec9569d3c62aa8fbf329a1b Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Fri, 8 Mar 2024 12:47:31 +0100 Subject: [PATCH 183/810] Update docs/classic-ui/theming/from-scratch.md Co-authored-by: Yuri --- docs/classic-ui/theming/from-scratch.md | 33 +++---------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/docs/classic-ui/theming/from-scratch.md b/docs/classic-ui/theming/from-scratch.md index 7fb722fe5..c9477d901 100644 --- a/docs/classic-ui/theming/from-scratch.md +++ b/docs/classic-ui/theming/from-scratch.md @@ -138,35 +138,10 @@ To do so, follow this guide. - Create a new CSS file in your theme, such as the following. ```scss - // plone variables (used in toolbar) - // Plone specific colors - //colors - $state-draft-color: #fab82a!default; // lime-yellow //draft is visible - $state-pending-color: #e2e721!default; // orange - $state-private-color: #c4183c!default; // red - $state-internal-color: #fab82a!default; // is draft - $state-internally-published-color: #883dfa!default; // is intranet - $plone-link-color: #007bb1!default; //plone blue made slightly darker for wcag 2.0 - $spacer: 1rem!default; - - // Toolbar - $plone-toolbar-bg: rgba(0, 0, 0, 0.9); - $plone-toolbar-submenu-bg: rgba(20, 20, 20, 0.95); - $plone-toolbar-font-primary: "Roboto Condensed", sans-serif; - $plone-toolbar-font-secondary: "Roboto", sans-serif; - $plone-toolbar-separator-color: rgba(255, 255, 255, 0.17); - $plone-toolbar-link: $plone-link-color; - $plone-toolbar-text-color: rgba(255, 255, 255, 0.9); - $plone-toolbar-submenu-text-color: #fff; - $plone-toolbar-submenu-header-color: lighten(#000, 80%); - - $plone-toolbar-locked-color: var(--bs-warning); // is intranet - - $plone-toolbar-width: 220px; - $plone-toolbar-width-collapsed: calc($spacer * 2.25); - $plone-toolbar-top-height: calc($spacer * 2.5); - - @import "bootstrap/scss/bootstrap"; +import "@plone/plonetheme-barceloneta-base/scss/variables.colors.plone"; +import "@plone/plonetheme-barceloneta-base/scss/variables.colors.dark.plone"; +import "@plone/plonetheme-barceloneta-base/scss/root_variables"; +import "bootstrap/scss/bootstrap"; @import "@plone/plonetheme-barceloneta-base/scss/toolbar"; @import "@plone/plonetheme-barceloneta-base/scss/controlpanels"; From 05ea28559962a29434df9b9f8cbaceb3cd4d9a02 Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Fri, 8 Mar 2024 12:48:55 +0100 Subject: [PATCH 184/810] Update docs/classic-ui/theming/from-scratch.md --- docs/classic-ui/theming/from-scratch.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/classic-ui/theming/from-scratch.md b/docs/classic-ui/theming/from-scratch.md index c9477d901..6b4ef2fc0 100644 --- a/docs/classic-ui/theming/from-scratch.md +++ b/docs/classic-ui/theming/from-scratch.md @@ -138,10 +138,10 @@ To do so, follow this guide. - Create a new CSS file in your theme, such as the following. ```scss -import "@plone/plonetheme-barceloneta-base/scss/variables.colors.plone"; -import "@plone/plonetheme-barceloneta-base/scss/variables.colors.dark.plone"; -import "@plone/plonetheme-barceloneta-base/scss/root_variables"; -import "bootstrap/scss/bootstrap"; + import "@plone/plonetheme-barceloneta-base/scss/variables.colors.plone"; + import "@plone/plonetheme-barceloneta-base/scss/variables.colors.dark.plone"; + import "@plone/plonetheme-barceloneta-base/scss/root_variables"; + import "bootstrap/scss/bootstrap"; @import "@plone/plonetheme-barceloneta-base/scss/toolbar"; @import "@plone/plonetheme-barceloneta-base/scss/controlpanels"; From b1e1c74a0239b70da47a1d34368a15d7e35c75e6 Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Fri, 8 Mar 2024 12:50:12 +0100 Subject: [PATCH 185/810] Update docs/classic-ui/theming/from-scratch.md --- docs/classic-ui/theming/from-scratch.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/classic-ui/theming/from-scratch.md b/docs/classic-ui/theming/from-scratch.md index 6b4ef2fc0..688431e6c 100644 --- a/docs/classic-ui/theming/from-scratch.md +++ b/docs/classic-ui/theming/from-scratch.md @@ -138,10 +138,10 @@ To do so, follow this guide. - Create a new CSS file in your theme, such as the following. ```scss - import "@plone/plonetheme-barceloneta-base/scss/variables.colors.plone"; - import "@plone/plonetheme-barceloneta-base/scss/variables.colors.dark.plone"; - import "@plone/plonetheme-barceloneta-base/scss/root_variables"; - import "bootstrap/scss/bootstrap"; + @import "@plone/plonetheme-barceloneta-base/scss/variables.colors.plone"; + @import "@plone/plonetheme-barceloneta-base/scss/variables.colors.dark.plone"; + @import "@plone/plonetheme-barceloneta-base/scss/root_variables"; + @import "bootstrap/scss/bootstrap"; @import "@plone/plonetheme-barceloneta-base/scss/toolbar"; @import "@plone/plonetheme-barceloneta-base/scss/controlpanels"; From c9463747982240f8d9666fef26295f431b6f5749 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 9 Mar 2024 11:28:25 -0800 Subject: [PATCH 186/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index ce7bfbef8..4287932ce 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit ce7bfbef8bb2d1fd7388bb8bb384eecb0dc81f81 +Subproject commit 4287932cefc9b4a6d901321b88c0b044330b2704 diff --git a/submodules/volto b/submodules/volto index 7bc30cb15..16ffad6a6 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 7bc30cb15160b5a18a519c0959df8fb5af07c15a +Subproject commit 16ffad6a65792fd2f8d39be44f47ad1e692359a2 From 8578612cace95438c88272f71e039707efd89ebe Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 10 Mar 2024 20:19:56 -0700 Subject: [PATCH 187/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 16ffad6a6..03b30f981 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 16ffad6a65792fd2f8d39be44f47ad1e692359a2 +Subproject commit 03b30f9817d0883f27b82bf789f6a6225b1aaec3 From fdadb8d652449a65397396c1d4d1bb78af502c09 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 12 Mar 2024 05:00:12 -0700 Subject: [PATCH 188/810] Add tip for how to avoid entering prompts for the cookiecutter --- docs/install/create-project.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/install/create-project.md b/docs/install/create-project.md index 311af5403..396f8447a 100644 --- a/docs/install/create-project.md +++ b/docs/install/create-project.md @@ -228,6 +228,10 @@ You will be presented with a series of prompts. You can accept the default values in square brackets (`[default-option]`) by hitting the {kbd}`Enter` key, or enter your preferred values. For ease of documentation, we will use the default values. +```{tip} +See the cookiecutter's README for how to [Use options to avoid prompts](https://github.com/collective/cookiecutter-plone-starter/?tab=readme-ov-file#use-options-to-avoid-prompts). +``` + (avoid-plone-core-package-names)= ```{important} From e0fa9c3e656dda58a23025cf9b6b5c967c76b250 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 12 Mar 2024 23:11:41 -0700 Subject: [PATCH 189/810] Update link to Classic UI demo --- docs/install/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install/index.md b/docs/install/index.md index fbe83381b..fa70cc81d 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -21,7 +21,7 @@ In this part of the documentation, you can find how to {ref}`try Plone Date: Tue, 12 Mar 2024 23:48:46 -0700 Subject: [PATCH 190/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 03b30f981..2db7d9704 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 03b30f9817d0883f27b82bf789f6a6225b1aaec3 +Subproject commit 2db7d9704d7485d4da99016755a6d8ac5efeda89 From e34f141b8a39a1e4bee9bda1fc8b02681042586c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 13 Mar 2024 21:17:57 -0700 Subject: [PATCH 191/810] Bump all the versions, add comment referring to open issue --- .github/workflows/build_deploy.yml | 14 +++++++------- .github/workflows/test.yml | 6 +++--- .github/workflows/update_submodule.yml | 1 + 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build_deploy.yml b/.github/workflows/build_deploy.yml index fcae3efb0..c62f25b7f 100644 --- a/.github/workflows/build_deploy.yml +++ b/.github/workflows/build_deploy.yml @@ -15,13 +15,13 @@ jobs: name: docs.plone.org url: https://docs.plone.org steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Graphviz - uses: ts-graphviz/setup-graphviz@v1 - - name: Set up Python 3.10 - uses: actions/setup-python@v4 + uses: ts-graphviz/setup-graphviz@v2 + - name: Set up Python 3.12 + uses: actions/setup-python@v5 with: - python-version: '3.10' + python-version: '3.12' cache: 'pip' - name: Install dependencies run: | @@ -39,11 +39,11 @@ jobs: run: make deploy - name: Use Node.js ${{ env.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ env.node-version }} - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v3 name: Install pnpm with: version: 8 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f99fc8cab..1beb30d1f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,12 +6,12 @@ jobs: if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: "3.10" + python-version: "3.12" - name: Install dependencies run: | diff --git a/.github/workflows/update_submodule.yml b/.github/workflows/update_submodule.yml index 1161b2a0b..7d95cc5ae 100644 --- a/.github/workflows/update_submodule.yml +++ b/.github/workflows/update_submodule.yml @@ -1,3 +1,4 @@ +# See https://github.com/plone/documentation/issues/1214 for current status name: Get latest version of submodules and push back to 6.0 branch on: From 3ce9bb2556b25321d7e36995c738946c176bfeaa Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 14 Mar 2024 14:38:19 -0700 Subject: [PATCH 192/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 4287932ce..e62bea212 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 4287932cefc9b4a6d901321b88c0b044330b2704 +Subproject commit e62bea2121d929d9c35298e7e5841332bd1dcbc5 diff --git a/submodules/volto b/submodules/volto index 2db7d9704..0deb876b3 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 2db7d9704d7485d4da99016755a6d8ac5efeda89 +Subproject commit 0deb876b34bcd698dc46282884ce5417aeae0fce From 8ee24effddd2b789e2fe100d4c90029d997aae3d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 15 Mar 2024 00:07:43 -0700 Subject: [PATCH 193/810] `https://classic.demo.plone.org` flip-flopped --- docs/install/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install/index.md b/docs/install/index.md index fa70cc81d..fbe83381b 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -21,7 +21,7 @@ In this part of the documentation, you can find how to {ref}`try Plone Date: Sun, 17 Mar 2024 02:28:08 -0700 Subject: [PATCH 194/810] Add `pnpm workspace` to glossary. --- docs/glossary.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/glossary.md b/docs/glossary.md index f8de2d4a0..9b90cf0d2 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -701,4 +701,13 @@ Nick predicate predicates In programming, a predicate is a test which returns `true` or `false`. + +pnpm workspace +workspace + pnpm has built-in support for monorepositories (also known as multi-package repositories, multi-project repositories, or monolithic repositories). + Workspaces provide support to manage multiple packages from your local file system from within a singular top-level, root package. + By defining a single `package.json` file at the root of the repository and specifying the individual packages as workspaces, pnpm treats them as interdependent projects. + + When you run `pnpm install` at the root of the repository, pnpm installs dependencies for all workspaces, ensuring consistency across the entire project. + This centralized approach streamlines development, facilitates code sharing, and simplifies the maintenance of complex projects. ``` From 604981f4c71510e9a45da8cbe485a95f762dd4b7 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 17 Mar 2024 03:12:13 -0700 Subject: [PATCH 195/810] Use correct filename for pnpm workspace definition --- docs/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/glossary.md b/docs/glossary.md index 9b90cf0d2..ddfc0fb5d 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -706,7 +706,7 @@ pnpm workspace workspace pnpm has built-in support for monorepositories (also known as multi-package repositories, multi-project repositories, or monolithic repositories). Workspaces provide support to manage multiple packages from your local file system from within a singular top-level, root package. - By defining a single `package.json` file at the root of the repository and specifying the individual packages as workspaces, pnpm treats them as interdependent projects. + By defining a single `pnpm-workspace.yaml` file at the root of the repository and specifying the individual packages as workspaces, pnpm treats them as interdependent projects. When you run `pnpm install` at the root of the repository, pnpm installs dependencies for all workspaces, ensuring consistency across the entire project. This centralized approach streamlines development, facilitates code sharing, and simplifies the maintenance of complex projects. From baefcd4857dba0af00f843947fcfdf76f7090a44 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 17 Mar 2024 03:24:09 -0700 Subject: [PATCH 196/810] Remove problematic sentence for pnpm workspace Add ESLint term --- docs/glossary.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/glossary.md b/docs/glossary.md index ddfc0fb5d..fca350fcc 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -706,8 +706,11 @@ pnpm workspace workspace pnpm has built-in support for monorepositories (also known as multi-package repositories, multi-project repositories, or monolithic repositories). Workspaces provide support to manage multiple packages from your local file system from within a singular top-level, root package. - By defining a single `pnpm-workspace.yaml` file at the root of the repository and specifying the individual packages as workspaces, pnpm treats them as interdependent projects. When you run `pnpm install` at the root of the repository, pnpm installs dependencies for all workspaces, ensuring consistency across the entire project. This centralized approach streamlines development, facilitates code sharing, and simplifies the maintenance of complex projects. + +ESLint + [ESLint](https://eslint.org/) statically analyzes your code to quickly find problems. + It is built into most text editors and you can run ESLint as part of your continuous integration pipeline. ``` From 3cda00feb50ee42f491ebf7d0ca29376f9677f81 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 17 Mar 2024 03:28:54 -0700 Subject: [PATCH 197/810] Add terms for Stylelint and Prettier --- docs/glossary.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/glossary.md b/docs/glossary.md index fca350fcc..b4d1ab5fd 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -713,4 +713,10 @@ workspace ESLint [ESLint](https://eslint.org/) statically analyzes your code to quickly find problems. It is built into most text editors and you can run ESLint as part of your continuous integration pipeline. + +Stylelint + [Stylelint](https://stylelint.io/) is a CSS linter that helps you avoid errors and enforce conventions. + +Prettier + [Prettier](https://prettier.io/) is an opinionated code formatter. ``` From 3dd903a82a9122111c5a3f2cff246385e382d0dc Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 17 Mar 2024 03:48:39 -0700 Subject: [PATCH 198/810] Add GitHub workflow term to glossary --- docs/glossary.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/glossary.md b/docs/glossary.md index b4d1ab5fd..9f25c8c72 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -719,4 +719,8 @@ Stylelint Prettier [Prettier](https://prettier.io/) is an opinionated code formatter. + +GitHub workflow +GitHub workflows + A [GitHub workflow](https://docs.github.com/en/actions/using-workflows) is a configurable automated process that will run one or more jobs. ``` From 439a1f19bc7c42c5d20c3861b32c86cc77a74fb7 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 17 Mar 2024 03:52:44 -0700 Subject: [PATCH 199/810] Add husky term to glossary --- docs/glossary.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/glossary.md b/docs/glossary.md index 9f25c8c72..71f5d2a49 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -716,11 +716,14 @@ ESLint Stylelint [Stylelint](https://stylelint.io/) is a CSS linter that helps you avoid errors and enforce conventions. - + Prettier [Prettier](https://prettier.io/) is an opinionated code formatter. GitHub workflow GitHub workflows A [GitHub workflow](https://docs.github.com/en/actions/using-workflows) is a configurable automated process that will run one or more jobs. + +husky + Husky automatically lints your commit messages, code, and runs tests upon committing or pushing commits to a remote repository. ``` From 8d125d5a491c85d7b27c1631c768e653fb48d94e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 17 Mar 2024 04:10:04 -0700 Subject: [PATCH 200/810] Add term for husky --- docs/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/glossary.md b/docs/glossary.md index 71f5d2a49..c7b497c95 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -725,5 +725,5 @@ GitHub workflows A [GitHub workflow](https://docs.github.com/en/actions/using-workflows) is a configurable automated process that will run one or more jobs. husky - Husky automatically lints your commit messages, code, and runs tests upon committing or pushing commits to a remote repository. + [Husky](https://typicode.github.io/husky/) automatically lints your commit messages, code, and runs tests upon committing or pushing commits to a remote repository. ``` From a1dedd1fd4fec040374783e2d1937c5dd664688b Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Sun, 17 Mar 2024 13:02:30 +0100 Subject: [PATCH 201/810] Example of how to use icon expressions --- docs/classic-ui/icons.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/classic-ui/icons.md b/docs/classic-ui/icons.md index 3a5963e9e..fdaf6feb6 100644 --- a/docs/classic-ui/icons.md +++ b/docs/classic-ui/icons.md @@ -67,13 +67,14 @@ To use a different icon than the system default, you can override the registrati ## Icon expression -```{todo} -How does this work? We need an example here! -``` - -- The field `icon_expression` is used again to define icons for actions, content types, and other purposes. +- The field `icon_expr` is used again to define icons for actions, content types, and other purposes. - Use the icon name for icon expressions. +Example: + +```xml +string:list-check +``` (classic-ui-icons-icon-resolver-label)= From 7ed4a0f91d17d5e7056f69cbac589406e3684de8 Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Sun, 17 Mar 2024 13:39:50 +0100 Subject: [PATCH 202/810] Update docs/backend/upgrading/version-specific-migration/upgrade-to-60.md Co-authored-by: Steve Piercy --- .../upgrading/version-specific-migration/upgrade-to-60.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md index f5baf442e..34b08c397 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md @@ -653,5 +653,6 @@ It renders the portlets from the `plone.footerportlets` portlet manager. ## Boolean fields -Since `zope.schema==6.1.0` all `zope.schema.Bool` fields need to have a `required=False` attribute, +Since `zope.schema==6.1.0`, all `zope.schema.Bool` fields must have a `required=False` attribute. +This allows you to either tick or not tick the checkbox, submit the form, and process the field with either its value when ticked or `None` when unticked. otherwise, you will not be able to save the form without marking the checkbox, which effectively turns that field to be always `True`. From 9a0c0990933ae3ae5915a3a37d800c7cd3010de2 Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Sun, 17 Mar 2024 13:40:01 +0100 Subject: [PATCH 203/810] Update docs/backend/upgrading/version-specific-migration/upgrade-to-60.md Co-authored-by: Steve Piercy --- .../upgrading/version-specific-migration/upgrade-to-60.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md index 34b08c397..bdd3b69f0 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md @@ -655,4 +655,4 @@ It renders the portlets from the `plone.footerportlets` portlet manager. Since `zope.schema==6.1.0`, all `zope.schema.Bool` fields must have a `required=False` attribute. This allows you to either tick or not tick the checkbox, submit the form, and process the field with either its value when ticked or `None` when unticked. -otherwise, you will not be able to save the form without marking the checkbox, which effectively turns that field to be always `True`. +Otherwise, you can't save the form without ticking the checkbox, which effectively makes the field value always `True`. From f3d06f2b808bec1d738fe618b154e2d66fe408d9 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 17 Mar 2024 06:13:40 -0700 Subject: [PATCH 204/810] Add Jest to Glossary --- docs/glossary.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/glossary.md b/docs/glossary.md index c7b497c95..e700fb8c7 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -726,4 +726,8 @@ GitHub workflows husky [Husky](https://typicode.github.io/husky/) automatically lints your commit messages, code, and runs tests upon committing or pushing commits to a remote repository. + +Jest + [Jest](https://jestjs.io/) is a JavaScript testing framework. + Volto uses Jest for unit tests. ``` From 508db8a2be1dedebec4a7f62be2465a199025e51 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 17 Mar 2024 23:03:13 -0700 Subject: [PATCH 205/810] Update tips submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 0deb876b3..27e84b5fa 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 0deb876b34bcd698dc46282884ce5417aeae0fce +Subproject commit 27e84b5fa170d8f86d0d0fb9ea5abc7c374afd66 From 4ce59a9a6aa6b148db75b3d7278aa964f33dca1c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 20 Mar 2024 06:29:44 -0700 Subject: [PATCH 206/810] Update tips submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 27e84b5fa..482bced02 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 27e84b5fa170d8f86d0d0fb9ea5abc7c374afd66 +Subproject commit 482bced02d01d9336e7db10aa4057cfcf0867ceb From 9df78e579cfd4aaa67148068499e1d5bbd31bd89 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 22 Mar 2024 15:15:37 -0700 Subject: [PATCH 207/810] Update tips submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 482bced02..f89c52313 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 482bced02d01d9336e7db10aa4057cfcf0867ceb +Subproject commit f89c52313a873ce718dde7213307aaaa13d80cc0 From b361592d1bf4e887b31a525976b2c017c8c0845c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 24 Mar 2024 02:23:11 -0700 Subject: [PATCH 208/810] Update tips submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index f89c52313..1853f9248 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit f89c52313a873ce718dde7213307aaaa13d80cc0 +Subproject commit 1853f9248ff1fe38394da7dc4ad0bb85f3d3832a From 1878587848a7492848da40f293df097ec8e5364d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 24 Mar 2024 03:03:18 -0700 Subject: [PATCH 209/810] Update tips submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 1853f9248..40526aaa8 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 1853f9248ff1fe38394da7dc4ad0bb85f3d3832a +Subproject commit 40526aaa8fb63d7710e1f4a68de1612fcf6ca976 From 51ab4262c01a134d0f06ebf2bd85f1ec6d74e9ba Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 24 Mar 2024 03:11:14 -0700 Subject: [PATCH 210/810] Clarify where to place Volto news items --- docs/contributing/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/contributing/index.md b/docs/contributing/index.md index 7dec72ed1..24be3d4ff 100644 --- a/docs/contributing/index.md +++ b/docs/contributing/index.md @@ -86,8 +86,10 @@ When a package is released with a new version, the release manager runs `towncri Because the log file is automatically generated, you should not edit it directly, except to make corrections, such as broken links. To create a change log entry or news item, create a file in the `news` directory, located in the root of the package. + For Volto, its repository is in a monorepo structure, consisting of several packages in the `packages` folder. Thus for Volto and its packages, change log entries should be created in `packages/PACKAGE_NAME/news/`, which is the root of the package. +When making a change to its documentation, set up, continuous integration, or other repository-wide items, place a change log entry in `packages/volto/news/` as a default. The change log entry's format must be `###.type`, where `###` is the referenced GitHub issue or pull request number, `.` is the literal extension delimiter, and `type` is one of the following strings. From e2b1786be177bd91297379687585e1dc9d9ccd61 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 29 Mar 2024 00:58:10 -0700 Subject: [PATCH 211/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 40526aaa8..d22c5e82e 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 40526aaa8fb63d7710e1f4a68de1612fcf6ca976 +Subproject commit d22c5e82e79a4f1f13eff9a5bfa1a830a8804efd From 5c9d2ed8a71bab282879c2fe941744e76f76edfb Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 31 Mar 2024 05:53:09 -0700 Subject: [PATCH 212/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index e62bea212..1d76fd7c7 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit e62bea2121d929d9c35298e7e5841332bd1dcbc5 +Subproject commit 1d76fd7c7ce7db42131e58a2b008163af4c4f8f9 diff --git a/submodules/volto b/submodules/volto index d22c5e82e..c256e4ee3 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit d22c5e82e79a4f1f13eff9a5bfa1a830a8804efd +Subproject commit c256e4ee385dc4f2dd884c71d37701b80078058e From 22d15abfab662141fd3184ea409ff66b9fdcf7db Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 1 Apr 2024 17:33:25 -0700 Subject: [PATCH 213/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index c256e4ee3..f60d83e2b 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit c256e4ee385dc4f2dd884c71d37701b80078058e +Subproject commit f60d83e2b4452a86f19f073c62bb4484e19cfe86 From f2f7d3cf89920dee8aaff0e19996443de9c21148 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 1 Apr 2024 17:34:11 -0700 Subject: [PATCH 214/810] Update tip submodules/plone.restapi --- submodules/plone.restapi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 1d76fd7c7..b9bda7b8e 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 1d76fd7c7ce7db42131e58a2b008163af4c4f8f9 +Subproject commit b9bda7b8edb5b692bc11e0291538f2879545ae39 From daf8ccbfdc6f8ec452e175b505539bb26caeb25e Mon Sep 17 00:00:00 2001 From: Peter Mathis Date: Tue, 9 Apr 2024 08:37:18 +0200 Subject: [PATCH 215/810] fix field referring code --- docs/backend/schemas.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend/schemas.md b/docs/backend/schemas.md index a9f9318ed..1e519d953 100644 --- a/docs/backend/schemas.md +++ b/docs/backend/schemas.md @@ -299,7 +299,7 @@ class IMySchema(model.Schema): ``` The value passed to the directive may be either `*`, indicating before or after all fields, or the name of another field. -Use `<.fieldname>` to refer to the field in the current schema or a base schema. +Use `.` to refer to the field in the current schema or a base schema. Prefix with the schema name, such as `IDublinCore.title`, to refer to a field in another schema. Use an unprefixed name to refer to a field in either the current or default schema for the form. From 7075f951fd7f3bdf0490cae706d5d7e11ad33187 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 9 Apr 2024 16:06:18 -0700 Subject: [PATCH 216/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index b9bda7b8e..848dff077 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit b9bda7b8edb5b692bc11e0291538f2879545ae39 +Subproject commit 848dff077a29cc5ceb52fc2373b3bf74d51cef49 diff --git a/submodules/volto b/submodules/volto index f60d83e2b..8aa167a6d 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit f60d83e2b4452a86f19f073c62bb4484e19cfe86 +Subproject commit 8aa167a6d5ffb94f329dec42c0d9c96700ea27d6 From 357f0cdd18ab242eb68550751f441783f4a6c1d3 Mon Sep 17 00:00:00 2001 From: MrTango Date: Thu, 11 Apr 2024 10:50:56 +0300 Subject: [PATCH 217/810] add more info about RichText field and the usage of transforms and RichTextValue --- docs/backend/fields.md | 111 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/docs/backend/fields.md b/docs/backend/fields.md index 735fd74c3..2c5c01267 100644 --- a/docs/backend/fields.md +++ b/docs/backend/fields.md @@ -115,6 +115,8 @@ See [`z3c.relationfield`](https://pypi.org/project/z3c.relationfield/) for more | `RelationChoice` | `RelationValue` | A `Choice` field intended to store `RelationValue`s | See {ref}`Choice ` | +(backend-fields-richtext-label)= + ### Fields in `plone.app.textfield` See [`plone.app.textfield`](https://pypi.org/project/plone.app.textfield/) for more details. @@ -124,6 +126,115 @@ See [`plone.app.textfield`](https://pypi.org/project/plone.app.textfield/) for m | `RichText` | `RichTextValue` | Stores a `RichTextValue`, which encapsulates a raw text value, the source MIME type, and a cached copy of the raw text transformed to the default output MIME type. | `IField`, `IRichText` | +The RichText field allows for alternative markups and content filtering. + +```python +from plone.app.textfield import RichText +from plone.supermodel import model + +class ITestSchema(model.Schema): + + body = RichText(title="Body text") +``` + +The `RichText` field constructor can take the following arguments, in addition to the usual arguments for a `Text` field. + +`default_mime_type` +: A string representing the default MIME type of the input markup. + This defaults to `text/html`. + +`output_mime_type` +: A string representing the default output MIME type. + This defaults to `text/x-html-safe`, which is a Plone-specific MIME type that disallows certain tags. + Use the {guilabel}`HTML Filtering` control panel in Plone to control the tags. + +`allowed_mime_types` +: A tuple of strings giving a vocabulary of allowed input MIME types. + If this is `None` (the default), the allowable types will be restricted to those set in Plone's {guilabel}`Markup` control panel. + +The *default* field can be set to either a Unicode object (in which case it will be assumed to be a string of the default MIME type) or a {ref}`backend-fields-richtextvalue-label`. + + +#### reStructuredText transformation + +Below is an example of a field that allows StructuredText and reStructuredText, transformed to HTML by default. + +```python +from plone.app.textfield import RichText +from plone.supermodel import model + +defaultBody = """\ +Background +========== + +Please fill this in + +Details +------- + +And this +""" + +class ITestSchema(model.Schema): + + body = RichText( + title="Body text", + default_mime_type='text/x-rst', + output_mime_type='text/x-html', + allowed_mime_types=('text/x-rst', 'text/structured',), + default=defaultBody, + ) +``` + + +(backend-fields-richtextvalue-label)= + +#### RichTextValue + +The `RichText` field, most of the time does not store a string. +Instead, it stores a `RichTextValue` object. +This is an immutable object that has the following properties. + +`raw` +: A Unicode string with the original input markup. + +`mimeType` +: The MIME type of the original markup, for example `text/html` or `text/structured`. + +`encoding` +: The default character encoding used when transforming the input markup. + Most likely, this will be UTF-8. + +`raw_encoded` +: The raw input encoded in the given encoding. + +`outputMimeType` +: The MIME type of the default output, taken from the field at the time of instantiation. + +`output` +: A Unicode object representing the transformed output. + If possible, this is cached persistently, until the `RichTextValue` is replaced with a new one (as happens when an edit form is saved, for example). + +The storage of the `RichTextValue` object is optimized for the case where the transformed output will be read frequently (for example, on the view screen of the content object) and the raw value will be read infrequently (for example, on the edit screen). +Because the output value is cached indefinitely, you will need to replace the `RichTextValue` object with a new one if any of the transformation parameters change. +However, as we will see below, it is possible to apply a different transformation on demand, if you need to. + +The code snippet below shows how a `RichTextValue` object can be constructed in code. +In this case, we have a raw input string of type `text/plain` that will be transformed to a default output of `text/html`. +Note that we would normally look up the default output type from the field instance. + +```python +from plone.app.textfield.value import RichTextValue + +context.body = RichTextValue("Some input text", 'text/plain', 'text/html') +``` + +The standard widget used for a `RichText` field will correctly store this type of object for you, so it is rarely necessary to create one yourself. + + + + + ### Fields in `plone.schema` See {ref}`backend-ploneschema-label` for more details. From f8fa0caa7b27914f1f641c2f4b44cd7a39dcb936 Mon Sep 17 00:00:00 2001 From: MrTango Date: Thu, 11 Apr 2024 10:58:11 +0300 Subject: [PATCH 218/810] add: "Using RichText fields in templates" and "Alternative transformations" --- docs/backend/fields.md | 56 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/docs/backend/fields.md b/docs/backend/fields.md index 2c5c01267..457412fbf 100644 --- a/docs/backend/fields.md +++ b/docs/backend/fields.md @@ -232,6 +232,62 @@ context.body = RichTextValue("Some input text", 'text/plain', 'text/html') The standard widget used for a `RichText` field will correctly store this type of object for you, so it is rarely necessary to create one yourself. +##### Using RichText fields in templates + +If you use a `DisplayForm`, the display widget for the `RichText` field will render the transformed output markup automatically. +If you write TAL manually, you may try something like the following. + +```xml +
+``` + +This, however, will render a string as follows. + +```html +RichTextValue object. (Did you mean .raw or .output?) +``` + +The correct syntax is: + +```xml +
+``` + +This will render the cached, transformed output. +This operation is approximately as efficient as rendering a simple `Text` field, since the transformation is only applied once, when the value is first saved. + + +##### Alternative transformations + +Sometimes, you may want to invoke alternative transformations. +Under the hood, the default implementation uses the `portal_transforms` tool to calculate a transform chain from the raw value's input MIME type to the desired output MIME type. +If you need to write your own transforms, take a look at [this tutorial](https://5.docs.plone.org/develop/plone/misc/portal_transforms.html). +This is abstracted behind an `ITransformer` adapter to allow alternative implementations. + +To invoke a transformation in code, you can use the following syntax. + +```python +from plone.app.textfield.interfaces import ITransformer + +transformer = ITransformer(context) +transformedValue = transformer(context.body, 'text/plain') +``` + +The `__call__()` method of the `ITransformer` adapter takes a `RichTextValue` object and an output MIME type as parameters. + +If you write a page template, there is an even more convenient syntax. + +```xml +
+``` + +The first traversal name gives the name of the field on the context (`body` in this case). +The second and third give the output MIME type. +If the MIME type is omitted, the default output MIME type will be used. + +```{note} +Unlike the `output` property, the value is not cached, and so will be calculated each time the page is rendered. +``` From 12ec16bf0a708c64fff95e7cc8ba646dd4995791 Mon Sep 17 00:00:00 2001 From: MrTango Date: Thu, 11 Apr 2024 15:29:09 +0300 Subject: [PATCH 219/810] fix RichTextValue paramters --- docs/backend/fields.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend/fields.md b/docs/backend/fields.md index 457412fbf..084e342e9 100644 --- a/docs/backend/fields.md +++ b/docs/backend/fields.md @@ -226,7 +226,7 @@ Note that we would normally look up the default output type from the field insta ```python from plone.app.textfield.value import RichTextValue -context.body = RichTextValue("Some input text", 'text/plain', 'text/html') +context.body = RichTextValue("Some input text", mimeType="text/html", outputMimeType="text/x-html-safe") ``` The standard widget used for a `RichText` field will correctly store this type of object for you, so it is rarely necessary to create one yourself. From 3ec56fdddc11dc14eee26e9a3aaa5ae386f6d730 Mon Sep 17 00:00:00 2001 From: MrTango Date: Thu, 11 Apr 2024 21:34:13 +0300 Subject: [PATCH 220/810] describe how to use NamedBlobImage --- docs/backend/fields.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/backend/fields.md b/docs/backend/fields.md index 084e342e9..28d438974 100644 --- a/docs/backend/fields.md +++ b/docs/backend/fields.md @@ -103,6 +103,25 @@ See [`plone.namedfile`](https://pypi.org/project/plone.namedfile/) and [plone.fo | `NamedBlobFile` | `NamedBlobFile` | A binary uploaded file stored as a ZODB blob. Requires the `blobs` extra to `plone.namedfile`. Otherwise identical to `NamedFile`. | `IField` | | `NamedBlobImage` | `NamedBlobImage` | A binary uploaded image stored as a ZODB blob. Requires the `blobs` extra to `plone.namedfile`. Otherwise identical to `NamedImage`. | `IField` | +#### NamedBlobImage + +The following example shows, how to create an Image object and attach the image file to it. + +```python +img_obj = api.content.create( + container=ww_article, + type="Image", + id="test.jpg", +) +img_obj.image = NamedBlobImage( + data=img_file, + filename="test.jpg", +) +``` + + + + ### Fields in `z3c.relationfield.schema` From 59fa3241b73389de630f14ce9b481d528acc7560 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 14 Apr 2024 02:52:29 -0700 Subject: [PATCH 221/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 8aa167a6d..a863b459c 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 8aa167a6d5ffb94f329dec42c0d9c96700ea27d6 +Subproject commit a863b459c118036035eb4efc3338dcf23770a2de From fed0655ad5cd0e47f027dce5a3200a158d87558b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 17 Apr 2024 01:41:33 -0600 Subject: [PATCH 222/810] Fix link to TinyMCE 4 to 5 upgrade guide. --- .../upgrading/version-specific-migration/upgrade-to-60.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md index bdd3b69f0..34ce02e2a 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md @@ -600,7 +600,7 @@ The following example {file}`registry.xml` may be used for configuring TinyMCE w Please make sure you write valid JSON for the `template` option. ```{seealso} -See also the [TinyMCE 4 to 5 upgrade guide](https://www.tiny.cloud/docs/migration-from-4x/). +See also [Migrating from TinyMCE 4 to TinyMCE 5](https://www.tiny.cloud/docs/tinymce/5/migration-from-4x/). ``` ## Viewlets From d4f0cd3b9c7439c8d1f343de71f0fe5d96795cbd Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 17 Apr 2024 02:26:41 -0600 Subject: [PATCH 223/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index a863b459c..72bc90981 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit a863b459c118036035eb4efc3338dcf23770a2de +Subproject commit 72bc90981d4195c1f656671a334b41aaacf427d3 From b060ce21f756b9ff0d3d61cf311aee62b0d658ff Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 17 Apr 2024 11:17:35 -0600 Subject: [PATCH 224/810] Add lazy load (and its verb derivations) to the glossary. Depends on merge of https://github.com/plone/volto/pull/5295/ --- docs/glossary.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/glossary.md b/docs/glossary.md index e700fb8c7..0ba2027c6 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -730,4 +730,10 @@ husky Jest [Jest](https://jestjs.io/) is a JavaScript testing framework. Volto uses Jest for unit tests. + +lazy load +lazy loading +lazy loaded + Lazy loading is a strategy to identify resources as non-blocking (non-critical) and load these only when needed. + It's a way to shorten the length of the [critical rendering path](https://developer.mozilla.org/en-US/docs/Web/Performance/Critical_rendering_path, which translates into reduced page load times. ``` From 86ba8aa269921dd51751830bd43caea5648ad185 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 19 Apr 2024 13:27:33 -0600 Subject: [PATCH 225/810] Initial skeleton of deployment documentation --- docs/deployment/backup.md | 12 ---- docs/deployment/components.md | 58 +++++++++++++++++++ .../continuous-integration-and-deployment.md | 20 +++++++ docs/deployment/index.md | 16 +++-- docs/deployment/orchestration.md | 20 +++++++ docs/deployment/provision.md | 23 -------- docs/deployment/scaling.md | 28 --------- docs/deployment/server-environment.md | 25 ++++++++ docs/glossary.md | 40 ++++++++++++- 9 files changed, 173 insertions(+), 69 deletions(-) delete mode 100644 docs/deployment/backup.md create mode 100644 docs/deployment/components.md create mode 100644 docs/deployment/continuous-integration-and-deployment.md create mode 100644 docs/deployment/orchestration.md delete mode 100644 docs/deployment/provision.md delete mode 100644 docs/deployment/scaling.md create mode 100644 docs/deployment/server-environment.md diff --git a/docs/deployment/backup.md b/docs/deployment/backup.md deleted file mode 100644 index 5cb068974..000000000 --- a/docs/deployment/backup.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -myst: - html_meta: - "description": "Backup and restore of Plone 6" - "property=og:description": "Backup and restore of Plone 6" - "property=og:title": "Backup and restore of Plone 6" - "keywords": "Plone, Backup, Restore" ---- - -(deployment-backup-restore-label)= - -# Backup and Restore diff --git a/docs/deployment/components.md b/docs/deployment/components.md new file mode 100644 index 000000000..5c8dc91d6 --- /dev/null +++ b/docs/deployment/components.md @@ -0,0 +1,58 @@ +--- +myst: + html_meta: + "description": "Components of a Plone 6 application for deployment" + "property=og:description": "Components of a Plone 6 application for deployment" + "property=og:title": "Components of a Plone 6 application for deployment" + "keywords": "Plone, deployment, components, backend, volto, fronted, TLS termination proxy, load balancer, router, database, mail service, optimization, maintenance" +--- + +(deployment-components-label)= + +# Components + +This page in the deployment guide covers the components in a Plone application deployment. +The components can be broken down into those that are required, recommended, and optional. + + +(deployment-required-components-label)= + +## Required components + +You need the following components to deploy a Plone application. + +- {term}`Plone backend` +- {term}`Volto` as the default {term}`Frontend` for Plone +- {term}`TLS termination proxy` +- {term}`Load balancer` or router +- Database +- Mail service +- Optimization tasks + - Database parameters + - https://5.docs.plone.org/manage/deploying/performance/index.html +- Maintenance tasks + - Database backup + - Packing database - https://5.docs.plone.org/manage/deploying/packing.html + - Monitoring + - Log rotation + - Firewall + - Attack protection + - DNS + - Host name resolution + + +(deployment-recommended-components-label)= + +## Recommended components + +Recommended components, although not required, will help with the performance and user experience of your Plone application. + +- HTTP caching + + +(deployment-optional-components-label)= + +## Optional components + +- Search + diff --git a/docs/deployment/continuous-integration-and-deployment.md b/docs/deployment/continuous-integration-and-deployment.md new file mode 100644 index 000000000..a92950254 --- /dev/null +++ b/docs/deployment/continuous-integration-and-deployment.md @@ -0,0 +1,20 @@ +--- +myst: + html_meta: + "description": "Continuous integration (CI) and continuous deployment (CD) for a Plone 6 application" + "property=og:description": "Continuous integration (CI) and continuous deployment (CD) for a Plone 6 application" + "property=og:title": "Continuous integration (CI) and continuous deployment (CD) for a Plone 6 application" + "keywords": "Plone, Continuous integration, CI, continuous deployment, CD, pipeline, images, GitHub, actions, workflows" +--- + +(deployment-continuous-integration-and-deployment-label)= + +# Continuous integration and deployment + +This page in the deployment guide covers {term}`continuous integration` (CI) and {term}`continuous deployment` (CD) for a Plone 6 application. + + +## Deployment pipeline + + +## Build images diff --git a/docs/deployment/index.md b/docs/deployment/index.md index 92926b998..bb1b7008c 100644 --- a/docs/deployment/index.md +++ b/docs/deployment/index.md @@ -4,22 +4,28 @@ myst: "description": "Deployment of Plone 6" "property=og:description": "Deployment of Plone 6" "property=og:title": "Deployment of Plone 6" - "keywords": "Plone, deployment, automation" + "keywords": "Plone, deployment, server, environment, continuous integration, continuous deployment, automation, tuning, optimatization, orchestration, Docker, Swarm, Kubernetes" --- (deployment-label)= # Deployment +This part of the documentation describes how to deploy your Plone 6 application. +This how-to guide covers the components of a Plone application, a server environment, continuous integration (CI) and continuous deployment (CD), and orchestration for a deployment. +It is not comprehensive of all ways to deploy Plone, but covers common usage. + + ```{todo} -Intro to chapter "deployment" +Find a better home for Caching, as it goes deep into explanation with a little bit of how-to guide. ``` ```{toctree} :maxdepth: 2 -provision -scaling -backup +components +server-environment +continuous-integration-and-deployment +orchestration caching/index ``` diff --git a/docs/deployment/orchestration.md b/docs/deployment/orchestration.md new file mode 100644 index 000000000..9d72fbfab --- /dev/null +++ b/docs/deployment/orchestration.md @@ -0,0 +1,20 @@ +--- +myst: + html_meta: + "description": "Orchestration of a Plone 6 application" + "property=og:description": "Orchestration of a Plone 6 application" + "property=og:title": "Orchestration of a Plone 6 application" + "keywords": "Plone, orchestration, scaling, Docker, Swarm, Kubernetes" +--- + +(deployment-orchestration-label)= + +# Orchestration + +This page covers orchestration of a Plone 6 application. + +The recommended procedure for Plone 6 is through the use of Docker Swarm. + +```{seealso} +Kubernetes is another orchestration option currently under development and testing in the [Plone Helm Charts](https://github.com/plone/helm-charts) GitHub repository. +``` diff --git a/docs/deployment/provision.md b/docs/deployment/provision.md deleted file mode 100644 index 94f1beb59..000000000 --- a/docs/deployment/provision.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -myst: - html_meta: - "description": "Provisioning of Plone 6" - "property=og:description": "Provisioning of Plone 6" - "property=og:title": "Provisioning of Plone 6" - "keywords": "Plone, Provision" ---- - -(deployment-provisioning-label)= - -# Provisioning - - -(deployment-provisioning-ansible-label)= - -## Ansible - - -(deployment-provisioning-containers-label)= - -## Containers - diff --git a/docs/deployment/scaling.md b/docs/deployment/scaling.md deleted file mode 100644 index 59bc93db1..000000000 --- a/docs/deployment/scaling.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -myst: - html_meta: - "description": "Scaling Plone 6" - "property=og:description": "Scaling Plone 6" - "property=og:title": "Scaling Plone 6" - "keywords": "Plone, scaling, high availability" ---- - -(deployment-scaling-label)= - -# Scaling - - -(deployment-scaling-traffic-label)= - -## Traffic - - -(deployment-scaling-high-availability-label)= - -## High availability - - -(deployment-scaling-caching-label)= - -## Caching - diff --git a/docs/deployment/server-environment.md b/docs/deployment/server-environment.md new file mode 100644 index 000000000..2a50fb4b7 --- /dev/null +++ b/docs/deployment/server-environment.md @@ -0,0 +1,25 @@ +--- +myst: + html_meta: + "description": "Prepare a server environment for a deployment of Plone 6" + "property=og:description": "Prepare a server environment for a deployment of Plone 6" + "property=og:title": "Prepare a server environment for a deployment of Plone 6" + "keywords": "Plone, deployment, server, environment" +--- + +(deployment-server-environment-label)= + +# Server environment + +This page in the deployment guide covers how to prepare a server environment for a Plone 6 deployment. +You will need to prepare your environment with the following items. + +```{note} +Should we reuse or update {ref}`install-packages-hardware-requirements-label`? +``` + +- server instance with an operating system that Plone can run on +- RAM +- disk +- SSH key +- preparation for orchestration diff --git a/docs/glossary.md b/docs/glossary.md index e700fb8c7..f82e78d27 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -403,7 +403,7 @@ Traefik Proxy [Traefik Proxy](https://traefik.io/traefik/) is an open-source reverse proxy and load balancer, suitable for containerized architectures. Volto - [Volto](https://github.com/plone/volto) is a React-based frontend for the Plone CMS. + [Volto](https://github.com/plone/volto) is a React-based frontend for Plone. It is the default user interface for Plone 6. The other frontend is {term}`Classic UI`. @@ -730,4 +730,42 @@ husky Jest [Jest](https://jestjs.io/) is a JavaScript testing framework. Volto uses Jest for unit tests. + +Plone + Plone is an open-source content management system (CMS) with over 20 years of stability and security wrapped in a modern, powerful, user-centric package. + It continues to set the standard for content management systems by offering the most functionality and customization out of the box. + +backend +Plone backend + Plone's backend includes a content management system, a REST API, and {term}`Classic UI` as a {term}`frontend`. + +frontend +Plone frontend + A frontend consists of the user interface elements of a web application. + Beginning with Plone 6, the default frontend is {term}`Volto`. + {term}`Classic UI` is a secondary frontend that is part of the {term}`Plone backend`. + +TLS +Transport Layer Security + Transport Layer Security (TLS) is a cryptographic protocol designed to provide communications security over a computer network. + + ```{seealso} + [Transport Layer Security](https://developer.mozilla.org/en-US/docs/Web/Security/Transport_Layer_Security) article from MDN. + ``` + +TLS termination proxy + A {term}`TLS` termination proxy is a proxy server that acts as an intermediary point between client and server applications. + It is used to terminate or establish TLS tunnels by decrypting or encrypting communications. + +Load balancer + A load balancer acts as a traffic proxy and distributes network or application traffic across endpoints on a number of servers. + +CI +continuous integration + Continuous integration (CI) is the practice of integrating all your code changes into the main branch of a shared source code repository early and often, automatically testing each change when you commit or merge them, and automatically kicking off a build. + +CD +continuous deployment +continuous delivery + Continuous deployment or continuous delivery is a software development practice that works in conjunction with {term}`CI` to automate the infrastructure provisioning and application release process. ``` From 2ad9a1e250a8beeaab66cc24922eef20fac87e68 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 19 Apr 2024 14:56:20 -0600 Subject: [PATCH 226/810] Fix link to upgrade to Plone 5 slides --- .../upgrading/version-specific-migration/p4x-to-p5x-upgrade.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend/upgrading/version-specific-migration/p4x-to-p5x-upgrade.md b/docs/backend/upgrading/version-specific-migration/p4x-to-p5x-upgrade.md index 1b8a5a5c1..da98fa71f 100644 --- a/docs/backend/upgrading/version-specific-migration/p4x-to-p5x-upgrade.md +++ b/docs/backend/upgrading/version-specific-migration/p4x-to-p5x-upgrade.md @@ -26,7 +26,7 @@ To upgrade add-ons to Plone 5, see also {doc}`upgrade-addons-to-50`. - Always upgrade from the latest version of 4.x to the latest version of 5.x (4.3.20 to 5.2.9 at the time of writing). This will resolve many migration-specific issues. - If you have problems, ask for help on https://community.plone.org. -- The talk _How to upgrade sites to Plone 5_ has a [video](https://www.youtube.com/watch?t=1m17s&v=bQ-IpO-7F00&feature=youtu.be) and [slides](https://de.slideshare.net/derschmock/upgrade-to-plone-5). +- The talk _How to upgrade sites to Plone 5_ has a [video](https://www.youtube.com/watch?t=1m17s&v=bQ-IpO-7F00&feature=youtu.be) and [slides](https://www.slideshare.net/slideshow/upgrade-to-plone-5/54040952). (upgrading-plone-4.x-to-5.0-changes-due-to-implemented-plips-label)= From 6f21df423f0d767593a8ada1dccb74fe26f71e84 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 19 Apr 2024 18:23:48 -0600 Subject: [PATCH 227/810] Add missing extensions to documentation and sort alphabetically. --- .../documentation/themes-and-extensions.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/contributing/documentation/themes-and-extensions.md b/docs/contributing/documentation/themes-and-extensions.md index b2bb8a94c..490b489b1 100644 --- a/docs/contributing/documentation/themes-and-extensions.md +++ b/docs/contributing/documentation/themes-and-extensions.md @@ -40,11 +40,21 @@ We use several MyST and Sphinx extensions to enhance the presentation of Plone d ### Sphinx +- [`myst_parser`](https://myst-parser.readthedocs.io/en/latest/) parses MyST, a rich and extensible flavour of Markdown for authoring documentation. +- [`sphinx-design`](https://sphinx-design.readthedocs.io/en/latest/), with a configuration name of `sphinx_design`, adds grids, cards, icons, badges, buttons, tabs, and dropdowns. +- [`sphinx-notfound-page`](https://sphinx-notfound-page.readthedocs.io/en/latest/index.html), with a configuration name of `notfound.extension`, creates a custom 404 page and helps generate proper static resource links to render the page properly. +- [`sphinx.ext.autodoc`](https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html) pulls in documentation from Python docstrings to generate reStructuredText which in turn gets parsed by Sphinx and rendered to the output format. + It is used by {doc}`/plone.api/index`. +- [`sphinx.ext.autosummary`](https://www.sphinx-doc.org/en/master/usage/extensions/autosummary.html) generates function/method/attribute summary lists. + It is used by {doc}`/plone.api/index`. - [`sphinx.ext.graphviz`](https://www.sphinx-doc.org/en/master/usage/extensions/graphviz.html) allows you to embed [Graphviz](https://graphviz.org/download/) graphs in your documents. +- [`sphinx.ext.ifconfig`](https://www.sphinx-doc.org/en/master/usage/extensions/ifconfig.html) includes content based on configuration. - [`sphinx.ext.intersphinx`](https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html) provides linking between separate projects that use Sphinx for documentation. - [`sphinx.ext.todo`](https://www.sphinx-doc.org/en/master/usage/extensions/todo.html) adds support for todo items. +- [`sphinx.ext.viewcode`](https://www.sphinx-doc.org/en/master/usage/extensions/viewcode.html) generates pages of source code modules and links between the source and the description. + It is used by {doc}`/plone.api/index`. - [`sphinx_copybutton`](https://sphinx-copybutton.readthedocs.io/en/latest/index.html) adds a little "copy" button to the right of code blocks. -- [`sphinx-design`](https://sphinx-design.readthedocs.io/en/latest/) adds grids, cards, icons, badges, buttons, tabs, and dropdowns. +- [`sphinx_reredirects`](https://documatt.com/sphinx-reredirects/) handles redirects for moved pages. - [`sphinx_sitemap`](https://pypi.org/project/sphinx-sitemap/) generates multiversion and multilanguage [sitemaps.org](https://www.sitemaps.org/protocol.html) compliant sitemaps. - [`sphinxcontrib.httpdomain`](https://sphinxcontrib-httpdomain.readthedocs.io/en/stable/) provides a Sphinx domain for describing HTTP APIs. It is used by Plone's {doc}`plone.restapi/docs/source/index`. @@ -53,7 +63,3 @@ We use several MyST and Sphinx extensions to enhance the presentation of Plone d It is used by Plone's {doc}`plone.restapi/docs/source/index`. - [`sphinxcontrib.video`](https://pypi.org/project/sphinxcontrib-video/) allows you to embed local videos as defined by the HTML5 standard. - [`sphinxext.opengraph`](https://pypi.org/project/sphinxext-opengraph/) generates [OpenGraph metadata](https://ogp.me/). -- [`sphinx.ext.viewcode`](https://www.sphinx-doc.org/en/master/usage/extensions/viewcode.html) generates pages of source code modules and links between the source and the description. - It is used by {doc}`/plone.api/index`. -- [`sphinx.ext.autosummary`](https://www.sphinx-doc.org/en/master/usage/extensions/autosummary.html) generates function/method/attribute summary lists. - It is used by {doc}`/plone.api/index`. From 7c63be00a3b0ec97a9d4b4e7f9c3a635c59c61fe Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 24 Apr 2024 09:57:14 -0700 Subject: [PATCH 228/810] Start Plone 6.1 upgrade guide --- .../version-specific-migration/index.md | 1 + .../upgrade-to-61.md | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 docs/backend/upgrading/version-specific-migration/upgrade-to-61.md diff --git a/docs/backend/upgrading/version-specific-migration/index.md b/docs/backend/upgrading/version-specific-migration/index.md index c210c3af0..c8cb485cd 100644 --- a/docs/backend/upgrading/version-specific-migration/index.md +++ b/docs/backend/upgrading/version-specific-migration/index.md @@ -26,5 +26,6 @@ upgrade-to-52 upgrade-to-python3 upgrade-zodb-to-python3 upgrade-to-60 +upgrade-to-61 migrate-to-volto ``` diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md new file mode 100644 index 000000000..8ff1567f7 --- /dev/null +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md @@ -0,0 +1,27 @@ +--- +myst: + html_meta: + "description": "How to upgrade to Plone 6.1" + "property=og:description": "How to upgrade to Plone 6.1" + "property=og:title": "How to upgrade to Plone 6.1" + "keywords": "Upgrade, Plone 6" +--- + +(backend-upgrade-plone-v61-label)= + +# Upgrade Plone 6.0 to 6.1 + +Plone 6.1 has seen the following major changes. +Some may require changes in your setup. + + +## TinyMCE upgraded + +Plone 6.0 uses TinyMCE, a rich text editor for websites. +TinyMCE 5 reached its end of support on April 20, 2023. +For Plone 6.1, TinyMCE has been upgraded from version 5 to 7. + +```{seealse} +- [How to upgrade TinyMCE 5 to TinyMCE 6](https://www.tiny.cloud/blog/upgrade-to-tinymce-6/) +- [Upgrading TinyMCE](https://www.tiny.cloud/docs/tinymce/latest/upgrading/) +``` From 67bf44538084ec7fd7a44363372939ef1acbb93a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 24 Apr 2024 10:10:25 -0700 Subject: [PATCH 229/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 72bc90981..1ce0d1ecb 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 72bc90981d4195c1f656671a334b41aaacf427d3 +Subproject commit 1ce0d1ecbf4ba7711cfd4577884ff05c201d08c8 From a966bb9a8dfe96769d9595e4aae857ee62565637 Mon Sep 17 00:00:00 2001 From: 1letter <1letter@gmx.de> Date: Wed, 24 Apr 2024 20:14:41 +0200 Subject: [PATCH 230/810] Fix typo --- .../upgrading/version-specific-migration/upgrade-to-61.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md index 8ff1567f7..bcbe81199 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md @@ -21,7 +21,7 @@ Plone 6.0 uses TinyMCE, a rich text editor for websites. TinyMCE 5 reached its end of support on April 20, 2023. For Plone 6.1, TinyMCE has been upgraded from version 5 to 7. -```{seealse} +```{seealso} - [How to upgrade TinyMCE 5 to TinyMCE 6](https://www.tiny.cloud/blog/upgrade-to-tinymce-6/) - [Upgrading TinyMCE](https://www.tiny.cloud/docs/tinymce/latest/upgrading/) ``` From 191eb53e4bb4b5e191cf18241a4806338da56239 Mon Sep 17 00:00:00 2001 From: 1letter <1letter@gmx.de> Date: Wed, 24 Apr 2024 20:16:12 +0200 Subject: [PATCH 231/810] Add a description to use the TinyMCE accordion plugin --- .../upgrade-to-61.md | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md index bcbe81199..30667e0e6 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md @@ -25,3 +25,37 @@ For Plone 6.1, TinyMCE has been upgraded from version 5 to 7. - [How to upgrade TinyMCE 5 to TinyMCE 6](https://www.tiny.cloud/blog/upgrade-to-tinymce-6/) - [Upgrading TinyMCE](https://www.tiny.cloud/docs/tinymce/latest/upgrading/) ``` + +### Enable the TinyMCE accordion plugin + +Go to the controlpanel to manage TinyMCE settings + +Enable the Plugin in the controlpanel + +Add a menu entry `accordion` for TinyMCE in the controlpanel + +```{code-block} json +{ + "insert": { + "title": "Insert", + "items": "link media | template hr | accordion" + }, +} +``` + +Check your settings in the HTML filter controlpanel + +add two new tags to `valid tags` + +- `summary` +- `details` + +add a new attribute to `custom_attributes` + +- `open` + +for a transform to valid bootstrap5 accordion markup use an outputfilter + +```{seealso} +- [Addon collective.outputfilters.tinymceaccordion](https://github.com/collective/collective.outputfilters.tinymceaccordion) +``` \ No newline at end of file From daa676aeda9c4a94bbab4de48e790c1583a04423 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 24 Apr 2024 13:04:50 -0700 Subject: [PATCH 232/810] Add reference implementation to the glossary. See https://github.com/plone/volto/pull/5970 --- docs/glossary.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/glossary.md b/docs/glossary.md index 0ba2027c6..31ea25a59 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -736,4 +736,8 @@ lazy loading lazy loaded Lazy loading is a strategy to identify resources as non-blocking (non-critical) and load these only when needed. It's a way to shorten the length of the [critical rendering path](https://developer.mozilla.org/en-US/docs/Web/Performance/Critical_rendering_path, which translates into reduced page load times. + +reference implementation + A reference implementation is a program that implements all requirements from a corresponding specification. + The reference implementation often accompanies a technical standard, and demonstrates what should be considered the "correct" behavior of any other implementation of it. ``` From ba0fb2d614a4c828809d7de7a024b71c41c22408 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 24 Apr 2024 13:32:28 -0700 Subject: [PATCH 233/810] Convert narrative to an enumerated list of steps, add guilabel MyST markup --- .../upgrade-to-61.md | 45 +++++++++---------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md index 30667e0e6..0f55d14e8 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md @@ -28,34 +28,31 @@ For Plone 6.1, TinyMCE has been upgraded from version 5 to 7. ### Enable the TinyMCE accordion plugin -Go to the controlpanel to manage TinyMCE settings +1. Go to the {guilabel}`Site Setup > General > TinyMCE` control panel to manage TinyMCE settings. +1. Under the {guilabel}`Plugins and Toolbar` tab, check {guilabel}`accordion` to enable the accordion plugin. +1. Under the same tab, add a menu entry `accordion` for TinyMCE in the control panel by editing the `items` key as shown. -Enable the Plugin in the controlpanel + ```json + { + "insert": { + "title": "Insert", + "items": "link media | template hr | accordion" + }, + } + ``` -Add a menu entry `accordion` for TinyMCE in the controlpanel +1. Click the {guilabel}`Save` button to save your settings. +1. In the {guilabel}`Security > HTML filtering` control panel, add two new tags to {guilabel}`Valid tags`. -```{code-block} json -{ - "insert": { - "title": "Insert", - "items": "link media | template hr | accordion" - }, -} -``` - -Check your settings in the HTML filter controlpanel - -add two new tags to `valid tags` + - `summary` + - `details` -- `summary` -- `details` +1. Also in the {guilabel}`Security > HTML filtering` control panel, add a new attribute to {guilabel}`Custom attributes`. -add a new attribute to `custom_attributes` + - `open` -- `open` +1. For a transform to valid markup of the Bootstrap 5 accordion, use an output filter. -for a transform to valid bootstrap5 accordion markup use an outputfilter - -```{seealso} -- [Addon collective.outputfilters.tinymceaccordion](https://github.com/collective/collective.outputfilters.tinymceaccordion) -``` \ No newline at end of file + ```{seealso} + - [Addon collective.outputfilters.tinymceaccordion](https://github.com/collective/collective.outputfilters.tinymceaccordion) + ``` From ee956e9731f415ee9bf833b84284c9a62e27fb73 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 25 Apr 2024 00:50:59 -0700 Subject: [PATCH 234/810] Pin myst-parser to previous version Fix syntax of `netlify.toml` `headers.values` to prevent search engine indexing of Netlify preview builds --- netlify.toml | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/netlify.toml b/netlify.toml index ebdd9ef6e..324168726 100644 --- a/netlify.toml +++ b/netlify.toml @@ -2,5 +2,5 @@ PYTHON_VERSION = "3.8" [[headers]] for = "/*" - [[headers.values]] + [headers.values] X-Robots-Tag = "none" diff --git a/requirements.txt b/requirements.txt index 1cbcdb3e3..875a63ae9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ Sphinx<5,>=3 # sphinx-book-theme 0.3.3 has requirement sphinx<5,>=3 graphviz lesscpy linkify-it-py -myst-parser +myst-parser>=2.0.0,<3.0.0 # Remove pin when upgrading to latest sphinx-book-theme pydata-sphinx-theme==0.8.1 # Build fails in 0.9.0. See https://github.com/plone/documentation/issues/1297 sphinx-autobuild sphinx-book-theme==0.3.3 # Temporary pin until we can sort out HTML refactoring. From 702eb7c0d406d4bd7f74a1c131eb5fa15cbee908 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 25 Apr 2024 00:59:00 -0700 Subject: [PATCH 235/810] Remove pin of myst-parser to try auto-resolution --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 875a63ae9..1cbcdb3e3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ Sphinx<5,>=3 # sphinx-book-theme 0.3.3 has requirement sphinx<5,>=3 graphviz lesscpy linkify-it-py -myst-parser>=2.0.0,<3.0.0 # Remove pin when upgrading to latest sphinx-book-theme +myst-parser pydata-sphinx-theme==0.8.1 # Build fails in 0.9.0. See https://github.com/plone/documentation/issues/1297 sphinx-autobuild sphinx-book-theme==0.3.3 # Temporary pin until we can sort out HTML refactoring. From 8ec7fbd74e10406d9c1dbc167d43d7ef7916e53f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 25 Apr 2024 01:08:35 -0700 Subject: [PATCH 236/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 1ce0d1ecb..8c37e24f9 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 1ce0d1ecbf4ba7711cfd4577884ff05c201d08c8 +Subproject commit 8c37e24f969077424cedfeef416f30dd43878a16 From e60cfd99ab4f003906131bd28be59e50270694ae Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 25 Apr 2024 16:04:40 -0700 Subject: [PATCH 237/810] Bump PLONE_BACKEND_PATCH_VERSION to 6.0.11 --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 64df6bca1..d4e89a5b6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -341,7 +341,7 @@ def source_replace(app, docname, source): # Dict of replacements. source_replacements = { "{PLONE_BACKEND_MINOR_VERSION}": "6.0", - "{PLONE_BACKEND_PATCH_VERSION}": "6.0.10.1", + "{PLONE_BACKEND_PATCH_VERSION}": "6.0.11", "{NVM_VERSION}": "0.39.5", "{SUPPORTED_PYTHON_VERSIONS}": "3.8, 3.9, 3.10, 3.11, or 3.12", } From 973f48a93d2187aeb630acdf947fdc0c8bebf0e9 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 27 Apr 2024 09:58:16 -0700 Subject: [PATCH 238/810] Temporarily pin myst-parser==1.0.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1cbcdb3e3..6cfc9f302 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ Sphinx<5,>=3 # sphinx-book-theme 0.3.3 has requirement sphinx<5,>=3 graphviz lesscpy linkify-it-py -myst-parser +myst-parser==1.0.0 # Temporary pin until theme is updated. pydata-sphinx-theme==0.8.1 # Build fails in 0.9.0. See https://github.com/plone/documentation/issues/1297 sphinx-autobuild sphinx-book-theme==0.3.3 # Temporary pin until we can sort out HTML refactoring. From 1465d95c0a589f74b56fa0089aedbf3e08274218 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 27 Apr 2024 10:03:04 -0700 Subject: [PATCH 239/810] Unpin --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 6cfc9f302..1cbcdb3e3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ Sphinx<5,>=3 # sphinx-book-theme 0.3.3 has requirement sphinx<5,>=3 graphviz lesscpy linkify-it-py -myst-parser==1.0.0 # Temporary pin until theme is updated. +myst-parser pydata-sphinx-theme==0.8.1 # Build fails in 0.9.0. See https://github.com/plone/documentation/issues/1297 sphinx-autobuild sphinx-book-theme==0.3.3 # Temporary pin until we can sort out HTML refactoring. From b2d770b688e977e4c9f20938b520aab7bd1c67d2 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 28 Apr 2024 02:15:32 -0700 Subject: [PATCH 240/810] Update tips submodules/plone.api submodules/plone.restapi submodules/volto --- submodules/plone.api | 2 +- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index 08884b755..53adcfbe4 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit 08884b755450cdc5290d640b826d3f659025179f +Subproject commit 53adcfbe40060377a2d545dec07d0ae49b2db0bf diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 848dff077..c03a8c14d 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 848dff077a29cc5ceb52fc2373b3bf74d51cef49 +Subproject commit c03a8c14d903555d2e80e070c57e0b66e417d40b diff --git a/submodules/volto b/submodules/volto index 8c37e24f9..e7d6f1c0b 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 8c37e24f969077424cedfeef416f30dd43878a16 +Subproject commit e7d6f1c0be483c6560a552bae615b3f80ec21c1e From fbab5c718487986f893eb46f11c6e8fe59f49e1a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 28 Apr 2024 13:52:48 -0700 Subject: [PATCH 241/810] Apply suggestions from code review --- docs/backend/fields.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/backend/fields.md b/docs/backend/fields.md index 28d438974..ca669384c 100644 --- a/docs/backend/fields.md +++ b/docs/backend/fields.md @@ -103,9 +103,9 @@ See [`plone.namedfile`](https://pypi.org/project/plone.namedfile/) and [plone.fo | `NamedBlobFile` | `NamedBlobFile` | A binary uploaded file stored as a ZODB blob. Requires the `blobs` extra to `plone.namedfile`. Otherwise identical to `NamedFile`. | `IField` | | `NamedBlobImage` | `NamedBlobImage` | A binary uploaded image stored as a ZODB blob. Requires the `blobs` extra to `plone.namedfile`. Otherwise identical to `NamedImage`. | `IField` | -#### NamedBlobImage +#### `NamedBlobImage` -The following example shows, how to create an Image object and attach the image file to it. +The following example shows how to create an `Image` object, and attach the image file to it. ```python img_obj = api.content.create( @@ -145,7 +145,8 @@ See [`plone.app.textfield`](https://pypi.org/project/plone.app.textfield/) for m | `RichText` | `RichTextValue` | Stores a `RichTextValue`, which encapsulates a raw text value, the source MIME type, and a cached copy of the raw text transformed to the default output MIME type. | `IField`, `IRichText` | -The RichText field allows for alternative markups and content filtering. +The `RichText` field allows for alternative markups and content filtering. +The following code sample shows how to create a schema with a `RichText` field. ```python from plone.app.textfield import RichText @@ -208,9 +209,9 @@ class ITestSchema(model.Schema): (backend-fields-richtextvalue-label)= -#### RichTextValue +#### `RichTextValue` -The `RichText` field, most of the time does not store a string. +The `RichText` field usually does not store a string. Instead, it stores a `RichTextValue` object. This is an immutable object that has the following properties. @@ -218,7 +219,7 @@ This is an immutable object that has the following properties. : A Unicode string with the original input markup. `mimeType` -: The MIME type of the original markup, for example `text/html` or `text/structured`. +: The MIME type of the original markup, for example, `text/html` or `text/structured`. `encoding` : The default character encoding used when transforming the input markup. @@ -251,7 +252,7 @@ context.body = RichTextValue("Some input text", mimeType="text/html", outputMime The standard widget used for a `RichText` field will correctly store this type of object for you, so it is rarely necessary to create one yourself. -##### Using RichText fields in templates +##### `RichText` fields in templates If you use a `DisplayForm`, the display widget for the `RichText` field will render the transformed output markup automatically. If you write TAL manually, you may try something like the following. @@ -280,7 +281,7 @@ This operation is approximately as efficient as rendering a simple `Text` field, Sometimes, you may want to invoke alternative transformations. Under the hood, the default implementation uses the `portal_transforms` tool to calculate a transform chain from the raw value's input MIME type to the desired output MIME type. -If you need to write your own transforms, take a look at [this tutorial](https://5.docs.plone.org/develop/plone/misc/portal_transforms.html). +If you need to write your own transforms, take a look at [Changing Portal Transforms Settings via Python](https://5.docs.plone.org/develop/plone/misc/portal_transforms.html). This is abstracted behind an `ITransformer` adapter to allow alternative implementations. To invoke a transformation in code, you can use the following syntax. @@ -300,8 +301,8 @@ If you write a page template, there is an even more convenient syntax.
``` -The first traversal name gives the name of the field on the context (`body` in this case). -The second and third give the output MIME type. +The first traversal name segment gives the name of the field on the context (`body` in this case). +The second and third segments give the output MIME type. If the MIME type is omitted, the default output MIME type will be used. ```{note} From 5c2fd099848402a0e819241f85be5df16e620802 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 28 Apr 2024 15:59:22 -0700 Subject: [PATCH 242/810] Move seealso in module federation --- docs/classic-ui/module-federation.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index 3dd79c525..f1b77ed58 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -10,11 +10,6 @@ html_meta: # Module Federation in Mockup - -```{seealso} -Webpack's documentation on [Module Federation](https://webpack.js.org/concepts/module-federation/). -``` - Module Federation allows sharing of dependencies between bundles. Each bundle includes the whole set of dependencies. However, if multiple bundles have the same dependencies they are loaded only once. @@ -26,7 +21,13 @@ There is a host bundle, as in the fictional example above, our bundle A. In Plone the host bundle is the main mockup bundle. Add-ons can add bundles called "remotes" which are initialized for module federation by the host bundle. +```{seealso} +Webpack's documentation on [Module Federation](https://webpack.js.org/concepts/module-federation/). +``` + + ## Using module federation + The following instructions are for you if you created an add-on with a Mockup pattern and you want to include the respective JavaScript code in your theme code. Starting with the webpack configuration that you get when creating a Barceloneta theme package via [plonecli][1], add the following: From aeedd859e95cad6fee6847039512f5c05d05be69 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 28 Apr 2024 16:00:47 -0700 Subject: [PATCH 243/810] Apply suggestions from code review --- docs/classic-ui/module-federation.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index f1b77ed58..54a6bcda7 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -78,11 +78,11 @@ Below this line add the following: ); ``` -Replace the name `myaddon` with your addon bundle's name (any unique name will do...), -replace the filename `myaddon-remote.min.js` with the file name you want to use for your remote bundle, -and replace `myaddon.min` with the corresponding key in `config.entry` that points to your `index.js`. +Replace the name `myaddon` with your add-on bundle's unique name. +Replace the filename `myaddon-remote.min.js` with the file name you want to use for your remote bundle. +Finally replace `myaddon.min` with the corresponding key in `config.entry` that points to your `index.js`. -For a full but simple example, see the Patterns generator [pat-PATTERN-TEMPLATE][2] or any other Pattern addon in the patternslib GitHub organisation. +For a full but simple example, see the Patterns generator [pat-PATTERN-TEMPLATE][2] or any other Pattern add-on in the [patternslib GitHub organization](https://github.com/patternslib/). For a complex example with Mockup integration see [plone.app.mosaic][3] and [Mockup][4] itself. [1]: https://pypi.org/project/plonecli/ From b180c91edc01f1e86b9c7c376ccb3a2a667df595 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 28 Apr 2024 16:08:41 -0700 Subject: [PATCH 244/810] Tidy up module-federation.md, prepare for final review and merge --- docs/classic-ui/module-federation.md | 47 +++++++++++++--------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index 54a6bcda7..b46bf9aa0 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -3,18 +3,18 @@ html_meta: "description": "How to use Module Federation in Mockup and add-on bundles." "property=og:description": "How to use Module Federation in Mockup and add-on bundles." "property=og:title": "Module Federation in Mockup" - "keywords": "Plone, Classic UI, classic-ui, Mockup, mockup, Module Federation, Webpack, JavaScript" + "keywords": "Plone, Classic UI, classic-ui, Mockup, mockup, module federation, webpack, JavaScript" --- (classic-ui-module-federation-in-mockup-label)= -# Module Federation in Mockup +# Module federation in Mockup Module Federation allows sharing of dependencies between bundles. Each bundle includes the whole set of dependencies. -However, if multiple bundles have the same dependencies they are loaded only once. +However, if multiple bundles have the same dependencies, then they are loaded only once. -For example, if bundle A and B both depend on jQuery and bundle A has already loaded it, bundle B can just reuse the already loaded jQuery file. +For example, if bundle A and B both depend on jQuery and bundle A has already loaded it, then bundle B can just reuse the already loaded jQuery file. But if only bundle B is loaded, it uses its own bundled version of the jQuery library. There is a host bundle, as in the fictional example above, our bundle A. @@ -26,28 +26,29 @@ Webpack's documentation on [Module Federation](https://webpack.js.org/concepts/m ``` -## Using module federation +## Use module federation -The following instructions are for you if you created an add-on with a Mockup pattern and you want to include the respective JavaScript code in your theme code. -Starting with the webpack configuration that you get when creating a Barceloneta theme package via [plonecli][1], add the following: +If you created an add-on with a Mockup pattern, and you want to include the respective JavaScript code in your theme code, then the following instructions are for you. -Create a new entry point `index.js` which only imports the normal entry point. +Starting with the webpack configuration that you get when creating a Barceloneta theme package via [`plonecli`](https://pypi.org/project/plonecli/), add the following. + +Create a new entry point {file}`index.js` which only imports the normal entry point. ```js import("./patterns"); ``` -Next add the module federation plugin in `webpack.config.js`. +Next add the module federation plugin in {file}`webpack.config.js`. There is a configuration factory `mf_config` which you can use for that. -Add the following line near the top of the file: +Add the following line near the top of the file. ```js const mf_config = require("@patternslib/dev/webpack/webpack.mf"); ``` Import all the dependencies you want to share. -Potentially these are the ones from Patternslib, Mockup and your own dependencies. -You can just add the Patternslib and Mockup dependencies, even if you are not using them. +Potentially these are the ones from Patternslib, Mockup, and your own dependencies. +You can add the Patternslib and Mockup dependencies, even if you are not using them. ```js const package_json = require("./package.json"); @@ -55,13 +56,13 @@ const package_json_mockup = require("@plone/mockup/package.json"); const package_json_patternslib = require("@patternslib/patternslib/package.json"); ``` -Then find the following line: +Then find the following line. ```js config = patternslib_config(env, argv, config, ["@plone/mockup"]); ``` -Below this line add the following: +Below this line add the following. ```js config.plugins.push( @@ -79,26 +80,20 @@ Below this line add the following: ``` Replace the name `myaddon` with your add-on bundle's unique name. -Replace the filename `myaddon-remote.min.js` with the file name you want to use for your remote bundle. -Finally replace `myaddon.min` with the corresponding key in `config.entry` that points to your `index.js`. +Replace the file name {file}`myaddon-remote.min.js` with the file name you want to use for your remote bundle. +Finally replace `myaddon.min` with the corresponding key in `config.entry` that points to your {file}`index.js`. -For a full but simple example, see the Patterns generator [pat-PATTERN-TEMPLATE][2] or any other Pattern add-on in the [patternslib GitHub organization](https://github.com/patternslib/). -For a complex example with Mockup integration see [plone.app.mosaic][3] and [Mockup][4] itself. +For a full and basic example, see the Patterns generator [pat-PATTERN-TEMPLATE](https://github.com/Patternslib/pat-PATTERN_TEMPLATE/blob/master/webpack.config.js) or any other Pattern add-on in the [patternslib GitHub organization](https://github.com/patternslib/). +For a complex example with Mockup integration see [`plone.app.mosaic`](https://github.com/plone/plone.app.mosaic/blob/master/webpack.config.js) and [Mockup](https://github.com/plone/mockup/blob/master/webpack.config.js) itself. -[1]: https://pypi.org/project/plonecli/ -[2]: https://github.com/Patternslib/pat-PATTERN_TEMPLATE/blob/master/webpack.config.js -[3]: https://github.com/plone/plone.app.mosaic/blob/master/webpack.config.js -[4]: https://github.com/plone/mockup/blob/master/webpack.config.js ## Special case: global modules `jQuery` and `Bootstrap` -In order to preserve compatibility with older add-ons and JavaScript implementations, -the modules `jQuery` and `Bootstrap` are stored in the global `window` namespace. -So constructs like the following are still working: +To preserve compatibility with older add-ons and JavaScript implementations, the modules `jQuery` and `Bootstrap` are stored in the global `window` namespace. +Constructs like the following still work: ```js (function($) { // JS code which uses $ })(jQuery); ``` - From 155fe18868383144f0febcc0731a77ec28a72647 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 29 Apr 2024 00:24:35 -0700 Subject: [PATCH 245/810] Update tip submodules/plone.api --- submodules/plone.api | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/plone.api b/submodules/plone.api index 53adcfbe4..7cb48160d 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit 53adcfbe40060377a2d545dec07d0ae49b2db0bf +Subproject commit 7cb48160d570d7fad0a4c3bd67c306e23299382b From 2b66e7ad90476ae38058db08d4f002798e45a67b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 29 Apr 2024 14:22:29 -0700 Subject: [PATCH 246/810] Clarify what needs to be upgraded in regards to TinyMCE --- .../version-specific-migration/upgrade-to-61.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md index 0f55d14e8..b5b604b76 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md @@ -15,16 +15,15 @@ Plone 6.1 has seen the following major changes. Some may require changes in your setup. -## TinyMCE upgraded +## TinyMCE upgraded in Classic UI -Plone 6.0 uses TinyMCE, a rich text editor for websites. +In Plone 6.0, the Classic UI frontend uses TinyMCE 5, a rich text editor for websites. TinyMCE 5 reached its end of support on April 20, 2023. -For Plone 6.1, TinyMCE has been upgraded from version 5 to 7. +For Plone 6.1, Classic UI upgraded TinyMCE from version 5 to 7. + +If you upgrade a site using Classic UI from Plone 6.0 to 6.1, you do not need to take any action, unless you implemented custom plugins, or you use a plugin which got removed or moved to premium in TinyMCE versions 6 or 7. +To upgrade your plugin implementation to TinyMCE 7, see the [upgrade guides](https://www.tiny.cloud/docs/tinymce/6/migration-from-5x/#plugins). -```{seealso} -- [How to upgrade TinyMCE 5 to TinyMCE 6](https://www.tiny.cloud/blog/upgrade-to-tinymce-6/) -- [Upgrading TinyMCE](https://www.tiny.cloud/docs/tinymce/latest/upgrading/) -``` ### Enable the TinyMCE accordion plugin From e3f4a1666941487da502b02607eb0a33d54ef103 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 29 Apr 2024 14:34:14 -0700 Subject: [PATCH 247/810] Create new section "Optimize and tune" --- docs/deployment/components.md | 3 --- docs/deployment/index.md | 1 + docs/deployment/optimize-and-tune.md | 30 ++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 docs/deployment/optimize-and-tune.md diff --git a/docs/deployment/components.md b/docs/deployment/components.md index 5c8dc91d6..d0188f2b7 100644 --- a/docs/deployment/components.md +++ b/docs/deployment/components.md @@ -27,9 +27,6 @@ You need the following components to deploy a Plone application. - {term}`Load balancer` or router - Database - Mail service -- Optimization tasks - - Database parameters - - https://5.docs.plone.org/manage/deploying/performance/index.html - Maintenance tasks - Database backup - Packing database - https://5.docs.plone.org/manage/deploying/packing.html diff --git a/docs/deployment/index.md b/docs/deployment/index.md index bb1b7008c..fca7b1cc2 100644 --- a/docs/deployment/index.md +++ b/docs/deployment/index.md @@ -27,5 +27,6 @@ components server-environment continuous-integration-and-deployment orchestration +optimize-and-tune caching/index ``` diff --git a/docs/deployment/optimize-and-tune.md b/docs/deployment/optimize-and-tune.md new file mode 100644 index 000000000..dcde9f697 --- /dev/null +++ b/docs/deployment/optimize-and-tune.md @@ -0,0 +1,30 @@ +--- +myst: + html_meta: + "description": "Optimize and tune a Plone 6 application for deployment" + "property=og:description": "Optimize and tune a Plone 6 application for deployment" + "property=og:title": "Optimize and tune a Plone 6 application for deployment" + "keywords": "Plone, deployment, optimize, optimization, tune, backend, volto, frontend, load balancer, database, maintenance" +--- + +(deployment-optimize-and-tune-label)= + +# Optimize and tune + +This page in the deployment guide describes how to optimize and tune your Plone application. + + +(deployment-optimize-and-tune-database-parameters-label)= + +## Database parameters + +```{todo} +Insert database parameters here. +``` + + +(deployment-optimize-and-tune-future-heading-tbd-label)= + +## Future heading TBD + +[Plone 5.2 documentation, Performance and tuning](https://5.docs.plone.org/manage/deploying/performance/index.html) From a25c576d2104c4e1c0840e85d12c1b6e072a3f59 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 29 Apr 2024 14:34:56 -0700 Subject: [PATCH 248/810] typo --- docs/deployment/components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/deployment/components.md b/docs/deployment/components.md index d0188f2b7..249975de3 100644 --- a/docs/deployment/components.md +++ b/docs/deployment/components.md @@ -4,7 +4,7 @@ myst: "description": "Components of a Plone 6 application for deployment" "property=og:description": "Components of a Plone 6 application for deployment" "property=og:title": "Components of a Plone 6 application for deployment" - "keywords": "Plone, deployment, components, backend, volto, fronted, TLS termination proxy, load balancer, router, database, mail service, optimization, maintenance" + "keywords": "Plone, deployment, components, backend, volto, frontend, TLS termination proxy, load balancer, router, database, mail service, optimization, maintenance" --- (deployment-components-label)= From 3d97d4148c04c6cada95a4b2ff19e681f443765e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 29 Apr 2024 14:35:43 -0700 Subject: [PATCH 249/810] Move monitoring to Optional subheading --- docs/deployment/components.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/deployment/components.md b/docs/deployment/components.md index 249975de3..b5b0e5005 100644 --- a/docs/deployment/components.md +++ b/docs/deployment/components.md @@ -30,7 +30,6 @@ You need the following components to deploy a Plone application. - Maintenance tasks - Database backup - Packing database - https://5.docs.plone.org/manage/deploying/packing.html - - Monitoring - Log rotation - Firewall - Attack protection @@ -51,5 +50,5 @@ Recommended components, although not required, will help with the performance an ## Optional components +- Monitoring - Search - From 9d29c455f12282530f29200a467394da0f80e4b5 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 29 Apr 2024 14:44:20 -0700 Subject: [PATCH 250/810] Move some topics from maintenance.md to server-environment.md --- docs/deployment/components.md | 4 ---- docs/deployment/server-environment.md | 7 +++++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/deployment/components.md b/docs/deployment/components.md index b5b0e5005..0b5207a12 100644 --- a/docs/deployment/components.md +++ b/docs/deployment/components.md @@ -31,10 +31,6 @@ You need the following components to deploy a Plone application. - Database backup - Packing database - https://5.docs.plone.org/manage/deploying/packing.html - Log rotation - - Firewall - - Attack protection - - DNS - - Host name resolution (deployment-recommended-components-label)= diff --git a/docs/deployment/server-environment.md b/docs/deployment/server-environment.md index 2a50fb4b7..d5c1380de 100644 --- a/docs/deployment/server-environment.md +++ b/docs/deployment/server-environment.md @@ -23,3 +23,10 @@ Should we reuse or update {ref}`install-packages-hardware-requirements-label`? - disk - SSH key - preparation for orchestration + +Although this documentation does not cover the following topics, you will need to consider them when setting up your server environment. + +- Firewall +- Attack protection +- DNS +- website configuration of virtual hosts, and listening on and binding to IP addresses From 758177296d8be7f901b9bcd059b8f9c973f2aa2d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 29 Apr 2024 22:53:42 -0700 Subject: [PATCH 251/810] Update tips submodules/plone.api submodules/plone.restapi submodules/volto --- submodules/plone.api | 2 +- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index 7cb48160d..f2ac29ae8 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit 7cb48160d570d7fad0a4c3bd67c306e23299382b +Subproject commit f2ac29ae8fe9509f877a01a3f12898792f2864cf diff --git a/submodules/plone.restapi b/submodules/plone.restapi index c03a8c14d..f2e365394 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit c03a8c14d903555d2e80e070c57e0b66e417d40b +Subproject commit f2e365394f19d2841cf0417bc69b89b18cdcacb9 diff --git a/submodules/volto b/submodules/volto index e7d6f1c0b..01cbe72d7 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit e7d6f1c0be483c6560a552bae615b3f80ec21c1e +Subproject commit 01cbe72d7fc711c8521fbaec55f7ca45d843e3d8 From e71f735bdbc17d8942e8f1c1214996a59c264080 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 30 Apr 2024 00:54:47 -0700 Subject: [PATCH 252/810] Add placeholder for `z3c.form` and `plone.app.z3cform` --- .../version-specific-migration/upgrade-to-61.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md index b5b604b76..99a66aa99 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md @@ -55,3 +55,17 @@ To upgrade your plugin implementation to TinyMCE 7, see the [upgrade guides](htt ```{seealso} - [Addon collective.outputfilters.tinymceaccordion](https://github.com/collective/collective.outputfilters.tinymceaccordion) ``` + + +## `z3c.form` and `plone.app.z3cform` + +````{todo} +This is a placeholder. + +- Update deprecated imports +- New widget templates + +```{seealso} +https://github.com/plone/plone.app.z3cform/pull/181 +``` +```` \ No newline at end of file From 953bc414a08ca318721a30a8e2eff080313973ea Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Sat, 4 May 2024 22:01:16 +0200 Subject: [PATCH 253/810] Upgrade: drop py 3.8/3.9. p.a.multilingual is core add-on. --- .../upgrade-to-61.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md index 99a66aa99..6cdd363d1 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md @@ -68,4 +68,20 @@ This is a placeholder. ```{seealso} https://github.com/plone/plone.app.z3cform/pull/181 ``` -```` \ No newline at end of file +```` + +## Drop Python 3.8 and 3.9 + +We only support Python 3.10, 3.11, and 3.12. + + +## `plone.app.multilingual` is a core add-on + +`plone.app.multilingual` is the package that adds multilingual support to Plone, so for having content in multiple languages. +Until Plone 6.0 this was a dependency of `Products.CMFPlone`, so it was available for installation in all Plone sites. +In Plone 6.1 it has become a dependency of the `Plone` package. + +If your project or your add-on needs this package, and you only depend on `Products.CMFPlone` until now, you should add `plone.app.multilingual` as dependency. +Then your project or add-on will keep working in both Plone 6.0 and 6.1. + +The goal of turning more of the current core packages into core add-ons, is to make the core smaller, and in some cases solve circular dependencies. From 3fb7301a7cb936ec5bd071a186b9290e3be1c371 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 4 May 2024 21:32:58 -0700 Subject: [PATCH 254/810] Move Python support to the first item. Nitpicky grammar fixes. --- .../upgrade-to-61.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md index 6cdd363d1..1f1f11a09 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md @@ -15,6 +15,11 @@ Plone 6.1 has seen the following major changes. Some may require changes in your setup. +## Drop Python 3.8 and 3.9 + +We only support Python 3.10, 3.11, and 3.12. + + ## TinyMCE upgraded in Classic UI In Plone 6.0, the Classic UI frontend uses TinyMCE 5, a rich text editor for websites. @@ -70,18 +75,14 @@ https://github.com/plone/plone.app.z3cform/pull/181 ``` ```` -## Drop Python 3.8 and 3.9 - -We only support Python 3.10, 3.11, and 3.12. - ## `plone.app.multilingual` is a core add-on -`plone.app.multilingual` is the package that adds multilingual support to Plone, so for having content in multiple languages. -Until Plone 6.0 this was a dependency of `Products.CMFPlone`, so it was available for installation in all Plone sites. -In Plone 6.1 it has become a dependency of the `Plone` package. +`plone.app.multilingual` is the package that adds multilingual support to Plone, allowing the storage and display of content in multiple languages. +In Plone 6.0 and earlier, this was a dependency of `Products.CMFPlone`, making it available for installation in all Plone sites. +In Plone 6.1 it is now a dependency of the `Plone` package. -If your project or your add-on needs this package, and you only depend on `Products.CMFPlone` until now, you should add `plone.app.multilingual` as dependency. +If your project or your add-on needs this package, and you only depend on `Products.CMFPlone` until now, you should add `plone.app.multilingual` as a dependency. Then your project or add-on will keep working in both Plone 6.0 and 6.1. -The goal of turning more of the current core packages into core add-ons, is to make the core smaller, and in some cases solve circular dependencies. +The goal of turning more of the current core packages into core add-ons is to make the core smaller, and in some cases solve circular dependencies. From 6468ee67d6a3f35a2a36c3ab32b3824968239c72 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 4 May 2024 21:36:24 -0700 Subject: [PATCH 255/810] Revert "Update tips submodules/plone.api submodules/plone.restapi submodules/volto" This reverts commit 758177296d8be7f901b9bcd059b8f9c973f2aa2d. --- submodules/plone.api | 2 +- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index f2ac29ae8..7cb48160d 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit f2ac29ae8fe9509f877a01a3f12898792f2864cf +Subproject commit 7cb48160d570d7fad0a4c3bd67c306e23299382b diff --git a/submodules/plone.restapi b/submodules/plone.restapi index f2e365394..c03a8c14d 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit f2e365394f19d2841cf0417bc69b89b18cdcacb9 +Subproject commit c03a8c14d903555d2e80e070c57e0b66e417d40b diff --git a/submodules/volto b/submodules/volto index 01cbe72d7..e7d6f1c0b 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 01cbe72d7fc711c8521fbaec55f7ca45d843e3d8 +Subproject commit e7d6f1c0be483c6560a552bae615b3f80ec21c1e From 64a69c6a90042f8ee200cddeeaa11a5a2e73eeb3 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 4 May 2024 21:37:46 -0700 Subject: [PATCH 256/810] Update tips submodules/plone.api submodules/plone.restapi submodules/volto --- submodules/plone.api | 2 +- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index 7cb48160d..7dc89978d 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit 7cb48160d570d7fad0a4c3bd67c306e23299382b +Subproject commit 7dc89978db5a894a8474c64e29f24fbdfc78e339 diff --git a/submodules/plone.restapi b/submodules/plone.restapi index c03a8c14d..5e989dd83 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit c03a8c14d903555d2e80e070c57e0b66e417d40b +Subproject commit 5e989dd839c5e6f4db5ebb0a619f8d539a40dde5 diff --git a/submodules/volto b/submodules/volto index e7d6f1c0b..883d25a9d 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit e7d6f1c0be483c6560a552bae615b3f80ec21c1e +Subproject commit 883d25a9dc4224fd4523348622074aa96d16fd2d From 0936804a47ca46a4b0d7b93035e94a9c16e26da6 Mon Sep 17 00:00:00 2001 From: MrTango Date: Wed, 8 May 2024 17:55:18 +0300 Subject: [PATCH 257/810] set image directly in create call --- docs/backend/fields.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/backend/fields.md b/docs/backend/fields.md index ca669384c..ed878afdf 100644 --- a/docs/backend/fields.md +++ b/docs/backend/fields.md @@ -112,10 +112,10 @@ img_obj = api.content.create( container=ww_article, type="Image", id="test.jpg", -) -img_obj.image = NamedBlobImage( - data=img_file, - filename="test.jpg", + image=NamedBlobImage( + data=img_file, + filename="test.jpg", + ) ) ``` From aaa3d17d7962a07934f82d474f22276fa89abeb2 Mon Sep 17 00:00:00 2001 From: MrTango Date: Wed, 8 May 2024 17:57:42 +0300 Subject: [PATCH 258/810] fix linting in code example --- docs/backend/fields.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/backend/fields.md b/docs/backend/fields.md index ed878afdf..d2dc8d4c8 100644 --- a/docs/backend/fields.md +++ b/docs/backend/fields.md @@ -199,9 +199,9 @@ class ITestSchema(model.Schema): body = RichText( title="Body text", - default_mime_type='text/x-rst', - output_mime_type='text/x-html', - allowed_mime_types=('text/x-rst', 'text/structured',), + default_mime_type="text/x-rst", + output_mime_type="text/x-html", + allowed_mime_types=("text/x-rst", "text/structured",), default=defaultBody, ) ``` From ce5009d5cce5d21daffc04a647a281d4adad5912 Mon Sep 17 00:00:00 2001 From: MrTango Date: Wed, 8 May 2024 17:59:28 +0300 Subject: [PATCH 259/810] linting --- docs/backend/fields.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend/fields.md b/docs/backend/fields.md index d2dc8d4c8..b7fa2ad71 100644 --- a/docs/backend/fields.md +++ b/docs/backend/fields.md @@ -290,7 +290,7 @@ To invoke a transformation in code, you can use the following syntax. from plone.app.textfield.interfaces import ITransformer transformer = ITransformer(context) -transformedValue = transformer(context.body, 'text/plain') +transformedValue = transformer(context.body, "text/plain") ``` The `__call__()` method of the `ITransformer` adapter takes a `RichTextValue` object and an output MIME type as parameters. From be3a03075ae2863971a8ea3e2cbe6eedfd14e4f1 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Wed, 8 May 2024 18:39:14 +0200 Subject: [PATCH 260/810] Point to Plone 6.0.11.1. Merge once the plone-backend image is ready, see https://github.com/plone/plone-backend/pull/141 --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index d4e89a5b6..707573de6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -341,7 +341,7 @@ def source_replace(app, docname, source): # Dict of replacements. source_replacements = { "{PLONE_BACKEND_MINOR_VERSION}": "6.0", - "{PLONE_BACKEND_PATCH_VERSION}": "6.0.11", + "{PLONE_BACKEND_PATCH_VERSION}": "6.0.11.1", "{NVM_VERSION}": "0.39.5", "{SUPPORTED_PYTHON_VERSIONS}": "3.8, 3.9, 3.10, 3.11, or 3.12", } From 55170bc598065f160d4dd41c0046824549455e6e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 9 May 2024 17:29:50 -0700 Subject: [PATCH 261/810] Add `sphinx-examples` extension --- docs/contributing/documentation/themes-and-extensions.md | 1 + requirements.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/contributing/documentation/themes-and-extensions.md b/docs/contributing/documentation/themes-and-extensions.md index 490b489b1..1e3d80c9d 100644 --- a/docs/contributing/documentation/themes-and-extensions.md +++ b/docs/contributing/documentation/themes-and-extensions.md @@ -42,6 +42,7 @@ We use several MyST and Sphinx extensions to enhance the presentation of Plone d - [`myst_parser`](https://myst-parser.readthedocs.io/en/latest/) parses MyST, a rich and extensible flavour of Markdown for authoring documentation. - [`sphinx-design`](https://sphinx-design.readthedocs.io/en/latest/), with a configuration name of `sphinx_design`, adds grids, cards, icons, badges, buttons, tabs, and dropdowns. +- [`sphinx-examples`](https://ebp-sphinx-examples.readthedocs.io/en/latest/) adds "example snippets" that allow you to show off source Markdown and the result of rendering it in Sphinx. - [`sphinx-notfound-page`](https://sphinx-notfound-page.readthedocs.io/en/latest/index.html), with a configuration name of `notfound.extension`, creates a custom 404 page and helps generate proper static resource links to render the page properly. - [`sphinx.ext.autodoc`](https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html) pulls in documentation from Python docstrings to generate reStructuredText which in turn gets parsed by Sphinx and rendered to the output format. It is used by {doc}`/plone.api/index`. diff --git a/requirements.txt b/requirements.txt index 1cbcdb3e3..fc386f263 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,6 +9,7 @@ sphinx-autobuild sphinx-book-theme==0.3.3 # Temporary pin until we can sort out HTML refactoring. sphinx-copybutton sphinx-design # Documentation only +sphinx-examples # Documentation only sphinx-notfound-page # Documentation only sphinx-reredirects sphinx-sitemap From b5f2797ddbf13f21e24cb823fba6a92c17bc8adc Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 9 May 2024 17:32:47 -0700 Subject: [PATCH 262/810] Trim to avoid syntax error --- docs/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/glossary.md b/docs/glossary.md index 19aa0cc52..6946b6827 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -744,7 +744,7 @@ Plone frontend A frontend consists of the user interface elements of a web application. Beginning with Plone 6, the default frontend is {term}`Volto`. {term}`Classic UI` is a secondary frontend that is part of the {term}`Plone backend`. - + TLS Transport Layer Security Transport Layer Security (TLS) is a cryptographic protocol designed to provide communications security over a computer network. From bd38efc631df543de694b89b7ff2d38b9a707202 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 9 May 2024 18:19:12 -0700 Subject: [PATCH 263/810] Simplify examples, tidy up requirements.txt --- docs/conf.py | 1 + docs/contributing/documentation/authors.md | 8 +- .../documentation/myst-reference.md | 138 +++--------------- docs/glossary.md | 9 +- requirements.txt | 4 +- 5 files changed, 31 insertions(+), 129 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index d4e89a5b6..17cfc6bf0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -49,6 +49,7 @@ "sphinx.ext.todo", "sphinx_copybutton", "sphinx_design", + "sphinx_examples", "sphinx_reredirects", "sphinx_sitemap", "sphinxcontrib.httpdomain", # plone.restapi diff --git a/docs/contributing/documentation/authors.md b/docs/contributing/documentation/authors.md index 38b71bd99..2a21fb2ac 100644 --- a/docs/contributing/documentation/authors.md +++ b/docs/contributing/documentation/authors.md @@ -127,14 +127,10 @@ When authors add a link to the documentation, it must be a valid public URL with If it is not a valid link, or is private or local, then you must exclude it from `linkcheck` by wrapping it in single backticks. -```md +```{example} Visit the URL `http://www.example.com` for an example. ``` -This will render as follows. - -> Visit the URL `http://www.example.com` for an example. - If a link has succumbed to bit rot, then try finding the most recently scraped version on the [Internet Archive Wayback Machine](https://web.archive.org/), and update the link. To validate links, run the following command. @@ -240,6 +236,8 @@ Authors should include at least `description`, `property=og:description`, `prope The following is an example of `html_meta`. Note that the content of the two tags `description` and `property=og:description` should be identical. +% Cannot use sphinx-examples for this one. + ```md --- myst: diff --git a/docs/contributing/documentation/myst-reference.md b/docs/contributing/documentation/myst-reference.md index 399dd56e0..7c922d74a 100644 --- a/docs/contributing/documentation/myst-reference.md +++ b/docs/contributing/documentation/myst-reference.md @@ -47,17 +47,17 @@ Official MyST documentation #### Link to a chapter or page -```md +```{example} Here is how to set up and build the documentation locally {doc}`/contributing/documentation/setup-build`. ``` -Here is how to set up and build the documentation locally {doc}`/contributing/documentation/setup-build`. - (myst-reference-link-heading-label)= #### Link to a heading +% Headings cannot be nested in sphinx-examples + ```md (myst-reference-hello-heading-label)= @@ -75,7 +75,7 @@ Read the section {ref}`myst-reference-hello-heading-label`. #### Link to an arbitrary location -```md +```{example} (example-target-label)= I have an HTML anchor above me. @@ -83,21 +83,13 @@ I have an HTML anchor above me. Click the link to visit {ref}`my text `. ``` -(example-target-label)= - -I have an HTML anchor above me. - -Click the link to visit {ref}`my text `. - #### Link to external page -```md +```{example} Use [Shimmer](http://example.com) for cleaner whiter teeth. ``` -Use [Shimmer](http://example.com) for cleaner whiter teeth. - ### Images and figures @@ -140,7 +132,7 @@ Cards allow the display of a caption, create a link to the source image to displ The following MyST example will display as shown below. -`````md +`````{example} ````{card} ```{image} /_static/caching/caching-disabled.png :alt: Caching Control Panel @@ -151,15 +143,6 @@ _Caching Control Panel_ ```` ````` -````{card} -```{image} /_static/caching/caching-disabled.png -:alt: Caching Control Panel -:target: /_static/caching/caching-disabled.png -``` -+++ -_Caching Control Panel_ -```` - #### Accessibility with `alt` text @@ -174,37 +157,31 @@ Accessibility is part of the [Plone brand and identity](https://plone.org/access The following MyST example will display as shown below. -````md +````{example} ```{image} /_static/standards.png :alt: XKCD "Standards" comic strip ``` ```` -```{image} /_static/standards.png -:alt: XKCD "Standards" comic strip -``` - #### Inline images For inline images, we use the MyST extension [`html_image`](https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#html-images). +The HTML attribute `class` must be set to `inline` to render the image inline at `1rem`. +Images and figures should always include `alt` text. Example syntax is shown below. ```html You can copy Copy icon blocks. ``` -Note that the HTML attribute `class` must be set to `inline` to render the image inline at `1rem`. - -The above syntax renders as shown below. - > You can copy Copy icon blocks. -Images and figures should always include `alt` text. +#### Figure example -The following MyST example will display as shown below. +The following MyST example for `figure` will display as shown below. -````md +````{example} ```{eval-rst} .. figure:: /_static/voting_flowchart.png :alt: Voting flowchart @@ -224,24 +201,6 @@ The following MyST example will display as shown below. ``` ```` -```{eval-rst} -.. figure:: /_static/voting_flowchart.png - :alt: Voting flowchart - - This is a caption in a single paragraph. - - This is a legend, which consists of all elements after the caption. - It can include a table. - - ====== ======= - Symbol Meaning - ====== ======= - ⃞ Object - ⬭ View - ➞ Flow - ====== ======= -``` - ### Video @@ -255,23 +214,18 @@ If you include audio, it is helpful to include closed captions or a transcript. It is helpful to include overlays of key strokes, and mouse and other input gestures, to describe how to interact with the user interface. Paths to videos must resolve in both the main documentation and the submodule's documentation, if present. +Note that the path must be absolute to support both submodules and the main documentation. +Don't use file-relative paths. See {ref}`static-assets-label` for details. Example MyST syntax is shown below. -````md -```{video} /_static/user-manual/blocks/block-copy-cut.mp4 -``` -```` - -Note that the path must be absolute to support both submodules and the main documentation. -Don't use file-relative paths. -The above MyST markup renders as shown below. - +`````{example} ````{only} not text ```{video} /_static/user-manual/blocks/block-copy-cut.mp4 ``` ```` +````` ### Diagrams and graphs with Graphviz @@ -280,7 +234,7 @@ We use [Graphviz](https://graphviz.org/download/) and its Sphinx extension [`sph The following MyST example will display as shown below. -````markdown +````{example} ```{eval-rst} .. graphviz:: :align: center @@ -294,24 +248,12 @@ The following MyST example will display as shown below. ``` ```` -```{eval-rst} -.. graphviz:: - :align: center - - digraph viewstructure { - { - node [margin=5,shape=box] - } - ZCML -> {Python, Template}; - } -``` - ### Code block A Python code snippet without reStructuredText options, using a simple fence. -````md +````{example} ```python a = 2 print("my 1st line") @@ -319,15 +261,9 @@ print(f"my {a}nd line") ``` ```` -```python -a = 2 -print("my 1st line") -print(f"my {a}nd line") -``` - A Python code snippet with reStructuredText options, using a fence with the parsed reStructuredText directive `code-block`. -````md +````{example} ```{code-block} python :linenos: :emphasize-lines: 1, 3 @@ -338,28 +274,20 @@ print(f"my {a}nd line") ``` ```` -```{code-block} python -:linenos: -:emphasize-lines: 1, 3 - -a = 2 -print("my 1st line") -print(f"my {a}nd line") -``` ### Escape literal backticks inline -```md +```{example} This is MyST syntax for term ``{term}`React` `` ``` -This is MyST syntax for term ``{term}`React` `` - ### Glossary terms Add a term to the {ref}`glossary-label`, located at {file}`/glossary.md`. +% For sphinx-examples, do not add a glossary term, as it will conflict with that in the actual glossary. + ```md React [React](https://reactjs.org/) is a JavaScript library for building user interfaces. @@ -368,18 +296,16 @@ React Reference a term in the {ref}`glossary-label`. -```md +```{example} Using {term}`React` makes frontends fun again! ``` -Using {term}`React` makes frontends fun again! - ### Nesting directives You can [nest directives](https://myst-parser.readthedocs.io/en/latest/syntax/roles-and-directives.html#nesting-directives), such as [admonitions](https://myst-parser.readthedocs.io/en/latest/syntax/admonitions.html) and code blocks, by ensuring that the backtick-lines corresponding to the outermost directive are longer than the backtick-lines for the inner directives. -````` +`````{example} ````{tip} To use formatted string literals ("f-strings"), begin a string with `f` or `F` before the opening quotation mark or triple quotation mark. Inside this string, you can write a Python expression between `{` and `}` characters that can refer to variables or literal values. @@ -394,19 +320,3 @@ print(f"my {a}nd line") ``` ```` ````` - -This would be rendered as: - -````{tip} -To use formatted string literals ("f-strings"), begin a string with `f` or `F` before the opening quotation mark or triple quotation mark. -Inside this string, you can write a Python expression between `{` and `}` characters that can refer to variables or literal values. - -```{code-block} python -:linenos: -:emphasize-lines: 1, 3 - -a = 2 -print("my 1st line") -print(f"my {a}nd line") -``` -```` diff --git a/docs/glossary.md b/docs/glossary.md index 6946b6827..4e161d317 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -344,7 +344,7 @@ fence You can define a directive with backticks (`` ` ``) followed by a reStructuredText directive in curly brackets (`{}`), and a matching number of closing backticks. You can also nest fences by increasing the number of backticks. - `````md + `````{example} ````{warning} There be dragons! ```{important} @@ -353,13 +353,6 @@ fence ```` ````` - ````{warning} - There be dragons! - ```{important} - Dragons have feelings, too! - ``` - ```` - Open Graph The [Open Graph protocol](https://ogp.me/) enables any web page to become a rich object in a social graph. For instance, this is used on Facebook to allow any web page to have the same functionality as any other object on Facebook. diff --git a/requirements.txt b/requirements.txt index fc386f263..a6c516054 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,12 +4,12 @@ graphviz lesscpy linkify-it-py myst-parser -pydata-sphinx-theme==0.8.1 # Build fails in 0.9.0. See https://github.com/plone/documentation/issues/1297 +pydata-sphinx-theme<=0.8.99 # Build fails in 0.9.0. See https://github.com/plone/documentation/issues/1297 sphinx-autobuild sphinx-book-theme==0.3.3 # Temporary pin until we can sort out HTML refactoring. sphinx-copybutton sphinx-design # Documentation only -sphinx-examples # Documentation only +sphinx-examples sphinx-notfound-page # Documentation only sphinx-reredirects sphinx-sitemap From 51054097ed3386f6d029c25ab79ac0e024f4c396 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 9 May 2024 18:34:27 -0700 Subject: [PATCH 264/810] Simplify references and remove conflict --- docs/install/containers/images/index.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/install/containers/images/index.md b/docs/install/containers/images/index.md index 9c40293f1..c230db378 100644 --- a/docs/install/containers/images/index.md +++ b/docs/install/containers/images/index.md @@ -11,11 +11,11 @@ myst: The Plone community maintains the following official images: -| Image | Description | -| --- | --- | -| [plone/plone-backend](backend) | Plone backend. Could be used standalone or as a headless CMS | -| [plone/plone-frontend](frontend) | Plone default frontend written in React. Requires a Plone backend | -| [plone/plone-zeo](zeo) | ZEO server, a specialized database to be used with Plone backend | +| Image | Description | +|-----------------|-------------------------------------------------------------------| +| {doc}`backend` | Plone backend. Could be used standalone or as a headless CMS | +| {doc}`frontend` | Plone default frontend written in React. Requires a Plone backend | +| {doc}`zeo` | ZEO server, a specialized database to be used with Plone backend | ```{toctree} :maxdepth: 2 From a83aea0cf4ee92e73c4b5622d4f4d24e75e836c3 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 14 May 2024 02:35:09 -0700 Subject: [PATCH 265/810] Update tips submodules/plone.api submodules/plone.restapi submodules/volto --- submodules/plone.api | 2 +- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index 7dc89978d..8b9239030 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit 7dc89978db5a894a8474c64e29f24fbdfc78e339 +Subproject commit 8b92390306e036d48d1665cb4de74bff152a32e5 diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 5e989dd83..9bbb1d7cd 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 5e989dd839c5e6f4db5ebb0a619f8d539a40dde5 +Subproject commit 9bbb1d7cdac09f1e7788fbbc376d5ab1e126fcf9 diff --git a/submodules/volto b/submodules/volto index 883d25a9d..96eb4fa4c 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 883d25a9dc4224fd4523348622074aa96d16fd2d +Subproject commit 96eb4fa4c0a1cb28e89f8f6e457978f748cc5112 From 19cc776d601a8d27a9ec26de6a43de37063b44f7 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 14 May 2024 16:29:54 -0700 Subject: [PATCH 266/810] Add section of supported languages --- docs/i18n-l10n/index.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/i18n-l10n/index.md b/docs/i18n-l10n/index.md index 4f68a17d5..9551fe281 100644 --- a/docs/i18n-l10n/index.md +++ b/docs/i18n-l10n/index.md @@ -26,6 +26,14 @@ Plone fully supports internationalization and localization. Wikipedia article [Internationalization and localization](https://en.wikipedia.org/wiki/Internationalization_and_localization) ``` +## Supported languages + +Plone supports many language translations in its two frontends. +For Volto, see [`plone/volto`](https://github.com/plone/volto/tree/main/packages/volto/locales). +For Classic UI, see [`collective/plone.app.locales`](https://github.com/collective/plone.app.locales/tree/master/plone/app/locales/locales). + +You can contribute new languages to both frontends. + (i18n-l10n-code-versus-content-label)= From 4a1fda0d4171cf0af2e1d830a60319d4fb5210b1 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 14 May 2024 16:30:25 -0700 Subject: [PATCH 267/810] Add label --- docs/i18n-l10n/index.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/i18n-l10n/index.md b/docs/i18n-l10n/index.md index 9551fe281..efd6ce6de 100644 --- a/docs/i18n-l10n/index.md +++ b/docs/i18n-l10n/index.md @@ -26,6 +26,9 @@ Plone fully supports internationalization and localization. Wikipedia article [Internationalization and localization](https://en.wikipedia.org/wiki/Internationalization_and_localization) ``` + +(i18n-l10n-supported-languages)= + ## Supported languages Plone supports many language translations in its two frontends. From d6e0bd0bd3c5a440d141208cfbe49b8201f75dbb Mon Sep 17 00:00:00 2001 From: "Jens W. Klein" Date: Wed, 15 May 2024 14:02:29 +0200 Subject: [PATCH 268/810] update package deps mental model to reflect 6.1 --- coredev/packages-dependencies.md | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/coredev/packages-dependencies.md b/coredev/packages-dependencies.md index d6bcd581a..5f673b7ce 100644 --- a/coredev/packages-dependencies.md +++ b/coredev/packages-dependencies.md @@ -23,7 +23,7 @@ This document shows the current state as an orientation. There are multiple level of dependencies: -- package level (`setup.py`/`setup.cfg`) +- package level (`setup.py`/`setup.cfg`/`pyproject.toml`) - Python level (imports) - ZCML level (includes) - testing (need for layers, such as functional testing) @@ -41,22 +41,35 @@ A base mental model for how Plone is organized in Plone 6 since alpha 4 is shown ``` ┌────────────────────────────┐ -│ │ -│ On top of Products.CMFPlone│ -│ like: │ -│ - Plone │ -│ - plone.api │ -│ - plone.volto │ +│ "Plone" | +| The Integration of both | +| distributions in one | +| Release | +├────────────────────────────┤ +| Distributions: | +| - plone.volto | +| - plone.classicui | +├────────────────────────────┤ +│ Core-Addons │ +│ - plone.distribution │ +│ - plone.app.exportimport │ +│ - plone.app.discussion │ +│ - plone.app.multilingual │ +│ - plone.app.caching │ │ - plone.app.iterate │ │ - plone.app.update │ │ │ ├────────────────────────────┤ +│ Core-APIs │ +│ - plone.restapi │ +│ - plone.api │ +├────────────────────────────┤ │ │ │ Products.CMFPlone │ │ │ ├────────────────────────────┤ │ │ -│ The space between │ +│ The space between (core ) │ │ │ │ - most of plone.app.* │ │ - but also some other │ @@ -75,6 +88,7 @@ A base mental model for how Plone is organized in Plone 6 since alpha 4 is shown │ - plone.registry │ │ - plone.dexterity │ │ - plone.behavior │ +│ - plone.rest │ │ - .... │ │ │ └────────────────────────────┘ From 28e43485ab8f4b272c6fdef734c6b2cc0878abe0 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 15 May 2024 14:32:22 -0700 Subject: [PATCH 269/810] Add documentation for how to enable discussion in Plone 6.1 --- .../version-specific-migration/upgrade-to-61.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md index 1f1f11a09..bda2de2bd 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md @@ -86,3 +86,18 @@ If your project or your add-on needs this package, and you only depend on `Produ Then your project or add-on will keep working in both Plone 6.0 and 6.1. The goal of turning more of the current core packages into core add-ons is to make the core smaller, and in some cases solve circular dependencies. + + +(backend-upgrade-plone-v61-discussion-label)= + +## Discussion is disabled by default + +Discussion, a feature that allows visitors to your site to comment on pages, is disabled by default in Plone 6.1 and later. +To enable discussion, you need to perform the following tasks. + +% Please add sufficient details for how to do this task, then delete this comment. +% Also consider that there might be different approaches between Classic UI and Volto that need to be mentioned. + +1. Install the core add-on `plone.app.discussion`. +1. Enable add-on. +1. 🍻 From edb79ab5165ac5f04d6c996bb52cd08f2a47a4b1 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 15 May 2024 14:38:13 -0700 Subject: [PATCH 270/810] Make description technically correct for both visitors and developers --- .../upgrading/version-specific-migration/upgrade-to-61.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md index bda2de2bd..ef098ed69 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md @@ -92,7 +92,7 @@ The goal of turning more of the current core packages into core add-ons is to ma ## Discussion is disabled by default -Discussion, a feature that allows visitors to your site to comment on pages, is disabled by default in Plone 6.1 and later. +Discussion, a feature that allows visitors to your site to comment on web pages for any content type, is disabled by default in Plone 6.1 and later. To enable discussion, you need to perform the following tasks. % Please add sufficient details for how to do this task, then delete this comment. From d269d96072b6f75905419de46c4214163730bc0b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 15 May 2024 14:40:36 -0700 Subject: [PATCH 271/810] Two shorter sentences is better than one long one. --- .../upgrading/version-specific-migration/upgrade-to-61.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md index ef098ed69..cc61a3694 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md @@ -92,7 +92,8 @@ The goal of turning more of the current core packages into core add-ons is to ma ## Discussion is disabled by default -Discussion, a feature that allows visitors to your site to comment on web pages for any content type, is disabled by default in Plone 6.1 and later. +Discussion is a feature that allows your site visitors to comment on web pages for any content object. +Discussion is disabled by default in Plone 6.1 and later. To enable discussion, you need to perform the following tasks. % Please add sufficient details for how to do this task, then delete this comment. From b8b8cc1af64f3e680f2eecc01bd1c08921502101 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 16 May 2024 12:59:19 -0700 Subject: [PATCH 272/810] Revise instructions per https://github.com/plone/documentation/pull/1666#discussion_r1603741706 --- .../upgrading/version-specific-migration/upgrade-to-61.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md index cc61a3694..1b47d0379 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md @@ -99,6 +99,8 @@ To enable discussion, you need to perform the following tasks. % Please add sufficient details for how to do this task, then delete this comment. % Also consider that there might be different approaches between Classic UI and Volto that need to be mentioned. -1. Install the core add-on `plone.app.discussion`. -1. Enable add-on. +1. In your Python {file}`requirements.txt` or {file}`pyproject.toml` file, add the core add-on `plone.app.discussion` to your dependencies. +1. Run pip to install `plone.app.discussion`. +1. Restart the Plone backend to load `plone.app.discussion`. +1. Enable the {guilabel}`Discussion` add-on in the Plone control panel under {menuselection}`Site Setup --> General`. 1. 🍻 From 73c13d45cd040aef3352cb2f2412d2a0b3409512 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 20 May 2024 14:49:59 -0700 Subject: [PATCH 273/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 9bbb1d7cd..c7b8e076d 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 9bbb1d7cdac09f1e7788fbbc376d5ab1e126fcf9 +Subproject commit c7b8e076deeb3c1f4b468521d0ecabfb0731483a diff --git a/submodules/volto b/submodules/volto index 96eb4fa4c..93c30b2f2 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 96eb4fa4c0a1cb28e89f8f6e457978f748cc5112 +Subproject commit 93c30b2f235e941ccfce25d1ea534d273806a226 From 98464195548b807f56a974b0fdc3318c4a865774 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 20 May 2024 15:53:35 -0700 Subject: [PATCH 274/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 93c30b2f2..f03e4b7c6 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 93c30b2f235e941ccfce25d1ea534d273806a226 +Subproject commit f03e4b7c66be9c1c70680f2ae127b31e52bd0056 From c1672318dca21c50159f975a4a6c57c543d49c6b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 22 May 2024 05:42:44 -0700 Subject: [PATCH 275/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index f03e4b7c6..6e50c82df 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit f03e4b7c66be9c1c70680f2ae127b31e52bd0056 +Subproject commit 6e50c82dfb078da73388b6bc2dbc50cbb4d937a9 From 84c23a5516171508a5b3ee91fb70d10fce7f1411 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 31 May 2024 01:37:46 -0700 Subject: [PATCH 276/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 6e50c82df..6b493b439 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 6e50c82dfb078da73388b6bc2dbc50cbb4d937a9 +Subproject commit 6b493b4397bbf8f2b2f120ba442a64762caea761 From 0680ff9398e38b4d1e1bdaddbf5b9b8aa8904297 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 8 Jun 2024 15:12:00 -0700 Subject: [PATCH 277/810] Lower and revert linkcheck_timeout from 10 to 5 Closes #1612 and https://github.com/collective/collective.exportimport/issues/239 --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index a91d48bfa..00877dcf4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -101,7 +101,7 @@ r"https://www.youtube.com/playlist", # volto, TODO remove after installing sphinxcontrib.youtube ] linkcheck_anchors = True -linkcheck_timeout = 10 +linkcheck_timeout = 5 linkcheck_retries = 1 # The suffix of source filenames. From 410b0802775197803886b8605589bbb8fe6c7d98 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 17 Jun 2024 05:03:40 -0700 Subject: [PATCH 278/810] Update tips submodules/plone.api submodules/plone.restapi submodules/volto --- submodules/plone.api | 2 +- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index 8b9239030..b114c588c 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit 8b92390306e036d48d1665cb4de74bff152a32e5 +Subproject commit b114c588c6b3b3984c2d682db4098912e87d0a48 diff --git a/submodules/plone.restapi b/submodules/plone.restapi index c7b8e076d..9d11653fe 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit c7b8e076deeb3c1f4b468521d0ecabfb0731483a +Subproject commit 9d11653fe2da0c50ee4d74bef1d8a416879c4168 diff --git a/submodules/volto b/submodules/volto index 6b493b439..b629e5acb 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 6b493b4397bbf8f2b2f120ba442a64762caea761 +Subproject commit b629e5acbc2539f9ab1ef758fca4965eec9ffb44 From 197a9557d378861d74520f275f81eb8fdae6861a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 18 Jun 2024 23:11:54 -0700 Subject: [PATCH 279/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index b629e5acb..b844f3149 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit b629e5acbc2539f9ab1ef758fca4965eec9ffb44 +Subproject commit b844f3149459f472837ac69ea204bdd90d5557e0 From 3c547df8775d39423584c541b00c7b4df5bb0f63 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 18 Jun 2024 23:56:18 -0700 Subject: [PATCH 280/810] Clean up PR #1670 --- coredev/agreement.md | 17 +- coredev/continous-integration.md | 13 +- coredev/contributors_agreement_explained.md | 19 +- coredev/culture.md | 2 +- coredev/documentation.md | 39 +- coredev/getting-started-with-development.md | 92 ++-- coredev/git.md | 13 +- coredev/guidelines.md | 37 +- coredev/index.md | 9 +- coredev/mrdeveloper.md | 6 +- coredev/packages-dependencies.md | 495 +++++++++--------- coredev/plip-review.md | 60 +-- coredev/plips.md | 84 ++- coredev/release.md | 71 +-- coredev/roboto.md | 27 +- coredev/troubleshooting.md | 15 +- docs/conf.py | 6 + .../core/continuous-integration.md | 98 ++++ docs/contributing/core/documentation.md | 81 +++ docs/contributing/core/index.md | 248 +++++++++ docs/contributing/core/mrdeveloper.md | 36 ++ .../contributing/core/package-dependencies.md | 350 +++++++++++++ docs/contributing/core/plip-review.md | 101 ++++ docs/contributing/core/plips.md | 276 ++++++++++ docs/contributing/core/release.md | 127 +++++ docs/contributing/core/troubleshooting.md | 55 ++ docs/contributing/index.md | 38 +- docs/glossary.md | 11 +- requirements.txt | 1 + styles/Vocab/Plone/accept.txt | 6 + 30 files changed, 1886 insertions(+), 547 deletions(-) create mode 100644 docs/contributing/core/continuous-integration.md create mode 100644 docs/contributing/core/documentation.md create mode 100644 docs/contributing/core/index.md create mode 100644 docs/contributing/core/mrdeveloper.md create mode 100644 docs/contributing/core/package-dependencies.md create mode 100644 docs/contributing/core/plip-review.md create mode 100644 docs/contributing/core/plips.md create mode 100644 docs/contributing/core/release.md create mode 100644 docs/contributing/core/troubleshooting.md diff --git a/coredev/agreement.md b/coredev/agreement.md index 337895245..53b5bd6f8 100644 --- a/coredev/agreement.md +++ b/coredev/agreement.md @@ -7,6 +7,10 @@ myst: "keywords": "Contributing, Plone" --- +```{todo} +All this can go, it's redundant +``` + (contributing-to-plone-label)= # Contributing to Plone @@ -19,19 +23,19 @@ Sending in a contributors agreement does not guarantee your commit access to the We ask that before requesting core access you familiarize yourself a little with the community since they will help you get ramped up: -- Ask and (especially) answer questions on [the Plone forum](https://community.plone.org/) and in {doc}`Plone chat ` with a focus on getting to know the active developers a bit. +- Ask and (especially) answer questions on [the Plone forum](https://community.plone.org/) and in {doc}`Plone chat ` with a focus on getting to know the active developers a bit. -- Attend a [conference](https://plone.org/news-and-events/events/plone-conferences), [symposium](https://plone.org/news-and-events/events/regional), or participate in a [sprint](https://plone.org/news-and-events/events/sprints). +- Attend a [conference](https://plone.org/news-and-events/events/plone-conferences), [symposium](https://plone.org/news-and-events/events/regional), or participate in a [sprint](https://plone.org/news-and-events/events/sprints). There are plenty of opportunities to meet the community and start contributing through various coding sessions, either in person or on the web. You may even be able to get immediate core access at a conference if you are flexing your mad coding skills and the right people are attending. -- Get your feet wet by contributing to the [collective](https://collective.github.io/). +- Get your feet wet by contributing to the [collective](https://collective.github.io/). Don't worry about getting it perfect or asking for help. This way you get to know us and we improve our code together as a community. -- **Patches:** Historically we encouraged people to submit patches to the ticket collector. +- **Patches:** Historically we encouraged people to submit patches to the ticket collector. These tickets are usually ignored forever. Technically, for us to accept your patch, you must sign the contributors agreement. If you want to contribute fixes, please just sign the agreement and go through the standard GitHub pull request process described below until you feel comfortable to bypass review. @@ -39,7 +43,7 @@ We ask that before requesting core access you familiarize yourself a little with Once you have familiarized yourself with the community and you are excited to contribute to the core: -- Sign the contributor agreement at , then either send by postal mail to the address provided, or scan and email it to . +- Sign the contributor agreement at , then either send by postal mail to the address provided, or scan and email it to . This offers both copyright protection and ensures that the Plone Foundation is able to exercise some control over the codebase, ensuring it is not appropriated for someone's unethical purposes. For questions about why the agreement is required, please see [About the Plone Contributor Agreement ](https://plone.org/foundation/contributors-agreement). @@ -50,7 +54,6 @@ A common way to start contributing is to participate in a [Plone sprint](https:/ **Welcome to the Plone community!** - ## Dealing with pull requests on GitHub Before we can merge a pull request, we must ensure that the author has signed the Plone Contributor Agreement. @@ -58,6 +61,6 @@ Before we can merge a pull request, we must ensure that the author has signed th If they're listed in either the [Developers](https://github.com/orgs/plone/teams/developers/members) or [Contributors](https://github.com/orgs/plone/teams/contributors/members) team, the author has signed the Plone Contributor Agreement, so we can go ahead and merge. If they aren't listed there, they may have signed and returned the Plone Contributor Agreement, but they were not yet added to a team. -You can ask agreements@plone.org to verify. +You can ask to verify. Pull requests without a signed Plone Contributor Agreement can only be merged in trivial cases, and only by the release manager. diff --git a/coredev/continous-integration.md b/coredev/continous-integration.md index a1458cf41..3f225f7f2 100644 --- a/coredev/continous-integration.md +++ b/coredev/continous-integration.md @@ -7,6 +7,10 @@ myst: "keywords": "Plone, continuous integration, best practices" --- +```{todo} +needs redaction and upgrade +``` + # Essential continuous integration practices The CI system at [jenkins.plone.org](https://jenkins.plone.org) is a shared resource for Plone core developers to notify them of regressions in Plone core code. @@ -15,7 +19,6 @@ Build breakages are a normal and expected part of the development process. Our aim is to find errors and eliminate them as quickly as possible, without expecting perfection and zero errors. Though, there are some essential rules that needs to be followed in order to achieve a stable build. - ## 1) Don't check in on a broken build Do not make things more complicated for the developer who is responsible for breaking the build. @@ -34,7 +37,6 @@ If this is the case, there is no way around breaking a single build for a certai In this case run the all tests locally with all the changes and commit them within a time frame of ten minutes. ``` - ## 2) Always run all commit tests locally before committing Following this practice ensures the build stays green, and other developers can continue to work without breaking the first rule. @@ -46,33 +48,28 @@ Furthermore, a common source of errors on check-in is to forget to add some file If you follow this rule and your local build passes, you can be sure that this is because someone else checked in in the meantime, or because you forgot to add a new class or configuration file that you have been working on into the version control system. - ## 3) Wait for commit tests to pass before moving on Always monitor the build's progress, and fix the problem right away if it fails. You have a far better chance of fixing the build, if you just introduced a regression than later. Also another developer might have committed in the meantime (by breaking rule 1), making things more complicated for yours. - ## 4) Never go home on a broken build Taking into account the first rule of CI ("Don't check in on a broken build"), breaking the build essentially stops all other developers from working on it. Therefore going home on a broken build (or even on a build that has not finished yet) is **not** acceptable. It will prevent all the other developers to stop working on the build or fixing the errors that you introduced. - ## 5) Always be prepared to revert to the previous revision In order for the other developers to be able to work on the build, you should always be prepared to revert to the previous (passing) revision. - ## 6) Time-box fixing before reverting When the build breaks on check-in, try to fix it for ten minutes. If, after ten minutes, you aren't finished with the solution, revert to the previous version from your version control system. This way you will allow other developers to continue to work. - ## 7) Don't comment out failing tests Once you begin to enforce the previous rule, the result is often that developers start commenting out failing tests in order to get the build passing again as quick as possible. @@ -83,7 +80,6 @@ This means that we either caused a regression, made assumptions that are no long You should always either fix the code (if a regression has been found), modify the test (if one of the assumptions has changed), or delete it (if the functionality under test no longer exists). - ## 8) Take responsibility for all breakages that result from your changes If you commit a change and all the tests you wrote pass, but others break, the build is still broken. @@ -97,7 +93,6 @@ If you think you hit such a test, try to fix it (better) or re-run the Jenkins j In any case the developer who made the commit is responsible to make it pass. - ## Further Reading Those rules were taken from the excellent book "Continuous Delivery" by Jez Humble and David Farley (Addison Wesley), and have been adopted and rewritten for the Plone community. diff --git a/coredev/contributors_agreement_explained.md b/coredev/contributors_agreement_explained.md index 88851f6c8..2915b5e61 100644 --- a/coredev/contributors_agreement_explained.md +++ b/coredev/contributors_agreement_explained.md @@ -8,8 +8,7 @@ myst: --- ```{todo} -All this content should be audited against the plone.org site, probably removed, and replaced with a link to the authorative content on plone.org. -Duplicating content is a maintenance burden. +All this can go, it's redundant ``` # Contributor's Agreement for Plone explained @@ -18,8 +17,7 @@ Prospective contributors to the Plone code base are required to sign a contribut This document explains the purposes of this, along with questions and answers about what this means. -The Plone Contributor's Agreement can be found at https://plone.org/foundation/contributors-agreement. - +The Plone Contributor's Agreement can be found at . ## About the Plone Contributor Agreement @@ -28,10 +26,9 @@ Prior to the Foundation, the intellectual property of Plone was jointly held by The community members who formed the Foundation felt that having the Foundation hold these rights provides several benefits: -1. **Minimizing confusion / maximizing business compatibility** -- Organizations considering adopting Plone have a simple answer for "Who owns this?", rather than a more complicated answer that might scare away the legally-cautious. -2. **Trademark protection** -- By having the Foundation hold the trademarks and rights to the Plone branding assets, it can effectively protect these from unfair use. -3. **Guarantee of future Open Source versions** -- The Foundation's contributor agreement ensures that there will **always** be an OSI-approved version of Plone. - +1. **Minimizing confusion / maximizing business compatibility** -- Organizations considering adopting Plone have a simple answer for "Who owns this?", rather than a more complicated answer that might scare away the legally-cautious. +2. **Trademark protection** -- By having the Foundation hold the trademarks and rights to the Plone branding assets, it can effectively protect these from unfair use. +3. **Guarantee of future Open Source versions** -- The Foundation's contributor agreement ensures that there will **always** be an OSI-approved version of Plone. ## Questions and answers @@ -95,7 +92,7 @@ How much would a non-GPL version of Plone cost? > Despite this, though, many large and excellent contributions—such as Archetypes—have been made, and the Foundation hopes that companies will continue to do so. > In any event, a company that purchases a non-GPL license (should such ever become available) is contributing financial resources to our community, which can be used to further develop, market, and protect the GPL version of Plone. -- https://plone.org/foundation/contributors-agreement/agreement.pdf -- https://github.com/collective -- https://github.com/plone +- +- +- - [Policy for Contributor Agreements and patches](https://plone.org/foundation/materials/foundation-resolutions/patch-policy-052011) diff --git a/coredev/culture.md b/coredev/culture.md index 545b90996..ff30aa2d8 100644 --- a/coredev/culture.md +++ b/coredev/culture.md @@ -8,7 +8,7 @@ myst: --- ```{todo} -This content is probably redundant and should be purged. +All this can go, it's redundant ``` # Plone developer culture diff --git a/coredev/documentation.md b/coredev/documentation.md index a09ec6bf8..bbaec73bc 100644 --- a/coredev/documentation.md +++ b/coredev/documentation.md @@ -6,6 +6,9 @@ myst: "property=og:title": "Writing documentation of Plone" "keywords": "documentation, Plone" --- +```{todo} +shorten & update +``` # Writing documentation @@ -13,14 +16,12 @@ For general guidance for contributing documentation, see {doc}`contributing/inde For documentation authors, see {doc}`contributing/authors`. - ## Documentation of Plone -The comprehensive resource for Plone documentation is https://6.docs.plone.org/. +The comprehensive resource for Plone documentation is . The documentation repository is on [GitHub](https://github.com/plone/documentation). Information for how to contribute to documentation can be found at {doc}`contributing/index`. - ## Documenting a package At the very least, your package should include the following forms of documentation. @@ -33,12 +34,11 @@ It should be formatted using [GitHub flavored Markdown](https://github.github.co `README.md` should include: -- A brief description of the package's purpose. -- Installation information (How do I get it working?) -- Compatibility information (what versions of Plone does it work with?) -- Links to other sources of documentation. -- Links to issue trackers, mailing lists, and other ways to get help. - +- A brief description of the package's purpose. +- Installation information (How do I get it working?) +- Compatibility information (what versions of Plone does it work with?) +- Links to other sources of documentation. +- Links to issue trackers, mailing lists, and other ways to get help. ### The manual (narrative documentation) @@ -46,27 +46,26 @@ The manual goes into further depth for people who want to know all about how to It includes topics like: -- What are its features -- How to use them (in English—not doctests!) -- Information about architecture -- Common gotchas +- What are its features +- How to use them (in English—not doctests!) +- Information about architecture +- Common gotchas The manual should consider various audiences who may need different types of information: -- End users who use Plone for content editing, but don't manage the site. -- Site administrators who install and configure the package. -- Integrators who need to extend the functionality of the package in code. -- System administrators who need to maintain the server running the software. +- End users who use Plone for content editing, but don't manage the site. +- Site administrators who install and configure the package. +- Integrators who need to extend the functionality of the package in code. +- System administrators who need to maintain the server running the software. Simple packages with limited functionality can get by with a single page of narrative documentation. In this case, it's simplest to include it in an extended `README.md`. -Some excellent examples of a single-page README are https://pypi.org/project/plone.outputfilters/ and https://github.com/plone/plone.app.caching. +Some excellent examples of a single-page README are and . If your project is moderately complex, you may want to set up your documentation with multiple pages. The preferred way to do this is to add Sphinx to your project, and host your docs on readthedocs.org, so that it rebuilds the documentation whenever you push to GitHub. If you do this, your `README.md` must link off site to the documentation. - ### Reference or API documentation An API reference provides information about the package's public API (that is, the code that the package exposes for use from external code). @@ -74,7 +73,6 @@ It is meant for random access to remind the reader of how a particular class or If the codebase is written with docstrings, API documentation can be automatically generated using Sphinx. - ### Changes or history ```{todo} @@ -102,7 +100,6 @@ See for a fu If a change was related to a bug in the issue tracker, the changelog entry should include a link to that issue. - ### Licenses Information about the open source license used for the package should be placed within the `docs` directory. diff --git a/coredev/getting-started-with-development.md b/coredev/getting-started-with-development.md index 5975adc21..109b4a594 100644 --- a/coredev/getting-started-with-development.md +++ b/coredev/getting-started-with-development.md @@ -7,27 +7,28 @@ myst: "keywords": "Plone, development" --- +```{todo} +Needs updating to Plone6, but contains useful info +``` + # Getting started with development This document assumes you want to run the current latest Plone source, fix a bug in Plone, or test an add-on in the context of the latest code, and will detail the full process. For how to write Plone Improvement Proposals (PLIPs), read {doc}`plips`. - ## Version support policy If you are triaging or fixing bugs, keep in mind that Plone has a [version support policy](https://plone.org/download/release-schedule#91815aec-0513-40e0-a804-55ea787a8c68). - ## Dependencies -- git. See [Set up Git](https://docs.github.com/en/get-started/quickstart/set-up-git). -- [Python](https://python.org/). See the [current supported versions of Python](https://plone.org/download/release-schedule). -- If you are on macOS, you will need to install [XCode](https://developer.apple.com/xcode/). +- git. See [Set up Git](https://docs.github.com/en/get-started/quickstart/set-up-git). +- [Python](https://python.org/). See the [current supported versions of Python](https://plone.org/download/release-schedule). +- If you are on macOS, you will need to install [XCode](https://developer.apple.com/xcode/). You can do this through the App Store or registering through the Apple Developer Program. -- [Pillow](https://pypi.org/project/Pillow/). -- [GCC](https://gcc.gnu.org/) in order to compile ZODB, Zope and lxml. -- [libxml2 and libxslt](https://gitlab.gnome.org/GNOME/libxslt/-/releases), including development headers. - +- [Pillow](https://pypi.org/project/Pillow/). +- [GCC](https://gcc.gnu.org/) in order to compile ZODB, Zope and lxml. +- [libxml2 and libxslt](https://gitlab.gnome.org/GNOME/libxslt/-/releases), including development headers. (setup-development-environment)= @@ -66,9 +67,8 @@ or as a WSGI service with: To login, the defaults are: -- username: admin -- password: admin - +- username: admin +- password: admin ## Switching branches @@ -98,7 +98,6 @@ The line with a `*` by it will indicate the branch on which you are currently wo Make sure to rerun buildout if you were in a different branch earlier to get the correct versions of packages, otherwise you will get some weird behavior. ``` - ## Jenkins and mr.roboto Plone has a continuous integration (CI) setup and follows CI rules. @@ -113,33 +112,32 @@ Build breakages are a normal and expected part of the development process. Our aim is to find errors and eliminate them as quickly as possible, without expecting perfection and zero errors. Though, there are some essential practices that need to be followed in order to achieve a stable build: -1. Don't check in on a broken build. Check Jenkins first. -2. Always run all commit tests locally before committing. -3. Wait for commit tests to pass before moving on. -4. Never go home on a broken build. -5. Always be prepared to revert to the previous revision. -6. Time-box fixing before reverting. -7. Don't comment out failing tests. -8. Take responsibility for all breakages that result from your changes. +1. Don't check in on a broken build. Check Jenkins first. +2. Always run all commit tests locally before committing. +3. Wait for commit tests to pass before moving on. +4. Never go home on a broken build. +5. Always be prepared to revert to the previous revision. +6. Time-box fixing before reverting. +7. Don't comment out failing tests. +8. Take responsibility for all breakages that result from your changes. See {doc}`continous-integration` for more information. Since it can be burdensome to check this manually, install the tools locally to always see the current state of the Plone CI Server: -- For Linux and X11 environments, there is [BuildNotify](https://pypi.org/project/BuildNotify/). -- For macOS there is [CCMenu](http://ccmenu.org/). -- For windows there is [CCTray](https://cruisecontrolnet.org/cctray_download_plugin-2/). -- For Firefox there is [CruiseControl Monitor](https://addons.thunderbird.net/EN-US/firefox/addon/cruisecontrol-monitor/?src=cb-dl-name) (no longer supported), and many other [Jenkins plugins](https://addons.mozilla.org/en-US/firefox/search/?q=jenkins). +- For Linux and X11 environments, there is [BuildNotify](https://pypi.org/project/BuildNotify/). +- For macOS there is [CCMenu](http://ccmenu.org/). +- For windows there is [CCTray](https://cruisecontrolnet.org/cctray_download_plugin-2/). +- For Firefox there is [CruiseControl Monitor](https://addons.thunderbird.net/EN-US/firefox/addon/cruisecontrol-monitor/?src=cb-dl-name) (no longer supported), and many other [Jenkins plugins](https://addons.mozilla.org/en-US/firefox/search/?q=jenkins). These tools were built to parse a specific file that CruiseControl, another CI tool, generated. Jenkins generates this file too. You can configure your notifier of choice with this url: `https://jenkins.plone.org/cc.xml` [which is a 404, LOL!] - ## Check out packages to fix Most packages are not in {file}`src/` by default, so you can use `mr.developer` to get the latest and make sure you are always up to date. -It can be a little daunting at first to find out which packages cause the bug in question, but just ask in https://community.plone.org/ if you need some help. +It can be a little daunting at first to find out which packages cause the bug in question, but just ask in if you need some help. Once you know which packages you want, pull their source. You can get the source of the package with `mr.developer` and the checkout command, or you can go directly to editing {file}`checkouts.cfg`. @@ -177,7 +175,6 @@ In both methods, `mr.developer` will download the source from GitHub (or otherwi You can repeat this process with as many or as few packages as you need. For some more tips on working with `mr.developer`, please read {doc}`mrdeveloper`. - ## Testing Locally To run a test for the specific module you modify: @@ -203,7 +200,6 @@ you may just let jenkins do this part for you. More on that below. ``` - ## Updating `CHANGES.rst` and `checkouts.cfg` Once all the tests are running locally on your machine, you are **ALMOST** ready to commit the changes. @@ -228,32 +224,30 @@ Not that you would ever skip running all tests. If your bug is in more than one release, for example 5.2 and 6.0, please checkout both branches, and add it to the file {file}`checkouts.cfg`. - ## Commits and pull requests Review the following checklist: -- Did you fix the original bug? -- Is your code consistent with our [Style Guides](https://5.docs.plone.org/develop/styleguide/index.html)? -- Did you remove any extra code and lingering pdbs? -- Did you write a test case for that bug? -- DO all test cases for the modules and Plone pass? -- Did you update {file}`CHANGES.rst` in each packages you touched? -- Did you add your changed packages to {file}`checkouts.cfg`? +- Did you fix the original bug? +- Is your code consistent with our [Style Guides](https://5.docs.plone.org/develop/styleguide/index.html)? +- Did you remove any extra code and lingering pdbs? +- Did you write a test case for that bug? +- DO all test cases for the modules and Plone pass? +- Did you update {file}`CHANGES.rst` in each packages you touched? +- Did you add your changed packages to {file}`checkouts.cfg`? If you answered *YES* to all of these questions, then you are ready to push your changes! A couple quick reminders: -- Only commit directly to the development branch if you're confident that your code won't break anything badly and the changes are small and fairly trivial. +- Only commit directly to the development branch if you're confident that your code won't break anything badly and the changes are small and fairly trivial. Otherwise, please create a `pull request` (more on that below). -- Please try to make one change per commit. +- Please try to make one change per commit. If you are fixing three bugs, make three commits. That way, it is easier to see what was done when, and easier to roll back any changes if necessary. If you want to make large changes cleaning up whitespace or renaming variables, it is especially important to do so in a separate commit for this reason. -- We have a few angels that follow the changes and each commit to see what happens to their favourite CMS! +- We have a few angels that follow the changes and each commit to see what happens to their favourite CMS! If you commit something REALLY sketchy, they will politely contact you, most likely after immediately reverting changes. - There are no official people assigned to this so if you are especially nervous, ask in https://community.plone.org/. - + There are no official people assigned to this so if you are especially nervous, ask in . ## Commit to `Products.CMFPlone` @@ -315,7 +309,7 @@ git checkout 4.2 git merge my-awesome-feature-4.2 ``` -### Branches and forks and direct commits - oh my! +### Branches and forks and direct commits - oh my ```{note} This section needs a rewrite. @@ -330,10 +324,10 @@ For Plone, this would be the version branch, whereas for most other packages thi HOWEVER, there are a few situations where a branch is appropriate. If you: -- are just getting started -- are not sure about your changes -- want feedback or code review -- are implementing a non-trivial change +- are just getting started +- are not sure about your changes +- want feedback or code review +- are implementing a non-trivial change then you should create a branch of whatever packages you are using, and then use the [pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) feature of GitHub to get review. Everything about this process would be the same except you need to work on a branch. @@ -365,13 +359,12 @@ This will turn your request into a pull request on the main branch. There are people who look once a week or more for pending pull requests and will confirm whether or not it's a good fix, and give you feedback where necessary. The reviewers are informal and very nice, so don't worry. They are there to help! -If you want immediate feedback, visit https://community.plone.org/ with the pull request link and ask for a review. +If you want immediate feedback, visit with the pull request link and ask for a review. ```{note} You still need to update the file {file}`checkouts.cfg` in the correct branches of `buildout.coredev`! ``` - ## Finalize issues If you are working from an issue, please don't forget to go back to the issue, and add a link to the change set. @@ -379,7 +372,6 @@ We don't have integration with GitHub yet so it's a nice way to track changes. It also lets the reporter know that you care. If the bug is really bad, consider pinging the release manager and asking them to make a release. - ## FAQ How do I know when my package got made? diff --git a/coredev/git.md b/coredev/git.md index 9c9034f75..992de6aa6 100644 --- a/coredev/git.md +++ b/coredev/git.md @@ -8,9 +8,7 @@ myst: --- ```{todo} -I seriously question the value of this entire guide. -I think it should be purged. -Plone should not be in the business of teaching how to use git or GitHub. +All this can go, it's redundant ``` # Working with Git and GitHub @@ -19,19 +17,17 @@ Plone should not be in the business of teaching how to use git or GitHub. Our repository on GitHub has the following layout: -- **feature branches**: +- **feature branches**: All development for new features must be done in dedicated branches, normally one branch per feature. -- **main** or **master** **branch**: +- **main** or **master** **branch**: when features get completed they are merged into the master branch; bugfixes are commited directly on the master branch, -- **tags**: +- **tags**: whenever we create a new release, we tag the repository so we can later retrace our steps, or rerelease versions. - ## Git basics Some introductory definitions and concepts, if you are already familiar enough with Git, head to next section: {ref}`general-guidelines-label`. - ### Mental working model With Git (as well as all modern [DVCS](http://en.wikipedia.org/wiki/Distributed_revision_control)), distributing changes to others is a two steps process (contrary to traditional VCS like `svn`). @@ -48,7 +44,6 @@ You can freely fix/change/remove/rework/update/... your commits afterwards. Push your changes whenever you are sure they are what you, and others, expect them to be. - ### Concepts In Git there are: diff --git a/coredev/guidelines.md b/coredev/guidelines.md index 6c9ea0236..a931c3eb1 100644 --- a/coredev/guidelines.md +++ b/coredev/guidelines.md @@ -7,9 +7,9 @@ myst: "keywords": "" --- -```todo -This should probably be purged. -It is redundant to the default [CONTRUBITING.md](https://github.com/plone/.github/blob/main/CONTRIBUTING.md) and other files. +```{todo} +All this can go, it's redundant. +IMPORTANT: it does need a rewrite on 6.docs.plone.org as there are many packages in the wild that link to it. ``` % Note: this page is linked to from CONTRIBUTING.rst in all packages. Keep it short! @@ -23,35 +23,34 @@ Let's bring you up to speed with the minimum you need to know to start contribut ## Create an issue -- If you know the issue is for a specific package, you can add an issue there. +- If you know the issue is for a specific package, you can add an issue there. When in doubt, create one in the [CMFPlone issue tracker](https://github.com/plone/Products.CMFPlone/issues). -- Please specify a few things: +- Please specify a few things: - - What steps reproduce the problem? - - What do you expect when you do that? - - What happens instead? - - Which Plone version are you using? + - What steps reproduce the problem? + - What do you expect when you do that? + - What happens instead? + - Which Plone version are you using? -- If it is a visual issue, can you add a screen shot? +- If it is a visual issue, can you add a screen shot? -- If there is an error in the Site Setup error log, please include it. +- If there is an error in the Site Setup error log, please include it. Especially a traceback is helpful. Click on the 'Display traceback as text' link if you see it in the error log. - ## Create a pull request -- Legally, you can NOT contribute code unless you have signed the {doc}`contributor agreement `. +- Legally, you can NOT contribute code unless you have signed the {doc}`contributor agreement `. This means that we can NOT accept pull requests from you unless this is done, so please don't put the code reviewers at risk and do it anyways. -- Add a changelog entry as file in the news directory. +- Add a changelog entry as file in the news directory. For helpful instructions, please see: -- For new features, an addition to README.rst is probably needed. +- For new features, an addition to README.rst is probably needed. A package may include other documentation that needs updating. -- All text that can be shown in a browser must be translatable. +- All text that can be shown in a browser must be translatable. Please mark all such strings as translatable. -- Be nice and use code quality checkers like flake8 and jshint. -- See if you can use git to squash multiple commits into one where this makes sense. +- Be nice and use code quality checkers like flake8 and jshint. +- See if you can use git to squash multiple commits into one where this makes sense. If you are not comfortable with git, never mind. -- If after reading this you become hesitant: don't worry. +- If after reading this you become hesitant: don't worry. You can always create a pull request, mark it as WIP (work in progress), and improve the above points later. diff --git a/coredev/index.md b/coredev/index.md index 80eb9b613..38bf4fc7b 100644 --- a/coredev/index.md +++ b/coredev/index.md @@ -7,12 +7,15 @@ myst: "keywords": "Developing, Plone, Contributing" --- +```{todo} +Most of this can go +``` + # Development in Plone This part describes the process of development in Plone. It is primarily a technical resource for setting up your development environment, fixing bugs, and writing Plone Improvement Proposals (PLIPs). - ## Plone Contributor Agreement You must sign the [Plone Contributor Agreement](https://plone.org/foundation/contributors-agreement). @@ -20,7 +23,6 @@ You must sign the [Plone Contributor Agreement](https://plone.org/foundation/con We can **NOT** accept pull requests from you until you have signed and returned the Contributor Agreement, and been approved. Please don't put the code reviewers at risk by ignoring this requirement. - ## Contents ```{toctree} @@ -38,7 +40,6 @@ git package-dependencies ``` - ## Additional material These are some documents used as reference for this documentation. @@ -60,4 +61,4 @@ The style guides are ancient and need to be overhauled. Documenation's style is guided by Vale and the Microsoft Style Guide. See [Contributing to Documentation](https://6.docs.plone.org/contributing/index.html). -Our coding style guides are located at the [Plone Style Guide](https://5.docs.plone.org/develop/styleguide/index.html section. +Our coding style guides are located at the [Plone Style Guide]( section. diff --git a/coredev/mrdeveloper.md b/coredev/mrdeveloper.md index 83d90a553..f1a280f21 100644 --- a/coredev/mrdeveloper.md +++ b/coredev/mrdeveloper.md @@ -7,10 +7,14 @@ myst: "keywords": "mr.developer" --- +```{todo} +Review, but keep +``` + # `mr.developer` This buildout uses `mr.developer` to manage package development. -See https://pypi.org/project/mr.developer/ for more information, or run `bin/develop help` for a list of available commands. +See for more information, or run `bin/develop help` for a list of available commands. The most common workflow to get all the latest updates is: diff --git a/coredev/packages-dependencies.md b/coredev/packages-dependencies.md index 5f673b7ce..2f8ba1145 100644 --- a/coredev/packages-dependencies.md +++ b/coredev/packages-dependencies.md @@ -7,26 +7,28 @@ myst: "keywords": "Architecture, packages, dependecies, Plone" --- +```{todo} +Needs grammar/style check, and re-do the ASCII art as Mermaid diagram for added clarity and visuals +``` + # Architecture: packages and dependecies This chapter describes the architecture of Plone's packages and dependencies. - ## Motivation In the past, lots of indirections were introduced in Plone's packages and dependecies. Our goal in the long run is to untangle them and get a direct dependency graph. This document shows the current state as an orientation. - ## Overview There are multiple level of dependencies: -- package level (`setup.py`/`setup.cfg`/`pyproject.toml`) -- Python level (imports) -- ZCML level (includes) -- testing (need for layers, such as functional testing) +- package level (`setup.py`/`setup.cfg`/`pyproject.toml`) +- Python level (imports) +- ZCML level (includes) +- testing (need for layers, such as functional testing) We do not have any circular dependencies at the package level anymore. This was solved already. @@ -34,7 +36,6 @@ This was solved already. Nevertheless we have indirection on all other levels. Since Plone consists of a lot of packages, it is complex to untangle those. - ## Mental model A base mental model for how Plone is organized in Plone 6 since alpha 4 is shown in the following diagram: @@ -96,9 +97,8 @@ A base mental model for how Plone is organized in Plone 6 since alpha 4 is shown As a rough model we have two packages as dividing lines: -1. `Products.CMFPlone` -2. `plone.base` - +1. `Products.CMFPlone` +2. `plone.base` ## Packages in detail @@ -106,263 +106,256 @@ If we look deeper into those, we have more sub-dividers, but first group all int Then, based on the 6.0.0.a4 release, these are the packages: - ### Above `Products.CMFPlone` -- Plone -- plone.api -- plone.app.iterate -- plone.app.upgrade -- plone.restapi -- plone.volto -- Products.CMFPlacefulWorkflow - +- Plone +- plone.api +- plone.app.iterate +- plone.app.upgrade +- plone.restapi +- plone.volto +- Products.CMFPlacefulWorkflow ### Between `Products.CMFPlone` and `plone.base` -- collective.monkeypatcher -- plone.app.caching -- plone.app.content -- plone.app.contentlisting -- plone.app.contentmenu -- plone.app.contentrules -- plone.app.contenttypes -- plone.app.customerize -- plone.app.dexterity -- plone.app.discussion -- plone.app.event -- plone.app.i18n -- plone.app.intid -- plone.app.layout -- plone.app.linkintegrity -- plone.app.locales -- plone.app.lockingbehavior -- plone.app.multilingual -- plone.app.portlets -- plone.app.querystring -- plone.app.redirector -- plone.app.registry -- plone.app.relationfield -- plone.app.textfield -- plone.app.theming -- plone.app.users -- plone.app.uuid -- plone.app.versioningbehavior -- plone.app.viewletmanager -- plone.app.vocabularies -- plone.app.widgets -- plone.app.workflow -- plone.app.z3cform -- plone.browserlayer -- plone.cachepurging -- plone.contentrules -- plone.formwidget.namedfile -- plone.formwidget.recurrence -- plone.i18n -- plone.namedfile -- plone.outputfilters -- plone.portlet.collection -- plone.portlet.static -- plone.portlets -- plone.protect -- plone.resourceeditor -- plone.rfc822 -- plone.schemaeditor -- plone.session -- plone.staticresources -- plone.stringinterp -- plone.theme -- plonetheme.barceloneta -- Products.isurlinportal - +- collective.monkeypatcher +- plone.app.caching +- plone.app.content +- plone.app.contentlisting +- plone.app.contentmenu +- plone.app.contentrules +- plone.app.contenttypes +- plone.app.customerize +- plone.app.dexterity +- plone.app.discussion +- plone.app.event +- plone.app.i18n +- plone.app.intid +- plone.app.layout +- plone.app.linkintegrity +- plone.app.locales +- plone.app.lockingbehavior +- plone.app.multilingual +- plone.app.portlets +- plone.app.querystring +- plone.app.redirector +- plone.app.registry +- plone.app.relationfield +- plone.app.textfield +- plone.app.theming +- plone.app.users +- plone.app.uuid +- plone.app.versioningbehavior +- plone.app.viewletmanager +- plone.app.vocabularies +- plone.app.widgets +- plone.app.workflow +- plone.app.z3cform +- plone.browserlayer +- plone.cachepurging +- plone.contentrules +- plone.formwidget.namedfile +- plone.formwidget.recurrence +- plone.i18n +- plone.namedfile +- plone.outputfilters +- plone.portlet.collection +- plone.portlet.static +- plone.portlets +- plone.protect +- plone.resourceeditor +- plone.rfc822 +- plone.schemaeditor +- plone.session +- plone.staticresources +- plone.stringinterp +- plone.theme +- plonetheme.barceloneta +- Products.isurlinportal ### The foundation below `plone.base` - #### Plone world -- borg.localrole -- plone.alterego -- plone.autoform -- plone.autoinclude -- plone.batching -- plone.behavior -- plone.caching -- plone.dexterity -- plone.event -- plone.folder -- plone.indexer -- plone.intelligenttext -- plone.keyring -- plone.locking -- plone.memoize -- plone.registry -- plone.resource -- plone.rest -- plone.scale -- plone.schema -- plone.subrequest -- plone.supermodel -- plone.transformchain -- plone.uuid -- plone.z3cform -- Products.DateRecurringIndex -- Products.ExtendedPathIndex -- Products.MimetypesRegistry -- Products.PlonePAS -- Products.PortalTransforms -- Products.statusmessages - +- borg.localrole +- plone.alterego +- plone.autoform +- plone.autoinclude +- plone.batching +- plone.behavior +- plone.caching +- plone.dexterity +- plone.event +- plone.folder +- plone.indexer +- plone.intelligenttext +- plone.keyring +- plone.locking +- plone.memoize +- plone.registry +- plone.resource +- plone.rest +- plone.scale +- plone.schema +- plone.subrequest +- plone.supermodel +- plone.transformchain +- plone.uuid +- plone.z3cform +- Products.DateRecurringIndex +- Products.ExtendedPathIndex +- Products.MimetypesRegistry +- Products.PlonePAS +- Products.PortalTransforms +- Products.statusmessages #### Zope ecosystem -- Chameleon -- diazo -- five.customerize -- five.intid -- five.localsitemanager -- icalendar -- Products.CMFCore -- Products.CMFDiffTool -- Products.CMFDynamicViewFTI -- Products.CMFEditions -- Products.CMFUid -- Products.DCWorkflow -- Products.ExternalMethod -- Products.GenericSetup -- Products.MailHost -- Products.PluggableAuthService -- Products.PluginRegistry -- Products.PythonScripts -- Products.Sessions -- Products.SiteErrorLog -- Products.StandardCacheManagers -- Products.ZopeVersionControl -- repoze.xmliter -- webresource -- z3c.caching -- z3c.form -- z3c.formwidget.query -- z3c.objpath -- z3c.pt -- z3c.relationfield -- z3c.zcmlhook -- zc.recipe.egg -- zc.relation -- zodbverify -- zope.copy -- zope.intid -- zope.keyreference - +- Chameleon +- diazo +- five.customerize +- five.intid +- five.localsitemanager +- icalendar +- Products.CMFCore +- Products.CMFDiffTool +- Products.CMFDynamicViewFTI +- Products.CMFEditions +- Products.CMFUid +- Products.DCWorkflow +- Products.ExternalMethod +- Products.GenericSetup +- Products.MailHost +- Products.PluggableAuthService +- Products.PluginRegistry +- Products.PythonScripts +- Products.Sessions +- Products.SiteErrorLog +- Products.StandardCacheManagers +- Products.ZopeVersionControl +- repoze.xmliter +- webresource +- z3c.caching +- z3c.form +- z3c.formwidget.query +- z3c.objpath +- z3c.pt +- z3c.relationfield +- z3c.zcmlhook +- zc.recipe.egg +- zc.relation +- zodbverify +- zope.copy +- zope.intid +- zope.keyreference #### Zope core -- AccessControl -- Acquisition -- AuthEncoding -- beautifulsoup4 -- BTrees -- DateTime -- DocumentTemplate -- ExtensionClass -- Missing -- MultiMapping -- Persistence -- persistent -- Products.BTreeFolder2 -- Products.ZCatalog -- Record -- RestrictedPython -- transaction -- zc.lockfile -- ZConfig -- zdaemon -- ZEO -- zExceptions -- ZODB -- ZODB3 -- zodbpickle -- Zope -- zope.annotation -- zope.app.locales -- zope.browser -- zope.browsermenu -- zope.browserpage -- zope.browserresource -- zope.cachedescriptors -- zope.component -- zope.componentvocabulary -- zope.configuration -- zope.container -- zope.contentprovider -- zope.contenttype -- zope.datetime -- zope.deferredimport -- zope.deprecation -- zope.dottedname -- zope.event -- zope.exceptions -- zope.filerepresentation -- zope.globalrequest -- zope.hookable -- zope.i18n -- zope.i18nmessageid -- zope.interface -- zope.lifecycleevent -- zope.location -- zope.pagetemplate -- zope.processlifetime -- zope.proxy -- zope.ptresource -- zope.publisher -- zope.ramcache -- zope.schema -- zope.security -- zope.sendmail -- zope.sequencesort -- zope.site -- zope.size -- zope.structuredtext -- zope.tal -- zope.tales -- zope.testbrowser -- zope.testing -- zope.traversing -- zope.viewlet -- Zope2 - +- AccessControl +- Acquisition +- AuthEncoding +- beautifulsoup4 +- BTrees +- DateTime +- DocumentTemplate +- ExtensionClass +- Missing +- MultiMapping +- Persistence +- persistent +- Products.BTreeFolder2 +- Products.ZCatalog +- Record +- RestrictedPython +- transaction +- zc.lockfile +- ZConfig +- zdaemon +- ZEO +- zExceptions +- ZODB +- ZODB3 +- zodbpickle +- Zope +- zope.annotation +- zope.app.locales +- zope.browser +- zope.browsermenu +- zope.browserpage +- zope.browserresource +- zope.cachedescriptors +- zope.component +- zope.componentvocabulary +- zope.configuration +- zope.container +- zope.contentprovider +- zope.contenttype +- zope.datetime +- zope.deferredimport +- zope.deprecation +- zope.dottedname +- zope.event +- zope.exceptions +- zope.filerepresentation +- zope.globalrequest +- zope.hookable +- zope.i18n +- zope.i18nmessageid +- zope.interface +- zope.lifecycleevent +- zope.location +- zope.pagetemplate +- zope.processlifetime +- zope.proxy +- zope.ptresource +- zope.publisher +- zope.ramcache +- zope.schema +- zope.security +- zope.sendmail +- zope.sequencesort +- zope.site +- zope.size +- zope.structuredtext +- zope.tal +- zope.tales +- zope.testbrowser +- zope.testing +- zope.traversing +- zope.viewlet +- Zope2 #### Libraries -- attrs -- cffi -- cssselect -- decorator -- docutils -- feedparser -- future -- importlib_metadata -- jsonschema -- Markdown -- multipart -- Paste -- PasteDeploy -- piexif -- Pillow -- pycparser -- PyJWT -- pyrsistent -- python_dotenv -- python_gettext -- requests -- roman -- sgmllib3k -- simplejson -- soupsieve -- Unidecode -- urllib3 -- waitress -- WebOb -- WebTest -- WSGIProxy2 -- zipp +- attrs +- cffi +- cssselect +- decorator +- docutils +- feedparser +- future +- importlib_metadata +- jsonschema +- Markdown +- multipart +- Paste +- PasteDeploy +- piexif +- Pillow +- pycparser +- PyJWT +- pyrsistent +- python_dotenv +- python_gettext +- requests +- roman +- sgmllib3k +- simplejson +- soupsieve +- Unidecode +- urllib3 +- waitress +- WebOb +- WebTest +- WSGIProxy2 +- zipp diff --git a/coredev/plip-review.md b/coredev/plip-review.md index 78aed655a..074a182fa 100644 --- a/coredev/plip-review.md +++ b/coredev/plip-review.md @@ -7,11 +7,14 @@ myst: "keywords": "PLIP, review, Plone Improvement Proposal, Plone" --- +```{todo} +Combine with PLIP page, remove obsolete technologies, go over language +``` + # PLIP review A Plone Improvement Proposal (PLIP) is a formal process to propose a change to improve Plone. - ## Expectations A good PLIP review takes about four hours. @@ -19,7 +22,6 @@ Please plan accordingly. When you are done, if you have access to core, commit the review to the `plips` folder, and reference the PLIP in your commit message. If you do not have access, attach your review to the PLIP ticket itself. - ## Setting up the environment Follow the instructions in {doc}`getting-started-with-development`. @@ -30,48 +32,43 @@ Instead of running the buildout with the default buildout file, you will run the ./bin/buildout -c plips/plipXXXX.cfg ``` - ## Functionality review This section describes the topics that may be addressed in a PLIP review, depending on the nature of the PLIP itself. - ### General -- Does the PLIP actually do what the implementers proposed? +- Does the PLIP actually do what the implementers proposed? Are there incomplete variations? -- Were there any errors running buildout? +- Were there any errors running buildout? Did the migration(s) work? -- Do error and status messages make sense? +- Do error and status messages make sense? Are they properly internationalized? -- Are there any performance considerations? +- Are there any performance considerations? Has the implementer addressed them, if so? - ### Bugs -- Are there any bugs? +- Are there any bugs? Nothing is too big nor small. -- Do fields handle wacky data? +- Do fields handle wacky data? How about strings in date fields, or nulls in required? -- Is validation up to snuff and sensical? +- Is validation up to snuff and sensical? Is it too restrictive or not restrictive enough? - ### Usability Issues -- Is the implementation usable? -- How will novice end users respond to the change? -- Does this PLIP need a usability review? +- Is the implementation usable? +- How will novice end users respond to the change? +- Does this PLIP need a usability review? If you think this PLIP needs a usability review, change the state to "please review" and add a note in the comments. -- Is the PLIP consistent with the rest of Plone? +- Is the PLIP consistent with the rest of Plone? For example, if there is control panel configuration, does the new form fit in with the rest of the panels? -- Does everything flow nicely for novice and advanced users? +- Does everything flow nicely for novice and advanced users? Is there any workflow that feels odd? -- Are there any new permissions and do they work properly? +- Are there any new permissions and do they work properly? Does their role assignment make sense? - ### Documentation Issues - Is the corresponding documentation for the end user, be it developer or Plone user, sufficient? @@ -83,23 +80,20 @@ This way the implementer can find help if they need it. Also set a priority for the ticket. The PLIP will not be merged until all blockers and critical bugs are fixed. - ### Code Review - #### Python -- Is this code maintainable? -- Is the code properly documented? -- Does the code adhere to PEP8 standards (more or less)? -- Are they importing deprecated modules? - +- Is this code maintainable? +- Is the code properly documented? +- Does the code adhere to PEP8 standards (more or less)? +- Are they importing deprecated modules? #### JavaScript -- Does the JavaScript meet our set of JavaScript standards? +- Does the JavaScript meet our set of JavaScript standards? See our section about [JavaScript](https://5.docs.plone.org/develop/addons/javascript/index.html) and the [JavaScript Style Guide](https://5.docs.plone.org/develop/styleguide/javascript.html). -- Does the JavaScript work in all currently supported browsers? +- Does the JavaScript work in all currently supported browsers? Is it performant? ```{todo} @@ -109,7 +103,7 @@ See https://github.com/plone/documentation/issues/1330 #### ME/TAL -- Does the PLIP use views appropriately, avoiding too much logic? -- Is there any code in a loop that could potentially be a performance issue? -- Are there any deprecated or old style ME/TAL lines of code, such as using `DateTime`? -- Is the rendered HTML compliant with standards? Are IDs and classes used appropriately? +- Does the PLIP use views appropriately, avoiding too much logic? +- Is there any code in a loop that could potentially be a performance issue? +- Are there any deprecated or old style ME/TAL lines of code, such as using `DateTime`? +- Is the rendered HTML compliant with standards? Are IDs and classes used appropriately? diff --git a/coredev/plips.md b/coredev/plips.md index 408793d47..5de254d16 100644 --- a/coredev/plips.md +++ b/coredev/plips.md @@ -7,6 +7,10 @@ myst: "keywords": "Plone Improvement Proposal, PLIP)" --- +```{todo} +Needs language review +``` + # Plone Improvement Proposals (PLIPs) A PLIP is a Plone Improvement Proposal. @@ -14,12 +18,10 @@ It is a change to a Plone package that would affect everyone. PLIPs go through a different process than bug fixes because of their broad reaching effect. The Plone Framework Team reviews all PLIPs to be sure that it's in the best interest of the broader community to be implemented and that it is of high quality. - ## Frequently asked questions about PLIPs This section provides detailed answers to common questions about PLIPs. - ### PLIP or bugfix? In general, anything that changes the API of Plone in the backend or the user interface (UI) on the front end should be filed as a PLIP. @@ -28,7 +30,6 @@ The Framework Team is eager to reduce its own workload and will reclassify it fo If the change you are proposing is not in the scope of a PLIP, a GitHub pull request or issue is the right format. The key point here is that each change must be documented, allowing it to be tracked and understood. - ### Who can submit PLIPs? Anyone who has signed a Plone Contributor Agreement can work on a PLIP. @@ -46,7 +47,6 @@ If you have ideas on new interactions or UI your ideas are more than welcome. We will help you pair up with implementers if needed. - ### What is a PLIP champion? When you submit your PLIP and it is approved, a Framework Team member who is especially excited about seeing the PLIP completed will be assigned to your PLIP as a champion. @@ -55,15 +55,14 @@ They are there to push you through completion, as well as answer any questions a A champion fulfill the following tasks. -- Answer any questions the PLIP implementor has, technical or otherwise. -- Encourage the PLIP author by constantly giving feedback and encouragement. -- Keep the implementer aware of timelines, and push to get things done on time. -- Assist with finding additional help when needed to complete the implementation in a timely matter. +- Answer any questions the PLIP implementor has, technical or otherwise. +- Encourage the PLIP author by constantly giving feedback and encouragement. +- Keep the implementer aware of timelines, and push to get things done on time. +- Assist with finding additional help when needed to complete the implementation in a timely matter. Keep in mind that champions are in passive mode by default. If you need help or guidance, please reach out to them as soon as possible to activate help mode. - ### Can I get involved in other ways? If you want to experience the process and how it works, help us review PLIPs as the implementations finish up. @@ -77,7 +76,6 @@ Then, follow the instructions for {doc}`reviewing a PLIP `. Thank you in advance! - ### When can I submit a PLIP? Today, tomorrow, any time! @@ -86,7 +84,6 @@ After the PLIP is accepted, the Framework Team will try to judge complexity and You can begin work immediately, and we encourage submitting fast and furious. - ### When is the PLIP due? **Summary: As soon as you get it done.** @@ -98,30 +95,27 @@ In general, we don't want to track a PLIP for more than a year. If your PLIP is accepted and we haven't seen activity in over a year, we will probably ask you to restart the whole process. - ### What happens if your PLIP is not accepted? If a PLIP isn't accepted in core, it doesn't mean it's a bad idea. It is often the case that there are competing implementations, and we want to see it vetted as an add-on before "blessing" a preferred implementation. - ## Process Overview -1. Submit a PLIP at any time. -2. PLIP is approved for inclusion into core for a given release. -3. Developer implements PLIP (code, tests, documentation). -4. PLIP is submitted for review by developer. -5. Framework Team reviews the PLIP and gives feedback. -6. Developer addresses concerns in feedback and re-submits the PLIP, if necessary. -7. This may go back and forth a few times, until both the Framework Team and developer are happy with the result. -8. PLIP is approved for merge. +1. Submit a PLIP at any time. +2. PLIP is approved for inclusion into core for a given release. +3. Developer implements PLIP (code, tests, documentation). +4. PLIP is submitted for review by developer. +5. Framework Team reviews the PLIP and gives feedback. +6. Developer addresses concerns in feedback and re-submits the PLIP, if necessary. +7. This may go back and forth a few times, until both the Framework Team and developer are happy with the result. +8. PLIP is approved for merge. In rare circumstances, a PLIP will be rejected. This is usually the result of the developer not responding to feedback or dropping out of the process. Hang in there! -9. After all other PLIPs are merged, a release is cut. +9. After all other PLIPs are merged, a release is cut. Standby for bugs! - (how-to-submit-a-plip)= ## How to submit a PLIP @@ -151,16 +145,15 @@ Others may be able to point out risks or even offer up better or existing soluti Please note a few things: -- It is very rare that the "Risks" section will be empty or none. -- If you find this is the case, and your PLIP is anything more than trivial, maybe some more vetting should be done. -- The seconder field is REQUIRED. +- It is very rare that the "Risks" section will be empty or none. +- If you find this is the case, and your PLIP is anything more than trivial, maybe some more vetting should be done. +- The seconder field is REQUIRED. We will send the PLIP back to you if it is not filled in. Currently, this is just someone else who thinks your PLIP is a good idea, a +1. In the near future, we will start asking that the seconder is either a coding partner, or someone who is willing and able to finish the PLIP should something happen to the implementer. - ### Evaluating PLIPs After you submit your PLIP, the Framework Team will meet within a couple weeks, and let you know if the PLIP is accepted. @@ -173,41 +166,38 @@ Please keep your eyes and inbox open for changes. These are the criteria by which the framework team will review your work: -- What is size and status of the work needed to be done? -- Is it already an add-on and well established? -- Is this idea well baked and expressed clearly? -- Does the work proposed belong in Plone now, or in the future? -- Is this PLIP more appropriate as a qualified add-on? -- Is this PLIP too risky? +- What is size and status of the work needed to be done? +- Is it already an add-on and well established? +- Is this idea well baked and expressed clearly? +- Does the work proposed belong in Plone now, or in the future? +- Is this PLIP more appropriate as a qualified add-on? +- Is this PLIP too risky? See the {doc}`plip-review` page for more information. - ## Implementing your PLIP You can start the development at any time, but if you are going to modify Plone itself, it is a good idea to wait to see if your idea is approved. - ### General Rules -- Any new packages must be in a branch in the `plone` namespace in GitHub. +- Any new packages must be in a branch in the `plone` namespace in GitHub. You don't have to develop there, but it must be there when submitted. We recommend using branches off of the repositories under the Plone GitHub organization, and will detail that below. -- Most importantly, the PLIP reviewers must be able run buildout and everything should "just work"™. -- Any new code must: +- Most importantly, the PLIP reviewers must be able run buildout and everything should "just work"™. +- Any new code must: - - Be {doc}`properly documented `. - - Have clear code. - - [Follow our style guides](https://5.docs.plone.org/develop/styleguide/index.html). + - Be {doc}`properly documented `. + - Have clear code. + - [Follow our style guides](https://5.docs.plone.org/develop/styleguide/index.html). For convenience and better code quality use Python, JavaScript, and other code linting plugins in your editor. - - [Be tested](https://5.docs.plone.org/develop/testing/index.html). + - [Be tested](https://5.docs.plone.org/develop/testing/index.html). ```{todo} Update links from Plone 5 to Plone 6 Documentation, once content is migrated. See https://github.com/plone/documentation/issues/1330 and other issues. ``` - ### Creating a new PLIP branch Create a buildout configuration file for your PLIP in the `plips` folder. @@ -242,7 +232,6 @@ zcml += Use the same naming convention when you branch existing packages. You should always branch packages when working on PLIPs. - ### Working on a PLIP To work on a PLIP, you bootstrap buildout, and then invoke buildout with your PLIP configuration: @@ -269,16 +258,15 @@ installed = .installed.cfg var = ./var ``` - ### Finishing up Before marking your PLIP as ready for review, please add a file to give a set of instructions to the PLIP reviewer. This file should be called {file}`plip__notes.txt`. This should include, but is not limited to: -- URLs pointing to all documentation created and updated -- Any concerns and issues still remaining -- Any weird buildout things +- URLs pointing to all documentation created and updated +- Any concerns and issues still remaining +- Any weird buildout things Once you have finished, update your PLIP issue to indicate that it is ready for review. The Framework Team will assign 2-3 people to review your PLIP. diff --git a/coredev/release.md b/coredev/release.md index 0d6ad6c57..674bd5b2a 100644 --- a/coredev/release.md +++ b/coredev/release.md @@ -7,11 +7,14 @@ myst: "keywords": "Plone, release, process" --- +```{todo} +Can stay, as it needs a place to live. Check in with Release Managers to update content, if needed +``` + # Plone release process This chapter describes the process to release Plone and its packages. - ## Release process for Plone packages To keep the Plone software stack maintainable, the Python egg release process must be automated to a high degree. @@ -26,21 +29,20 @@ This command includes the following requirements. All files mentioned in this list may be written in Markdown or reStructuredText and have the appropriate file name suffix. ``` -- All releases must be hosted on PyPI. -- All versions must be tagged in version control. -- Each package must have a {file}`README` file with links to the version control repository and issue tracker. -- {file}`CHANGES` ({file}`docs/HISTORY`) must be always up-to-date and must contain list of functional changes which may affect package users. -- {file}`CHANGES` must contain release dates. -- {file}`README` and {file}`CHANGES` must be visible on PyPI. -- Released eggs must contain generated gettext `.mo` files, but these files must not be committed to the repository. +- All releases must be hosted on PyPI. +- All versions must be tagged in version control. +- Each package must have a {file}`README` file with links to the version control repository and issue tracker. +- {file}`CHANGES` ({file}`docs/HISTORY`) must be always up-to-date and must contain list of functional changes which may affect package users. +- {file}`CHANGES` must contain release dates. +- {file}`README` and {file}`CHANGES` must be visible on PyPI. +- Released eggs must contain generated gettext `.mo` files, but these files must not be committed to the repository. The `.mo` files can be created with the `zest.pocompile` add-on, which should be installed together with `zest.releaser`. -- `.gitignore` and `MANIFEST.in` must reflect the files going in to the egg (must include page template, po files). +- `.gitignore` and `MANIFEST.in` must reflect the files going in to the egg (must include page template, po files). ```{seealso} [High quality automated package releases for Python with `zest.releaser`](https://opensourcehacker.com/2012/08/14/high-quality-automated-package-releases-for-python-with-zest-releaser/). ``` - ## Special packages The Plone Release Team releases the core Plone packages. @@ -56,14 +58,13 @@ These are: `plone.app.locales` : Please leave this to the i18n team lead, Vincent Fretin. - ## Plone core release process checklist -1. Check Jenkins status. +1. Check Jenkins status. Check the latest Plone coredev job on [Jenkins](https://jenkins.plone.org/). It should be green, but if it is not, fix the problem first. -2. Check out `buildout.coredev`. +2. Check out `buildout.coredev`. ```shell git clone git@github.com:plone/buildout.coredev.git @@ -73,45 +74,45 @@ These are: bin/buildout -c buildout.cfg ``` -3. Check packages for updates. +3. Check packages for updates. Check all packages for updates, add to or remove from `checkouts.cfg` accordingly. This script may help: ```shell bin/manage report --interactive ``` - + This step should not be needed, because we do the check for every single commit, but people may still have forgotten to add a package to the `checkouts.cfg` file. -4. Check packages individually. +4. Check packages individually. Use the `bin/fullrelease` script from the core development buildout. This includes extra checks that we have added in `plone.releaser`. It guides you through all the next steps. - 1. Check changelog. + 1. Check changelog. Check if `CHANGES` is up-to-date. All changes since the last release should be included. A "Fixes" or "New" header should be included, with the relevant changes under it. Upgrade notes are best placed here as well. Compare `git log HEAD...` with `CHANGES`, or from `zest.releaser` use the command `lasttaglog `. - 2. Run [pyroma](https://pypi.org/project/pyroma/). - 3. Run [check-manifest](https://pypi.org/project/check-manifest/). - 4. Check package "best practices" (`README`, `CHANGES`, `src` directory). - 5. Check if the version in `setup.py` is correct and follows our versioning best practice. - 6. Make a release (zest.releaser: `bin/fullrelease`) - 7. Remove packages from auto-checkout section in `checkouts.cfg` and update `versions.cfg`. - -5. Make sure `plone.app.upgrade` contains an upgrade step for the future Plone release. -6. Update CMFPlone version in `profiles/default/metadata.xml`. -7. Create an issue in to ask the i18n team lead @vincentfretin to do a `plone.app.locales` release. -8. Create a pending release (directory) on [dist.plone.org](https://dist.plone.org/). - - 1. Copy all core packages there. - 2. Possibly make an alpha or beta release of CMFPlone. - 3. Copy the `versions.cfg` file from coredev to there. - -9. Write an email to the Plone developers list announcing a pending release. + 2. Run [pyroma](https://pypi.org/project/pyroma/). + 3. Run [check-manifest](https://pypi.org/project/check-manifest/). + 4. Check package "best practices" (`README`, `CHANGES`, `src` directory). + 5. Check if the version in `setup.py` is correct and follows our versioning best practice. + 6. Make a release (zest.releaser: `bin/fullrelease`) + 7. Remove packages from auto-checkout section in `checkouts.cfg` and update `versions.cfg`. + +5. Make sure `plone.app.upgrade` contains an upgrade step for the future Plone release. +6. Update CMFPlone version in `profiles/default/metadata.xml`. +7. Create an issue in to ask the i18n team lead @vincentfretin to do a `plone.app.locales` release. +8. Create a pending release (directory) on [dist.plone.org](https://dist.plone.org/). + + 1. Copy all core packages there. + 2. Possibly make an alpha or beta release of CMFPlone. + 3. Copy the `versions.cfg` file from coredev to there. + +9. Write an email to the Plone developers list announcing a pending release. 10. Update `plone.app.locales` version. 11. Create a unified changelog. @@ -123,7 +124,7 @@ These are: 13. Update the "-latest" link on [dist.plone.org](https://dist.plone.org/). 14. For Plone 5.x versions only, create the new release on [Launchpad](https://launchpad.net/plone/). 15. Create a release page on [plone.org](https://plone.org/download/releases) -16. Send links to the installers list at plone-installers@lists.sourceforge.net. +16. Send links to the installers list at . 17. Wait for installers to be uploaded to Launchpad, with a link to the plone.org release page. 18. Publish release page on plone.org. 19. Update plone.org homepage links to point to the new release. diff --git a/coredev/roboto.md b/coredev/roboto.md index 89d42038f..a195e0ade 100644 --- a/coredev/roboto.md +++ b/coredev/roboto.md @@ -7,6 +7,10 @@ myst: "keywords": "Mr. Roboto, mr.roboto, Plone" --- +```{todo} +Needs content review, it looks highly outdated with references to CVS, kgs and other obsolete tech +``` + # Mr. Roboto ```{todo} @@ -17,31 +21,30 @@ Add brief description of what is Mr. Roboto and what it does. When a push happens on GitHub, `mr.roboto` is triggered and it starts to analyze the push. -- If it's on `buildout-coredev`, it starts the job of the branch that has been pushed. +- If it's on `buildout-coredev`, it starts the job of the branch that has been pushed. In this case, we send to `plone-cvs` the commit to keep track of the commits on that list. -- If it's on a package that's on the {file}`sources.cfg` of a `buildout-coredev`, it starts the coredev jobs that are linked to that package and a kgs job with that package. +- If it's on a package that's on the {file}`sources.cfg` of a `buildout-coredev`, it starts the coredev jobs that are linked to that package and a kgs job with that package. This kgs job is a snapshot of the last working version of the `buildout.coredev` with the newest version of the package that is involved on the push. These jobs are really fast, as we only test the package applied to the kgs Plone and Python version `coredev` buildout. -- If it's on a PLIP specification, it runs the job that is configured Through The Web on the `mr.roboto` interface at http://jenkins.plone.org/roboto/plips. +- If it's on a PLIP specification, it runs the job that is configured Through The Web on the `mr.roboto` interface at . ```{todo} `http://jenkins.plone.org/roboto/plips` is obsolete, and returns a 404 not found. -``` - +``` ## Job finishes When Jenkins finishes a job, it makes a callback to `mr.roboto`, which in turn does the following: -- If it comes from a `coredev` job, when all the `coredev` jobs related to that push are finished, it writes a comment on the GitHub commit with all the information. +- If it comes from a `coredev` job, when all the `coredev` jobs related to that push are finished, it writes a comment on the GitHub commit with all the information. It does this one time only, with all the information, so no more empty mails from the GitHub notification system. -- If it comes from a kgs job and all the kgs jobs are finished, (that may take max 10 min) and some have failed, we send an email to the testbot mailing list saying that a commit failed on the kgs job. +- If it comes from a kgs job and all the kgs jobs are finished, (that may take max 10 min) and some have failed, we send an email to the testbot mailing list saying that a commit failed on the kgs job. We also send an email to [plone-cvs](https://sourceforge.net/projects/plone/lists/plone-cvs) with the information to keep track of all the commits. -- If it comes from a kgs job and all the kgs jobs are finished, and all are working, we send an email to [plone-cvs](https://sourceforge.net/projects/plone/lists/plone-cvs) with the information to keep track of all the commits. +- If it comes from a kgs job and all the kgs jobs are finished, and all are working, we send an email to [plone-cvs](https://sourceforge.net/projects/plone/lists/plone-cvs) with the information to keep track of all the commits. For all kgs jobs jenkins sends an email to the author with the results when is finished. -All the notifications have an URL similar to http://jenkins.plone.org/roboto/get_info?push=9a183de85b3f48abb363fa8286928a10. +All the notifications have an URL similar to . ```{todo} http://jenkins.plone.org/roboto/get_info?push=9a183de85b3f48abb363fa8286928a10 is obsolete, and returns a 404 not found. @@ -49,9 +52,9 @@ http://jenkins.plone.org/roboto/get_info?push=9a183de85b3f48abb363fa8286928a10 i On this URL, there is the commit hash, who committed it, the diff, the files, and the result for each Jenkins job. -- [plone-testbot](https://lists.plone.org/mailman/listinfo/plone-testbot) mailing list receives messages only when a test fails on the kgs environment, and may take up to ten minutes from the push. -- [plone-cvs](https://sourceforge.net/projects/plone/lists/plone-cvs) always has the commit, diff, and the information, and it may take ten minutes to get there after the push. -- The author receives the results of tests failing against kgs after ten minutes after the push. +- [plone-testbot](https://lists.plone.org/mailman/listinfo/plone-testbot) mailing list receives messages only when a test fails on the kgs environment, and may take up to ten minutes from the push. +- [plone-cvs](https://sourceforge.net/projects/plone/lists/plone-cvs) always has the commit, diff, and the information, and it may take ten minutes to get there after the push. +- The author receives the results of tests failing against kgs after ten minutes after the push. ```{note} In case of integration errors with other packages that may fail because of the push, kgs will not be aware of that. diff --git a/coredev/troubleshooting.md b/coredev/troubleshooting.md index db636fd80..7dcc0f98c 100644 --- a/coredev/troubleshooting.md +++ b/coredev/troubleshooting.md @@ -7,17 +7,19 @@ myst: "keywords": "Troubleshooting, development issues, Plone" --- +```{todo} +Needs review. In general, a 'troubleshooting' page is nice, but this looks outdated +``` + # Troubleshooting This chapter describes how to troubleshoot development issues in Plone. - ## Buildout issues Buildout can be frustrating for those unfamiliar with parsing through autistic robot language. These errors are almost always a quick fix, and a little bit of understanding goes a long way. - ### Errors running `bootstrap.py` You may not even get to running buildout, and then you will already have an error. @@ -60,7 +62,6 @@ You may get the same error above again, but now that you know how to fix it, you Hooray! - ### When `mr.developer` is unhappy `mr.developer` is never unhappy, except when it is. @@ -106,7 +107,6 @@ allow-hosts += sphinx.pocoo.org Again, this is only necessary if the package wasn't found in the end. - ### `mr.developer` path errors ```console @@ -121,21 +121,18 @@ To fix, do: ln -s plips/.mr.developer.cfg ``` - ## Other random issues ```{TODO} These need to be revalidated ``` - ### Dirty packages ```console ERROR: Can't update package 'Some package', because it's dirty. ``` - #### Fix `mr.developer` is complaining because a file has been changed or added, but not committed. @@ -143,7 +140,6 @@ ERROR: Can't update package 'Some package', because it's dirty. Use `bin/develop update --force`. Adding `*.pyc *~.nib *.egg-info .installed.cfg *.pt.py *.cpt.py *.zpt.py *.html.py *.egg` to your subversion configuration's `global-ignores` has been suggested as a more permanent solution. - ### No module named zope 2 ```console @@ -153,7 +149,6 @@ ImportError: No module named Zope2" when building using a PLIP cfg file. Appears to not actually be the case. Delete {file}`mkzopeinstance.py` from {file}`bin/`, and rerun buildout to correct this if you're finding it irksome. - ### Can't open file '/Startup/run.py' Two possible fixes. @@ -163,7 +158,6 @@ If you use Python 2.4 by mistake, use 2.6 instead. Or you may need to make sure you run `bin/buildout …` after `bin/develop …`. Try removing {file}`parts/*`, {file}`bin/*`, {file}`.installed.cfg`, then re-bootstrap and re-run buildout, develop, buildout. - ### Missing PIL {file}`pil.cfg` is included within this buildout to aid in PIL installation. @@ -171,7 +165,6 @@ Run {command}`bin/buildout -c pil.cfg` to install. This method does not work on Windows. We're unable to run it by default. - ### Modified egg issues {command}`bin/develop status` is showing that the `Products.CMFActionIcons` egg has been modified, but I haven't touched it. diff --git a/docs/conf.py b/docs/conf.py index 00877dcf4..a5a763de4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -59,6 +59,7 @@ "sphinx.ext.viewcode", # plone.api "sphinx.ext.autosummary", # plone.api "sphinx.ext.graphviz", + "sphinxcontrib.mermaid", "notfound.extension", ] @@ -99,6 +100,8 @@ r"https://stackoverflow.com", # volto and documentation # TODO retest with latest Sphinx. r"https://web.archive.org/", # volto r"https://www.youtube.com/playlist", # volto, TODO remove after installing sphinxcontrib.youtube + r"https://www.upc.edu/en", # TODO remove after their certificate is fixed + r"http://z3c.pt", # fluke where Sphinx interprets this as a URL ] linkcheck_anchors = True linkcheck_timeout = 5 @@ -179,6 +182,8 @@ "fawrench": '', } +mermaid_version = "10.9.1" + # -- Intersphinx configuration ---------------------------------- # This extension can generate automatic links to the documentation of objects @@ -329,6 +334,7 @@ "edit_page_url_template": "https://6.docs.plone.org/contributing/index.html?{{ file_name }}#making-contributions-on-github", } + # An extension that allows replacements for code blocks that # are not supported in `rst_epilog` or other substitutions. # https://stackoverflow.com/a/56328457/2214933 diff --git a/docs/contributing/core/continuous-integration.md b/docs/contributing/core/continuous-integration.md new file mode 100644 index 000000000..ed195183b --- /dev/null +++ b/docs/contributing/core/continuous-integration.md @@ -0,0 +1,98 @@ +--- +myst: + html_meta: + "description": "Essential continuous integration practices" + "property=og:description": "Essential continuous integration practices" + "property=og:title": "Essential continuous integration practices" + "keywords": "Plone, continuous integration, best practices" +--- + +# Essential continuous integration practices + +The {term}`CI` system at [jenkins.plone.org](https://jenkins.plone.org) is a shared resource for Plone core developers to notify them of regressions in Plone core code. + +Build breakages are a normal and expected part of the development process. +The aim is to find errors and remove them as quickly as possible, without expecting perfection and zero errors. +Though, there are some essential practices that you need follow to achieve a stable build: + +## 1) Don't check in on a broken build + +Do not make things more complicated for the developer who is responsible for breaking the build. + +If the build breaks, the developer has to identify the cause of the breakage as soon as possible and should fix it. +This strategy gives the developer the best option to find out what caused the breakage and fix it immediately. +Fixing the build is easier with a clear look at the problem. +Checking in further changes and triggering new builds will complicate matters and lead to more problems. + +If the build is broken over a longer period of time (more than a couple of hours) you should either: + +- notify the developer who is responsible for the breakage +- fix the problem yourself +- or revert the commit so you and others can continue to work. + +```{note} +There is one exception to this rule. +Sometimes there are changes or tests that depend on changes in other packages. +If this is the case, there is no way around breaking a single build for a certain period of time. +In this case run the all tests locally with all the changes and commit them within a time frame of ten minutes. +``` + +## 2) Always run all commit tests locally before committing + +Follow this practice so the build stays green, and other developers can continue to work without breaking the first rule. + +Remember that Plone development can happen all over the world, at all times. So other developers may have checked in changes since your last synchronization. These may interact with your work. + +Therefore it's essential that you check out ({command}`git pull`) and run the tests again before you push your changes to GitHub. + +A common source of errors on check-in is to forget to add some files to the repository. +Use {command}`git status` to check and correct for this. Also double-check to not check in files that should not be part of a package, such as editor configuration files. + +## 3) Wait for commit tests to pass before moving on + +Always monitor the build's progress, and fix the problem right away if it fails. +You have a far better chance of fixing the build, if you just introduced a regression than later. +Also another developer might have committed in the meantime (by breaking rule 1), making things more complicated for you. + +## 4) Never go home on a broken build + +Take into account the first rule of CI ("Don't check in on a broken build"): breaking the build essentially stops all other developers from working on it. +Therefore going home on a broken build (or even on a build that has not finished yet) is **not** acceptable. +It will prevent all other developers to stop working or they will need to fix the errors that you introduced. + +## 5) Always be prepared to revert to the previous revision + +In order for other developers to be able to work on the build, you should always be prepared to revert to the previous (passing) revision. + +## 6) Time-box fixing before reverting + +When the build breaks on check-in, try to fix it for ten minutes. +If, after ten minutes, you aren't finished with the solution, revert to the previous version from your version control system. +This way you will allow other developers to continue to work. + +## 7) Don't comment out failing tests + +Once you begin to enforce the previous rule, the result is often that developers start commenting out failing tests in order to get the build passing again as quick as possible. +While this impulse is understandable, it is **not acceptable**. + +The tests were passing for a while and then start to fail. +This means that you either caused a regression, made assumptions that are no longer valid, or the application has changed the functionality being tested for a valid reason. + +You should always either fix the code (if a regression has been found), modify the test (if one of the assumptions has changed), or delete it (if the functionality under test no longer exists). + +## 8) Take responsibility for all breakages that result from your changes + +If you commit a change and all the tests you wrote pass, but others break, the build is still broken. +This also applies to tests that fail in `buildout.coredev` and don't belong directly to the package you worked on. +This means that you have introduced a regression bug into the application. + +It is **your responsibility** to fix all tests that are not passing because of your changes. + +There are some tests in Plone that fail randomly, the community is always working on fixing those. +If you think you hit such a test, try to fix it (better) or re-run the Jenkins job to see if it passes again. + +In any case the developer who made the commit is responsible to make it pass. + +## Further reading + +These rules were taken from the excellent book "Continuous Delivery" by Jez Humble and David Farley (Addison Wesley), and have been adopted and rewritten for the Plone community. diff --git a/docs/contributing/core/documentation.md b/docs/contributing/core/documentation.md new file mode 100644 index 000000000..740b86881 --- /dev/null +++ b/docs/contributing/core/documentation.md @@ -0,0 +1,81 @@ +--- +myst: + html_meta: + "description": "Writing documentation of Plone" + "property=og:description": "Writing documentation of Plone" + "property=og:title": "Writing documentation of Plone" + "keywords": "documentation, Plone" +--- + +# Writing documentation + +For general guidance for contributing documentation, see {doc}`/contributing/documentation/index`. + +For documentation authors, see {doc}`/contributing/documentation/authors`. + +## Documentation of Plone + +The comprehensive resource for Plone documentation is . +The documentation repository is on [GitHub](https://github.com/plone/documentation). +Information for how to contribute to documentation can be found at {doc}`/contributing/documentation/index`. + +## Documenting a package + +At the very least, your package should include the following forms of documentation. + +### `README.md` + +The `README.md` is the first entry point for most people to your package. +It will be included on the PyPI page for your package, and on the front page of its GitHub repository. +It should be formatted using [GitHub flavored Markdown](https://github.github.com/gfm/) to get formatted properly by those systems. + +`README.md` should include: + +- A brief description of the package's purpose. +- Installation information (How do I get it working?) +- Compatibility information (what versions of Plone does it work with?) +- Links to other sources of documentation. +- Links to issue trackers, mailing lists, and other ways to get help. + +### The manual (narrative documentation) + +The manual goes into further depth for people who want to know all about how to use the package. + +It includes topics like: + +- What are its features +- How to use them (in English — not doctests!) +- Information about architecture +- Common gotchas + +The manual should consider various audiences who may need different types of information: + +- End users who use Plone for content editing, but don't manage the site. +- Site administrators who install and configure the package. +- Integrators who need to extend the functionality of the package in code. +- System administrators who need to maintain the server running the software. + +Simple packages with limited functionality can get by with a single page of narrative documentation. +In this case, it's simplest to include it in an extended `README.md`. +Some excellent examples of a single-page README are and . + +If your project is moderately complex, you may want to set up your documentation with multiple pages. +The preferred way to do this is to add Sphinx to your project, and host your docs on [readthedocs.org](https://readthedocs.org), so that it rebuilds the documentation whenever you push to GitHub. +If you do this, your `README.md` must link off site to the documentation. + +### Reference or API documentation + +An API reference provides information about the package's public API (that is, the code that the package exposes for use from external code). +It is meant for random access to remind the reader of how a particular class or method works, rather than for reading in its entirety. + +If the codebase is written with docstrings, API documentation can be automatically generated using Sphinx. + +### Changes or history + +Best practice is to set up [towncrier](https://pypi.org/project/towncrier/) so your package will have a clear and structured history of changes. + +### Licenses + +Information about the open source license used for the package should be placed within the `docs` directory. + +For Plone core packages, this includes `LICENSE.md` and {file}`LICENSE.GPL`. diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md new file mode 100644 index 000000000..6c505c50a --- /dev/null +++ b/docs/contributing/core/index.md @@ -0,0 +1,248 @@ +--- +myst: + html_meta: + "description": "Contributing to Plone 6 Core" + "property=og:description": "Contributing to Plone 6 Core" + "property=og:title": "Contributing to Plone 6 Core" + "keywords": "Plone, Plone Contributor Agreement, License, Code of Conduct" +--- + +# Contributing to Plone 6 core + +This part describes the process of development in Plone core. +It's primarily a technical resource for setting up your development environment, fixing bugs, and writing Plone Improvement Proposals (PLIPs). + +It expands upon {doc}`/contributing/index` and, where applicable, {doc}`/contributing/first-time`. + +## Version support policy + +If you are fixing bugs, keep in mind that Plone has a [version support policy](https://plone.org/download/release-schedule) + +## Dependencies + +```{include} ../../volto/contributing/install-operating-system.md +``` + +- {ref}`setup-build-installation-python-label` {SUPPORTED_PYTHON_VERSIONS} +- {ref}`setup-build-installation-gnu-make-label` +- [git](https://help.github.com/articles/set-up-git/) +- [Pillow](https://pypi.org/project/Pillow/). +- [libxml2 and libxslt](https://gitlab.gnome.org/GNOME/libxslt/-/releases), including development headers. +- [GCC](https://gcc.gnu.org/) to compile {term}`ZODB`, {term}`Zope` and {term}`lxml`. + +The first step in fixing a bug is getting this [buildout](https://github.com/plone/buildout.coredev) running. +Start with fixing the bug on the latest branch and then [backporting](https://en.wikipedia.org/wiki/Backporting) as necessary. +[GitHub](https://github.com/plone/buildout.coredev/) by default always points to the currently active branch. +Depending on the current development cycle there may exist a future branch. + +At the moment 6.0 is the actively maintained stable branch and 6.1 is the future, currently unstable, active development branch. +More information on switching release branches is below. + +To set up a plone 6 development environment: + +```shell +cd ~/buildouts # or wherever you want to put things +git clone -b 6.1 https://github.com/plone/buildout.coredev ./plone6devel +cd ./plone6devel +./bootstrap.sh +``` + +If you run into issues in this process, please see {doc}`troubleshooting`. + +This will run for a long time if it's your first pull (approximately 20 minutes). +Once that's done pulling down eggs, you can start your new instance with: + +```shell +./bin/instance fg +``` + +or as {term}`WSGI` service with:: + +```shell +./bin/wsgi +``` + +To login, the defaults are: + +- username: admin +- password: admin + +## Switching branches + +If the bug is specific to one branch or should be [backported](http://en.wikipedia.org/wiki/Backporting), +you can easily switch branches. The first time you get a branch, you must do: + +```shell +git checkout -t origin/6.1 +``` + +This should set up a local 6.1 branch tracking the one on GitHub. +From then on you can do: + +```shell +git checkout 6.1 +``` + +To see what branch you are currently on, + +```shell +git branch +``` + +The line with a * by it will indicate which branch you are currently working on. + +```{important} +Make sure to rerun buildout if you were in a different branch earlier to get the correct versions of packages, otherwise you will get some weird behavior. +``` + +## Jenkins and mr.roboto + +Plone has a continuous integration ({term}`CI`) setup and follows CI rules. + +When you push a change to any Plone package, the testing/CI package [mr.roboto](https://github.com/plone/mr.roboto) starts running all the tests to make sure that you don't break anything. +For each Plone and Python version it runs two jobs, one for the package itself (which will give you a fast feedback, within 10 minutes) and one on the full `coredev` build (which can take up to an hour, but makes sure no other packages are affected by your change). + +See {doc}`continuous-integration` for more information. + +## Check out packages to fix + +Most packages are not in {file}`src/` by default, so you can use `mr.developer` to get the latest and make sure you are always up to date. +It can be a little daunting at first to find out which packages cause the bug in question, you can ask in if you need some help. +Once you know which packages you want, pull their source. + +At the base of your buildout, open {file}`checkouts.cfg` and add your package if it's not already there: + +```cfg +auto-checkout = + # my modified packages + plone.app.caching + plone.caching + # others + ... +``` + +Then rerun buildout to get the source packages: + +```shell +./bin/buildout +``` + +For some more tips on working with `mr.developer`, please read {doc}`mrdeveloper`. + +## Testing locally + +To run a test for the specific module you modify: + +```shell +./bin/test -m plone.app.caching +``` + +These should all run without error. +Please don't check in anything that doesn't succeed! +Now write a test case for the bug you are fixing, and make sure everything is running as it should. + +After the module level tests run with your change, please make sure other modules aren't affected by the change by running the full suite, including robot-tests (remove the `--all` to run without robot tests): + +```shell +./bin/test --all +``` + +```{note} +Tests take a long time to run. +Once you have enough experience in doing bugfixes, +you may let jenkins do this part for you. +More on that below. +``` + +## Updating `CHANGES.rst` and `checkouts.cfg` + +Once all the tests run locally on your machine, you are **ALMOST** ready to commit the changes. +You must perform a couple housekeeping chores before moving on. + +You need to create a change note of what has been modified. +This change note will be collated for the next Plone release and is important for integrators and developers to be able to see what they will get if they upgrade. + +Most packages are using [towncrier](https://pypi.org/project/towncrier/). +If that is the case, there will be a directory "news" in the package. Please follow the Towncrier format and put a note in that directory. + +For packages that haven't switched to using Towncrier, edit {file}`CHANGES.rst` (or {file}`CHANGES.txt`, or {file}`HISTORY.txt`) in each package you have modified and add a summary of the change. New changelog entries should be added at the top of {file}`CHANGES.rst`. + +Most importantly, if you didn't do it earlier, edit the file {file}`checkouts.cfg` in the buildout directory, and add your changes package to the `auto-checkout` list. +This lets the release manager know that the package has been updated, so that when the next release of Plone is cut, a new egg will be released, and Plone will need to pin to the next version of that package. +In other words, this is how your fix becomes an egg! + +Note that there is a section separator called "# Test Fixes Only". +Make sure your egg is above that line, else your egg probably won't get made quickly. +This tells the release manager that any eggs below this line have tests that are updated, but no code changes. + +Modifying the file {file}`checkouts.cfg` also triggers the buildbot, [jenkins](https://jenkins.plone.org/), to pull in the egg and run all the tests against the changes you just made. + +If your bug fix is in more than one release, for example 6.1 and 6.0, please checkout both branches, and add it to the file {file}`checkouts.cfg` in both branches. + +## Commits and pull requests + +Review the following checklist: + +- Did you fix the original bug? +- Is your code consistently formatted? You can use the [Plone Meta](https://github.com/plone/meta) project to set up your development environment to be consistent with Plone community agreed best practices. +- Did you remove any extra code and lingering {term}`pdb` statements? +- Did you write a test case for that bug? +- DO all test cases for the modules and Plone pass? +- Did you write an update note (using Towncrier or via {file}`CHANGES.rst`) in each package you changed? +- Did you add your changed packages to {file}`checkouts.cfg`? + +If you answered *Yes* to all, then you are ready to push your changes! +A couple of quick reminders: + +- Never commit directly to the development branch. Create a `pull request` (more on that below). +- Please try to make one change per commit. + If you are fixing three bugs, make three commits. + That way, it's easier to see what was done when, and easier to roll back any changes if necessary. + If you want to make large changes cleaning up whitespace or renaming variables, it's especially important to do so in a separate commit for this reason. + +## Branching and pull requests + +You should create a branch of whatever packages you are updating, and then use the [pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) feature of GitHub to get review. + +Take the `plone.app.caching` example. +After checking it out with `mr.developer`, create your own branch with: + +```shell +cd src/plone.app.caching +git checkout -b my_descriptive_branch_name +``` + +When you are ready to push your fix, push to a remote branch with: + +```shell +git push origin my_descriptive_branch_name +``` + +This will make a remote branch in GitHub. +Navigate to this branch in the GitHub user interface, and on the top right, there will be a button that says {guilabel}`Pull Request`. +This will turn your request into a pull request on the main branch. +There are people who look once a week or more for pending pull requests and will confirm whether it's a good fix, and give you feedback where necessary. +The reviewers are informal and nice, so don't worry. +They are there to help! +If you want immediate feedback, visit with the pull request link and ask for a review. + +## Finalize issues + +If you are working from an issue, please don't forget to go back to the issue, and add a link to the change set. +There is no automatic integration with GitHub yet so it's a nice way to track changes. +It also lets the reporter know that you care. + +## Additional material + +```{toctree} +:maxdepth: 1 + +continuous-integration +mrdeveloper +documentation +troubleshooting +plips +plip-review +package-dependencies +release +``` diff --git a/docs/contributing/core/mrdeveloper.md b/docs/contributing/core/mrdeveloper.md new file mode 100644 index 000000000..ce14a624d --- /dev/null +++ b/docs/contributing/core/mrdeveloper.md @@ -0,0 +1,36 @@ +--- +myst: + html_meta: + "description": "mr.developer" + "property=og:description": "mr.developer" + "property=og:title": "mr.developer" + "keywords": "mr.developer" +--- + +# `mr.developer` + +This buildout uses `mr.developer` to manage package development. +See [mr.developer on pypi](https://pypi.org/project/mr.developer/) for more information, or run `bin/develop help` for a list of available commands. + +The most common workflow to get all the latest updates is: + +```shell +git pull +bin/develop rebuild +``` + +This will get you the latest `coredev` configuration, checkout and update all packages via git in src, and run buildout to configure the whole thing. + +From time to time you can check if some old cruft has accumulated: + +```shell +bin/develop status +``` + +If this prints any lines with a question mark in front, you can cleanup by: + +```shell +bin/develop purge +``` + +This will remove packages from {file}`src/` which are no longer needed, as they have been replaced by proper egg releases of these packages. diff --git a/docs/contributing/core/package-dependencies.md b/docs/contributing/core/package-dependencies.md new file mode 100644 index 000000000..d2270a395 --- /dev/null +++ b/docs/contributing/core/package-dependencies.md @@ -0,0 +1,350 @@ +--- +myst: + html_meta: + "description": "This chapter describes the architecture of Plone's packages and dependencies." + "property=og:description": "This chapter describes the architecture of Plone's packages and dependencies." + "property=og:title": "Architecture: packages and dependecies" + "keywords": "Architecture, packages, dependecies, Plone" +--- + +# Architecture: packages and dependecies + +This chapter describes the architecture of Plone's packages and dependencies. + +## Motivation + +Plone has over the years developed many indirections in its packages and dependencies. +The goal in the long run is to untangle them and get a simple dependency graph. +This document shows the current state, as orientation. + +## Overview + +There are multiple level of dependencies: + +- package level (`setup.py`/`setup.cfg`/`pyproject.toml`) +- Python level (imports) +- ZCML level (includes) +- testing (need for layers, such as functional testing) + +At some point there were circular dependencies at the package level. +This was solved. + +Nevertheless there is indirection on all other levels. +Since Plone consists of a lot of packages, it is complex to untangle those. + +## Mental model + +A base mental model for how Plone is organized in Plone 6 is shown in the following diagram: + +```{mermaid} +block-beta + columns 1 + + Plone["Plone
the integraton of both distributions in one release"] + space + Distributions + block:dist + plone.volto + plone.classic + end + space + block:core + coreaddons["Core addons"] + coreapi["Core APIs"] + end + space + cmfplone["Products.CMFPlone"] + + space:2 + + block:layer + ploneapp["Most of plone.app.* namespace"] + otherlay["Various other packages"] + end + +space + + plonebase["plone.base"] + space + foundations["The Foundations"] + space:3 + block:foundationcomponents + ploneworld["Plone world"] + zopeeco["Zope ecosystem"] + zopecore["Zope core"] + libraries["Libraries"] + end + Plone --> Distributions + dist --> core + cmfplone --> layer + core --> cmfplone + layer --> plonebase + plonebase --> foundations + + style cmfplone fill:#ff0 + style plonebase fill:#ff0 + +``` + +As a rough model there are two packages as dividing lines: + +1. `Products.CMFPlone` +2. `plone.base` + +## Packages in detail + +Looking deeper into those, there are more sub-dividers, but first group all into the three groups: + +### Above `Products.CMFPlone` + +- Plone +- plone.api +- plone.app.iterate +- plone.app.upgrade +- plone.restapi +- plone.volto +- Products.CMFPlacefulWorkflow + +### Between `Products.CMFPlone` and `plone.base` + +- collective.monkeypatcher +- plone.app.caching +- plone.app.content +- plone.app.contentlisting +- plone.app.contentmenu +- plone.app.contentrules +- plone.app.contenttypes +- plone.app.customerize +- plone.app.dexterity +- plone.app.discussion +- plone.app.event +- plone.app.i18n +- plone.app.intid +- plone.app.layout +- plone.app.linkintegrity +- plone.app.locales +- plone.app.lockingbehavior +- plone.app.multilingual +- plone.app.portlets +- plone.app.querystring +- plone.app.redirector +- plone.app.registry +- plone.app.relationfield +- plone.app.textfield +- plone.app.theming +- plone.app.users +- plone.app.uuid +- plone.app.versioningbehavior +- plone.app.viewletmanager +- plone.app.vocabularies +- plone.app.widgets +- plone.app.workflow +- plone.app.z3cform +- plone.browserlayer +- plone.cachepurging +- plone.contentrules +- plone.formwidget.namedfile +- plone.formwidget.recurrence +- plone.i18n +- plone.namedfile +- plone.outputfilters +- plone.portlet.collection +- plone.portlet.static +- plone.portlets +- plone.protect +- plone.resourceeditor +- plone.rfc822 +- plone.schemaeditor +- plone.session +- plone.staticresources +- plone.stringinterp +- plone.theme +- plonetheme.barceloneta +- Products.isurlinportal + +### The foundation below `plone.base` + +#### Plone world + +- borg.localrole +- plone.alterego +- plone.autoform +- plone.autoinclude +- plone.batching +- plone.behavior +- plone.caching +- plone.dexterity +- plone.event +- plone.folder +- plone.indexer +- plone.intelligenttext +- plone.keyring +- plone.locking +- plone.memoize +- plone.registry +- plone.resource +- plone.rest +- plone.scale +- plone.schema +- plone.subrequest +- plone.supermodel +- plone.transformchain +- plone.uuid +- plone.z3cform +- Products.DateRecurringIndex +- Products.ExtendedPathIndex +- Products.MimetypesRegistry +- Products.PlonePAS +- Products.PortalTransforms +- Products.statusmessages + +#### Zope ecosystem + +- Chameleon +- diazo +- five.customerize +- five.intid +- five.localsitemanager +- icalendar +- Products.CMFCore +- Products.CMFDiffTool +- Products.CMFDynamicViewFTI +- Products.CMFEditions +- Products.CMFUid +- Products.DCWorkflow +- Products.ExternalMethod +- Products.GenericSetup +- Products.MailHost +- Products.PluggableAuthService +- Products.PluginRegistry +- Products.PythonScripts +- Products.Sessions +- Products.SiteErrorLog +- Products.StandardCacheManagers +- Products.ZopeVersionControl +- repoze.xmliter +- webresource +- z3c.caching +- z3c.form +- z3c.formwidget.query +- z3c.objpath +- z3c.pt +- z3c.relationfield +- z3c.zcmlhook +- zc.recipe.egg +- zc.relation +- zodbverify +- zope.copy +- zope.intid +- zope.keyreference + +#### Zope core + +- AccessControl +- Acquisition +- AuthEncoding +- beautifulsoup4 +- BTrees +- DateTime +- DocumentTemplate +- ExtensionClass +- Missing +- MultiMapping +- Persistence +- persistent +- Products.BTreeFolder2 +- Products.ZCatalog +- Record +- RestrictedPython +- transaction +- zc.lockfile +- ZConfig +- zdaemon +- ZEO +- zExceptions +- ZODB +- ZODB3 +- zodbpickle +- Zope +- zope.annotation +- zope.app.locales +- zope.browser +- zope.browsermenu +- zope.browserpage +- zope.browserresource +- zope.cachedescriptors +- zope.component +- zope.componentvocabulary +- zope.configuration +- zope.container +- zope.contentprovider +- zope.contenttype +- zope.datetime +- zope.deferredimport +- zope.deprecation +- zope.dottedname +- zope.event +- zope.exceptions +- zope.filerepresentation +- zope.globalrequest +- zope.hookable +- zope.i18n +- zope.i18nmessageid +- zope.interface +- zope.lifecycleevent +- zope.location +- zope.pagetemplate +- zope.processlifetime +- zope.proxy +- zope.ptresource +- zope.publisher +- zope.ramcache +- zope.schema +- zope.security +- zope.sendmail +- zope.sequencesort +- zope.site +- zope.size +- zope.structuredtext +- zope.tal +- zope.tales +- zope.testbrowser +- zope.testing +- zope.traversing +- zope.viewlet +- Zope2 + +#### Libraries + +- attrs +- cffi +- cssselect +- decorator +- docutils +- feedparser +- future +- importlib_metadata +- jsonschema +- Markdown +- multipart +- Paste +- PasteDeploy +- piexif +- Pillow +- pycparser +- PyJWT +- pyrsistent +- python_dotenv +- python_gettext +- requests +- roman +- sgmllib3k +- simplejson +- soupsieve +- Unidecode +- urllib3 +- waitress +- WebOb +- WebTest +- WSGIProxy2 +- zipp diff --git a/docs/contributing/core/plip-review.md b/docs/contributing/core/plip-review.md new file mode 100644 index 000000000..670838c93 --- /dev/null +++ b/docs/contributing/core/plip-review.md @@ -0,0 +1,101 @@ +--- +myst: + html_meta: + "description": "PLIP review" + "property=og:description": "PLIP review" + "property=og:title": "PLIP review" + "keywords": "PLIP, review, Plone Improvement Proposal, Plone" +--- + +# PLIP review + +A Plone Improvement Proposal (PLIP) is a formal process to propose a change to improve Plone. + +## Expectations + +A good PLIP review takes about four hours. +Please plan accordingly. + +When you are done, if you have access to core, commit the review to the `plips` folder of [buildout.coredev](https://github.com/plone/buildout.coredev), and reference the PLIP in your commit message. +If you do not have access, attach your review to the PLIP ticket itself. + +## Setting up the environment + +Follow the instructions in {doc}`index`. +You will need to checkout the branch to which the PLIP is assigned. +Instead of running the buildout with the default buildout file, you will run the configuration specific to that PLIP: + +```shell +./bin/buildout -c plips/plip-XXXX.cfg +``` + +## Functionality review + +This section describes the topics that may be addressed in a PLIP review, depending on the nature of the PLIP itself. + +### General + +- Does the PLIP actually do what the implementers proposed? + Are there incomplete variations? +- Were there any errors running buildout? + Did the migration(s) work? +- Do error and status messages make sense? + Are they properly internationalized? +- Are there any performance considerations? + Has the implementer addressed them, if so? +- For changes in the UI, are they accessible for people using assisted technologies? + +### Bugs + +- Are there any bugs? + Nothing is too big nor small. +- Do fields handle wacky, incomplete or harmful data? + How about strings in date fields, or nulls in required? +- Is validation up to snuff and sensical? + Is it too restrictive or not restrictive enough? + +### Usability Issues + +- Is the implementation usable? +- How will novice end users respond to the change? +- Does this PLIP need a usability review? + If you think this PLIP needs a usability review, change the state to "please review" and add a note in the comments. +- Is the PLIP consistent with the rest of Plone? + For example, if there is control panel configuration, does the new form fit in with the rest of the panels? +- Does everything flow nicely for novice and advanced users? + Is there any workflow that feels odd? +- Are there any new permissions and do they work properly? + Does their role assignment make sense? + +### Documentation Issues + +- Is the corresponding documentation for the end user, be it developer or Plone user, sufficient? +- Is the change itself properly documented? + +Report bugs or issues on GitHub as you would for any Plone bug. +Reference the PLIP in the bug, assign to its implementer, and add a tag for the PLIP in the form of `plip-xxx`. +This way the implementer can find help if they need it. +Also set a priority for the ticket. +The PLIP will not be merged until all blockers and critical bugs are fixed. + +### Code Review + +#### Python + +- Is this code maintainable? +- Is the code properly documented? +- Does the code adhere to Plone best practices for formatting? +- Are they importing deprecated modules? + +#### JavaScript + +- Does the JavaScript meet Plone's set of JavaScript standards? +- Does the JavaScript work in all currently supported browsers? + Is it performant? + +#### ME/TAL + +- Does the PLIP use views appropriately, avoiding too much logic? +- Is there any code in a loop that could potentially be a performance issue? +- Are there any deprecated or old style ME/TAL lines of code, such as using `DateTime`? +- Is the rendered HTML compliant with standards? Are IDs and classes used appropriately? diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md new file mode 100644 index 000000000..7f7b766d9 --- /dev/null +++ b/docs/contributing/core/plips.md @@ -0,0 +1,276 @@ +--- +myst: + html_meta: + "description": "Plone Improvement Proposals (PLIPs)" + "property=og:description": "Plone Improvement Proposals (PLIPs)" + "property=og:title": "Plone Improvement Proposals (PLIPs)" + "keywords": "Plone Improvement Proposal, PLIP)" +--- + +# Plone Improvement Proposals (PLIPs) + +A {term}`PLIP` is a Plone Improvement Proposal. + +It is a change to a Plone package that would affect everyone. +PLIPs go through a different process than bug fixes because of their broad reach. +The Plone Framework Team reviews all PLIPs to make sure that it's in the best interest of the broader community, and that it's of high quality. + +## Frequently asked questions about PLIPs + +This section provides detailed answers to common questions about PLIPs. + +### PLIP or bugfix? + +In general, anything that changes the API of Plone in the backend or the user interface (UI) on the front end should be filed as a PLIP. +When in doubt, submit it as a PLIP. +The Framework Team will reclassify it if your proposal falls below the threshold. +If the change you are proposing is not in the scope of a PLIP, a GitHub pull request or issue is the right format. +The key point here is that each change must be documented, allowing it to be tracked and understood. + +### Who can submit PLIPs? + +Anyone who has signed a Plone Contributor Agreement can work on a PLIP. + +You do not have to be the most amazing coder in the world to submit a PLIP. +The Framework Team is happy to help you at any point in the process. + +Submitting a PLIP can be a great learning process. + +When the PLIP is accepted, a Framework Team member will "champion" your PLIP and follow up to its completion. + +PLIPs are not just for code experts. +If you have ideas on new interactions or UI your ideas are more than welcome. + +The community will help you pair up with implementers if needed. + +### What is a PLIP champion? + +When you submit your PLIP and it is approved, a Framework Team member will take on the role of champion for that PLIP. + +They are there to help you through completion, answer questions and provide guidance. + +A champion fulfills the following tasks: + +- Answer any questions the PLIP implementer has, technical or otherwise. +- Encourage the PLIP author by giving feedback and encouragement. +- Keep the implementer aware of timelines, and push to get things done on time. +- Assist with finding additional help when needed to complete the implementation in a timely matter. + +Keep in mind that champions are volunteers as well, and have other tasks in life. +That means you will have to play an active role in asking for help or guidance. + +### Can I get involved in other ways? + +If you want to experience the process and how it works, help us review PLIPs as the implementations finish up. +Ask one of the Framework Team members what PLIPs are available for review, or check the status of PLIPs at the [GitHub issues](https://github.com/plone/Products.CMFPlone/issues) page +for [Products.CMFPlone](https://github.com/Plone/Products.CMFPlone) +for [issues tagged with "03 type: feature (plip)"](https://github.com/plone/Products.CMFPlone/labels/03%20type%3A%20feature%20%28plip%29). + +Make sure to let the community know you intend to review the PLIP by communicating that to the [Framework Team](https://community.plone.org/c/development/framework-team). + +Then, follow the instructions for {doc}`reviewing a PLIP `. + +Thank you in advance! + +### When can I submit a PLIP? + +Today, tomorrow, any time! + +After the PLIP is accepted, the Framework Team will try to judge complexity and time to completion, and assign it to a milestone. + +### When is the PLIP due? + +**Summary: As soon as you get it done.** + +Ideally, a PLIP should be completed for the release to which it's assigned. +Sometimes life gets in the way, and a PLIP may have to be re-assigned to the following release. + +In general, PLIPs shouldn't take more than a year, otherwise they should be closed. A new PLIP can follow up if there is more capacity to see it through. + +### What happens if your PLIP is not accepted? + +If a PLIP isn't accepted in core, it doesn't mean it's a bad idea. +It is often the case that there are competing implementations, and the community wants to see it vetted as an add-on before "blessing" a particular implementation. + +## Process Overview + +1. Submit a PLIP at any time. +2. PLIP is approved for inclusion into core for a given release. +3. Developer implements PLIP (code, tests, documentation). +4. PLIP is submitted for review by developer. +5. Framework Team reviews the PLIP and gives feedback. +6. Developer addresses concerns in feedback and re-submits the PLIP, if necessary. +7. This may go back and forth a few times, until both the Framework Team and developer are happy with the result. +8. PLIP is approved for merge. + In rare circumstances, a PLIP will be rejected. + This is usually the result of the developer not responding to feedback or dropping out of the process. + Hang in there! +9. After all other PLIPs are merged, a release is cut. + Standby for bugs! + +(how-to-submit-a-plip)= + +## How to submit a PLIP + +Whether you want to update the default theme, or rip out a piece of architecture, major changes should go through the PLIP process. +If you need help at any point in this process, please contact a member of the Framework Team personally or ask for help at the [Framework Team Space](https://community.plone.org/c/development/framework-team). + +A PLIP is a [GitHub issue](https://github.com/plone/Products.CMFPlone/issues/new) on [`Products.CMFPlone`](https://github.com/Plone/Products.CMFPlone) with a special template and a specific tag. + +To get started, open a new issue. +The issue will be prefilled with headings and comments for a bug or a PLIP. +Remove the bug part. +Fill in all applicable fields. +After submitting, select the tag `03 type: feature (plip)` for the issues. + +When writing a PLIP, be as specific and to-the-point as you can. +Remember your audience. +To get support for your proposal, people will have to be able to read it! + +A good PLIP is sufficiently clear for a knowledgeable Plone user to understand the proposed changes, and sufficiently detailed for the release manager and other developers to understand the full impact the proposal would have on the code base. + +You don't have to list every line of code that needs to be changed, but you should also give an indication that you have some idea of how the change can be feasibly implemented. + +After your PLIP is written, solicit feedback on your idea on the [Plone Community Forum](https://community.plone.org/). +In this vetting process, you want to make sure that the change won't adversely affect other people on accident. +Others may be able to point out risks or even offer up better or existing solutions. + +Please note a few things: + +- It is very rare that the "Risks" section will be empty or none. +- If you find this is the case, and your PLIP is anything more than trivial, maybe some more vetting should be done. +- The seconder field is REQUIRED. + +The PLIP will be sent back to you if it is not filled in. +Currently, this is just someone else who thinks your PLIP is a good idea, a +1. + +In the near future, the seconder should either a coding partner, or someone who is willing and able to finish the PLIP should something happen to the implementer. + +### Evaluating PLIPs + +After you submit your PLIP, the Framework Team will meet within a couple weeks, and let you know if the PLIP is accepted. +If the PLIP is not accepted, please don't be discouraged! + +Most PLIPs first start as an add-on, if possible, to make sure it works in practice. + +All communication with you occurs on the PLIP issue itself. +Please keep your eyes and inbox open for changes. + +These are the criteria by which the framework team will review your work: + +- What is the size and status of the work needed to be done? +- Is it already an add-on and well established? +- Is this idea well baked and expressed clearly? +- Does the work proposed belong in Plone now, or in the future? +- Is this PLIP more appropriate as a qualified add-on? +- Is this PLIP too risky? + +See the {doc}`plip-review` page for more information. + +## Implementing your PLIP + +You can start the development at any time, but if you are going to modify Plone itself, it is a good idea to wait to see if your idea is approved. + +### General Rules + +- Any new packages must be in a branch in the `plone` namespace in GitHub. + You don't have to develop there, but it must be there when submitted. + Use branches off of the repositories under the Plone GitHub organization, see below. +- Most importantly, the PLIP reviewers must be able run buildout and everything should "just work"™. +- Any new code must: + + - Be {doc}`properly documented `. + - Have clear code. + - Follow current best practices in coding style. The [Plone Meta](https://github.com/plone/meta) project can help you set up your environment. For Volto, follow [this guide](https://6.docs.plone.org/volto/contributing/linting.html). + - [Be tested](https://5.docs.plone.org/develop/testing/index.html). For Volto, follow [this guide](https://6.docs.plone.org/volto/contributing/testing.html) + +```{todo} +Update links from Plone 5 to Plone 6 Documentation, once content is migrated. +See https://github.com/plone/documentation/issues/1330 and other issues. +``` + +### Creating a new PLIP branch + +Create a buildout configuration file for your PLIP in the `plips` folder of {file}`buildout.coredev`. + +Give it a descriptive name, starting with the PLIP number, for example, {file}`plip-1234-widget-frobbing.cfg`. + +The PLIP number is your PLIP's issue number. + +This file will define the branches you're working with in your PLIP, along with other buildout configuration. + +It should look something like the following, such as in a file {file}`plips/plip-1234-widget-frobbing.cfg`. + +```ini +[buildout] +extends = plipbase.cfg +auto-checkout += + plone.somepackage + plone.app.someotherpackage + +[sources] +plone.somepackage = git https://github.com/plone/plone.somepackage.git branch=plip-1234-widget-frobbing +plone.app.someotherpackage = git https://github.com/plone/plone.app.somepackage.git branch=plip-1234-widget-frobbing + +[instance] +eggs += + plone.somepackage + plone.app.someotherpackage +zcml += + plone.somepackage + plone.app.someotherpackage +``` + +Use the same naming convention when you branch existing packages. +You should always branch packages when working on PLIPs. + +### Working on a PLIP + +To work on a PLIP, you bootstrap buildout, and then invoke buildout with your PLIP configuration: + +```shell +virtualenv . +./bin/pip install -r requirements.txt +./bin/buildout -c plips/plip-1234-widget-frobbing.cfg +``` + +If you are using a {file}`local.cfg` to extend your PLIP file with some changes that you do not want to commit accidentally, be aware that you need to override some settings from {file}`plipbase.cfg` to avoid some files being created in the {file}`plips` directory or in the directory above the buildout directory. +This is done as shown below. + +```ini +[buildout] +extends = plips/plip-1234-widget-frobbing.cfg +develop-eggs-directory = ./develop-eggs +bin-directory = ./bin +parts-directory = ./parts +sources-dir = ./src +installed = .installed.cfg + +[instance] +var = ./var +``` + +### Finishing up + +Before marking your PLIP as ready for review, please add a file to give a set of instructions to the PLIP reviewer. +This file should be called {file}`plip__notes.txt`. +This should include, but is not limited to: + +- URLs pointing to all documentation created and updated +- Any concerns and issues still remaining +- Any weird buildout things + +Once you have finished, update your PLIP issue to indicate that it is ready for review. +The Framework Team will assign 2-3 people to review your PLIP. +They will follow the guidelines listed at {doc}`plip-review`. + +After the PLIP has been accepted by the Framework Team and the release managers, you will be asked to merge your work into the main development line. +Merging the PLIP in is not the hardest part, but you must think about it when you develop. + +You'll have to interact with a large number of people to get it all set up. + +The merge may have unintended interactions with other PLIPs coming in. +During the merge phase you must be prepared to help out with all the features and bugs that arise. + +If all went as planned, the next Plone release will carry on with your PLIP in it. +You'll be expected to help out with that feature after it's been released (within reason). diff --git a/docs/contributing/core/release.md b/docs/contributing/core/release.md new file mode 100644 index 000000000..f9eba0c43 --- /dev/null +++ b/docs/contributing/core/release.md @@ -0,0 +1,127 @@ +--- +myst: + html_meta: + "description": "Plone release process" + "property=og:description": "Plone release process" + "property=og:title": "Plone release process" + "keywords": "Plone, release, process" +--- + +# Plone release process + +This chapter describes the process to release Plone and its packages. + +## Release process for Plone packages + +To keep the Plone software stack maintainable, the Python egg release process must be automated to a high degree. +This happens by enforcing Python packaging best practices, and then making automated releases using [`zest.releaser`](https://github.com/zestsoftware/zest.releaser/). + +Plone coredev specific features extend on that using [`plone.releaser`](https://github.com/plone/plone.releaser). + +Anyone with necessary PyPI permissions must be able to make a new release by running the `fullrelease` command. +This command includes the following requirements. + +```{note} +All files mentioned in this list may be written in Markdown or reStructuredText and have the appropriate file name suffix. +``` + +- All releases must be hosted on PyPI. +- All versions must be tagged in version control. +- Each package must have a {file}`README` file with links to the version control repository and issue tracker. +- {file}`CHANGES` ({file}`docs/HISTORY`) must be always up-to-date and must contain list of functional changes which may affect package users. +- {file}`CHANGES` must contain release dates. +- {file}`README` and {file}`CHANGES` must be visible on PyPI. +- Released eggs must contain generated gettext `.mo` files, but these files must not be committed to the repository. + The `.mo` files can be created with the `zest.pocompile` add-on, which should be installed together with `zest.releaser`. +- `.gitignore` and `MANIFEST.in` must reflect the files going in to the egg (must include page template, po files). + +```{seealso} +[High quality automated package releases for Python with `zest.releaser`](https://opensourcehacker.com/2012/08/14/high-quality-automated-package-releases-for-python-with-zest-releaser/). +``` + +## Special packages + +The Plone Release Team releases the core Plone packages. +Several others also have the rights to release individual packages on [PyPI](https://pypi.org/). +If you have those rights on your account, you should feel free to make releases. + +Some packages need special care, or should be done only by specific people, as they know what they are doing. +These are: + +`Products.CMFPlone`, `Plone`, and `plone.app.upgrade` +: Please leave these to the release managers, Eric Steele and Maurits van Rees. + +`plone.app.locales` +: Please leave this to the i18n team lead, Vincent Fretin. + +## Plone core release process checklist + +1. Check Jenkins status. + Check the latest Plone coredev job on [Jenkins](https://jenkins.plone.org/). + It should be green, but if it is not, fix the problem first. + +2. Check out `buildout.coredev`. + + ```shell + git clone git@github.com:plone/buildout.coredev.git + cd buildout.coredev + git checkout 6.1 + python bootstrap.py + bin/buildout -c buildout.cfg + ``` + +3. Check packages for updates. + Check all packages for updates, add to or remove from `checkouts.cfg` accordingly. + This script may help: + + ```shell + bin/manage report --interactive + ``` + + This step should not be needed, because we do the check for every single commit, but people may still have forgotten to add a package to the `checkouts.cfg` file. + +4. Check packages individually. + + Use the `bin/fullrelease` script from the core development buildout. + This includes extra checks that we have added in `plone.releaser`. + It guides you through all the next steps. + + 1. Check changelog. + Check if `CHANGES` is up-to-date. + All changes since the last release should be included. + A "Fixes" or "New" header should be included, with the relevant changes under it. + Upgrade notes are best placed here as well. + Compare `git log HEAD...` with `CHANGES`, or from `zest.releaser` use the command `lasttaglog `. + 2. Run [pyroma](https://pypi.org/project/pyroma/). + 3. Run [check-manifest](https://pypi.org/project/check-manifest/). + 4. Check package "best practices" (`README`, `CHANGES`, `src` directory). + 5. Check if the version in `setup.py` is correct and follows our versioning best practice. + 6. Make a release (zest.releaser: `bin/fullrelease`) + 7. Remove packages from auto-checkout section in `checkouts.cfg` and update `versions.cfg`. + +5. Make sure `plone.app.upgrade` contains an upgrade step for the future Plone release. +6. Update CMFPlone version in `profiles/default/metadata.xml`. +7. Create an issue in to ask the i18n team lead @vincentfretin to do a `plone.app.locales` release. +8. Create a pending release (directory) on [dist.plone.org](https://dist.plone.org/). + + 1. Copy all core packages there. + 2. Possibly make an alpha or beta release of CMFPlone. + 3. Copy the `versions.cfg` file from coredev to there. + +9. Write an email to the Plone developers list announcing a pending release. +10. Update `plone.app.locales` version. +11. Create a unified changelog. + + ```shell + bin/manage changelog + ``` + +12. Make the final release on [dist.plone.org](https://dist.plone.org/) (remove "-pending") +13. Update the "-latest" link on [dist.plone.org](https://dist.plone.org/). +14. For Plone 5.x versions only, create the new release on [Launchpad](https://launchpad.net/plone/). +15. Create a release page on [plone.org](https://plone.org/download/releases) +16. Wait for installers to be uploaded to Launchpad, with a link to the [plone.org](https://plone.org/download/releases) release page. +17. Publish release page on [plone.org](https://plone.org). +18. Update plone.org homepage links to point to the new release. +19. Send out announcement to the plone-announce email distribution list. +20. Ask the security team to update the [Hotfixes](https://plone.org/security/hotfixes/) page in the configuration control panel. diff --git a/docs/contributing/core/troubleshooting.md b/docs/contributing/core/troubleshooting.md new file mode 100644 index 000000000..7a08cfa17 --- /dev/null +++ b/docs/contributing/core/troubleshooting.md @@ -0,0 +1,55 @@ +--- +myst: + html_meta: + "description": "Troubleshooting development issues in Plone" + "property=og:description": "Troubleshooting development issues in Plone" + "property=og:title": "Troubleshooting development issues in Plone" + "keywords": "Troubleshooting, development issues, Plone" +--- + +# Troubleshooting + +This chapter describes how to troubleshoot development issues in Plone. + +## Buildout issues + +Buildout can be frustrating for those unfamiliar with parsing through error messages. + +These errors are normally a quick fix. + +### Errors running `bootstrap.py` + +You may not even get to running buildout, before you already get an error. +As example: + +```shell + File "/usr/local/lib/python2.6/site-packages/distribute-0.6.13-py2.6.egg/pkg_resources.py", line 556, in resolve + raise VersionConflict(dist,req) # XXX put more info here + pkg_resources.VersionConflict: (zc.buildout 1.5.1 (/usr/local/lib/python2.6/site-packages/zc.buildout-1.5.1-py2.6.egg), Requirement.parse('zc.buildout==1.5.2')) +``` + +Buildout has noticed that the version of buildout required by the file `bootstrap.py` you are trying to run does not match the version of buildout in your Python library. +In the error above, your system has buildout 1.5.1 installed and the `bootstrap.py` file wants to run with 1.5.2. + +To fix, you have a couple options. +First, you can force buildout to run with the version you already have installed by invoking the version tag. +This tells your Plone `bootstrap.py` file to play nicely with the version that you already have installed. +In the case of the error pasted above, that would be: + +```shell +python bootstrap.py --version=1.5.1 +``` + +The other option is to delete your current egg and force the upgrade. +In the case of the error above, delete the egg the system currently has, for example: + +```shell +rm -rf /usr/local/lib/python3.10/site-packages/zc.buildout-1.5.1-py3.10.egg +``` + +When you rerun bootstrap, it will look for the buildout of the egg, note that there isn't one, and then go fetch a new egg in the version that it wants for you. + +Do one of those and re-run bootstrap. + +One other thing of note is that running bootstrap effectively ties that Python executable and all of its libraries to your buildout. +If you have several Python installs, and want to switch which Python is tied to your buildout, rerun `bootstrap.py` with the new Python (and then rerun buildout). diff --git a/docs/contributing/index.md b/docs/contributing/index.md index 24be3d4ff..54735e7e7 100644 --- a/docs/contributing/index.md +++ b/docs/contributing/index.md @@ -20,7 +20,6 @@ To contribute to any project in Plone, you must follow the policies of the [Plon This chapter covers policies that apply to all Plone projects. Other chapters cover any variations and additional policies for each project. - (contributing-sign-and-return-the-plone-contributor-agreement-label)= ## Sign and return the Plone Contributor Agreement @@ -48,7 +47,6 @@ Sign the Plone Contributor Agreement - [Plone Framework Components Relicensing Policy, Framework Components Available Under a BSD License](https://plone.org/foundation/about/materials/foundation-resolutions/plone-framework-components-relicensing-policy#3b050ad2-361a-46de-b5c6-9b90f8947eb7) ``` - (contributing-code-of-conduct-label)= ## Code of Conduct @@ -56,14 +54,12 @@ Sign the Plone Contributor Agreement The Plone Foundation has published a [Code of Conduct](https://plone.org/foundation/materials/foundation-resolutions/code-of-conduct). All contributors to the Plone Documentation follow the Code of Conduct. - (contributing-first-time-contributors-label)= ## First-time contributors First-time contributors should read and follow our guide {doc}`first-time`. - (contributing-continuous-integration-label)= ## Continuous integration @@ -72,7 +68,6 @@ Plone project repositories use continuous integration (CI) to run tests, ensure Plone uses GitHub Actions, Jenkins, Cypress, Netlify, and other services for CI. All of a project's CI jobs must pass before a contribution may be accepted. - (contributing-change-log-label)= ## Change log entry @@ -93,18 +88,18 @@ When making a change to its documentation, set up, continuous integration, or ot The change log entry's format must be `###.type`, where `###` is the referenced GitHub issue or pull request number, `.` is the literal extension delimiter, and `type` is one of the following strings. -- `breaking` for breaking changes -- `bugfix` for bug fixes -- `documentation` for documentation -- `feature` for new features -- `internal` for internal changes +- `breaking` for breaking changes +- `bugfix` for bug fixes +- `documentation` for documentation +- `feature` for new features +- `internal` for internal changes A package configures the types it allows in a file `towncrier.toml` located at the root of its package directory. The content of this file must include the following. -- A brief message that summarizes the changes in your contribution. -- An attribution to yourself, in the format of `@github_username`. +- A brief message that summarizes the changes in your contribution. +- An attribution to yourself, in the format of `@github_username`. ```{important} These change log entries become narrative documentation. @@ -112,13 +107,13 @@ These change log entries become narrative documentation. You can write good change log entries with the following guidance. -- Use a narrative format, in the past tense, proper English spelling and grammar, and inline markup as needed. -- Write your change log entry for its appropriate audience. - - Most entries should address _users_ of the software. - - An entry for a change to a public API should address _developers_. -- If you fix a bug, write what was broken and is now fixed. -- If you add or change a feature or public API, write a summary of previous behavior, what it does now, and how to use it. -- Refer to narrative documentation as needed. +- Use a narrative format, in the past tense, proper English spelling and grammar, and inline markup as needed. +- Write your change log entry for its appropriate audience. + - Most entries should address _users_ of the software. + - An entry for a change to a public API should address _developers_. +- If you fix a bug, write what was broken and is now fixed. +- If you add or change a feature or public API, write a summary of previous behavior, what it does now, and how to use it. +- Refer to narrative documentation as needed. The following text is an example of a good change log entry, placed inside {file}`/news/4470.documentation`. @@ -132,7 +127,6 @@ The following would be a poor change log entry. Fix #123456 by chaning config of additionalToolbarComponents [did_not_read_this_guide] ``` - (contributing-project-configuration-files-label)= ## Project configuration files @@ -141,7 +135,6 @@ To standarize the developer experience across packages, a configuration tool is See the [tool documentation](https://github.com/plone/meta) for more information. - (contributing-specific-contribution-policies-for-projects-label)= ## Specific contribution policies of projects @@ -171,7 +164,6 @@ Volto : Plone 6 default frontend. See {doc}`../volto/contributing/index`. - (contributing-releases-label)= ## Releases @@ -182,7 +174,6 @@ We use [`zest.releaser`](https://zestreleaser.readthedocs.io/en/latest/) for rel We use [`release-it`](https://github.com/release-it/release-it) for releasing the Node.js packages used in Plone, including {doc}`Volto ` and the [Classic UI mockup](https://github.com/plone/mockup). - ```{toctree} --- caption: Contributing @@ -192,6 +183,7 @@ hidden: true first-time documentation/index +core/index plone-api plone-restapi volto diff --git a/docs/glossary.md b/docs/glossary.md index 4e161d317..bf30a43de 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -77,7 +77,7 @@ pipx pyenv Python version management. - [pyenv](https://github.com/pyenv/pyenv) lets you easily switch between multiple versions of Python. + [pyenv](https://github.com/pyenv/pyenv) lets you easily switch between multiple versions of Python. pm2 [PM2](https://pm2.keymetrics.io/) is a daemon process manager. @@ -470,6 +470,10 @@ language tag - W3C Working Draft [Language Tags and Locale Identifiers for the World Wide Web](https://www.w3.org/TR/ltli/) ``` +lxml + A library used for processing XML and HTML with Python. It is a binding for the libxml2 and libxslt C libraries. + See https://lxml.de/ + gettext UNIX standard software translation tool. See https://www.gnu.org/software/gettext/. @@ -673,6 +677,9 @@ UID UID is an acronym meaning "unique identifier". A UID is an identifier that is guaranteed to be unique among all identifiers used for those objects and for a specific purpose. +pdb + The Python Debugger module is an interactive source code debugger for Python programs. See https://docs.python.org/3/library/pdb.html + integer identifier intid In Plone, an integer identifier, or intid, is used to uniquely identify content objects within a Plone site. @@ -741,7 +748,7 @@ Plone frontend TLS Transport Layer Security Transport Layer Security (TLS) is a cryptographic protocol designed to provide communications security over a computer network. - + ```{seealso} [Transport Layer Security](https://developer.mozilla.org/en-US/docs/Web/Security/Transport_Layer_Security) article from MDN. ``` diff --git a/requirements.txt b/requirements.txt index a6c516054..a0d60d48f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,4 +23,5 @@ sphinxcontrib-qthelp==1.0.3 # https://github.com/plone/documentation/issues/160 sphinxcontrib-serializinghtml==1.1.5 # https://github.com/plone/documentation/issues/1604 sphinxcontrib-video sphinxext-opengraph +sphinxcontrib.mermaid==0.9.2 vale==2.30.0 diff --git a/styles/Vocab/Plone/accept.txt b/styles/Vocab/Plone/accept.txt index c93207b67..15b0ecf03 100644 --- a/styles/Vocab/Plone/accept.txt +++ b/styles/Vocab/Plone/accept.txt @@ -8,8 +8,10 @@ accessor APIs [Aa]sync [Bb]ackend +backport(ed|ing) Barceloneta [Bb]oolean +bugfix buildout cacheable doctest @@ -17,11 +19,14 @@ folderish fieldset getter JavaScript +[Jj]enkins jQuery +libxslt Mockup npm nvm Pastanaga +PLIP(s) Plone pluggab(le|ility) programatically @@ -34,6 +39,7 @@ RichText Sass Schuko subfolder +[Tt]owncrier transpile[dr]{0,1} unregister UUID From 83b708f7ad337fd5af33508946a1fc446b99caa1 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 19 Jun 2024 00:06:39 -0700 Subject: [PATCH 281/810] Revert whitespace changes and use naked URLs (< and > are not required with a MyST extension we use), thus simplifying the diff review against `6.0`. --- coredev/agreement.md | 13 +- coredev/continous-integration.md | 9 + coredev/contributors_agreement_explained.md | 16 +- coredev/documentation.md | 36 +- coredev/getting-started-with-development.md | 88 ++-- coredev/git.md | 9 +- coredev/guidelines.md | 31 +- coredev/index.md | 5 +- coredev/mrdeveloper.md | 2 +- coredev/packages-dependencies.md | 491 ++++++++++---------- coredev/plip-review.md | 56 ++- coredev/plips.md | 80 ++-- coredev/release.md | 67 +-- coredev/roboto.md | 21 +- coredev/troubleshooting.md | 11 + 15 files changed, 512 insertions(+), 423 deletions(-) diff --git a/coredev/agreement.md b/coredev/agreement.md index 53b5bd6f8..a95b9a8cf 100644 --- a/coredev/agreement.md +++ b/coredev/agreement.md @@ -23,19 +23,19 @@ Sending in a contributors agreement does not guarantee your commit access to the We ask that before requesting core access you familiarize yourself a little with the community since they will help you get ramped up: -- Ask and (especially) answer questions on [the Plone forum](https://community.plone.org/) and in {doc}`Plone chat ` with a focus on getting to know the active developers a bit. +- Ask and (especially) answer questions on [the Plone forum](https://community.plone.org/) and in {doc}`Plone chat ` with a focus on getting to know the active developers a bit. -- Attend a [conference](https://plone.org/news-and-events/events/plone-conferences), [symposium](https://plone.org/news-and-events/events/regional), or participate in a [sprint](https://plone.org/news-and-events/events/sprints). +- Attend a [conference](https://plone.org/news-and-events/events/plone-conferences), [symposium](https://plone.org/news-and-events/events/regional), or participate in a [sprint](https://plone.org/news-and-events/events/sprints). There are plenty of opportunities to meet the community and start contributing through various coding sessions, either in person or on the web. You may even be able to get immediate core access at a conference if you are flexing your mad coding skills and the right people are attending. -- Get your feet wet by contributing to the [collective](https://collective.github.io/). +- Get your feet wet by contributing to the [collective](https://collective.github.io/). Don't worry about getting it perfect or asking for help. This way you get to know us and we improve our code together as a community. -- **Patches:** Historically we encouraged people to submit patches to the ticket collector. +- **Patches:** Historically we encouraged people to submit patches to the ticket collector. These tickets are usually ignored forever. Technically, for us to accept your patch, you must sign the contributors agreement. If you want to contribute fixes, please just sign the agreement and go through the standard GitHub pull request process described below until you feel comfortable to bypass review. @@ -43,7 +43,7 @@ We ask that before requesting core access you familiarize yourself a little with Once you have familiarized yourself with the community and you are excited to contribute to the core: -- Sign the contributor agreement at , then either send by postal mail to the address provided, or scan and email it to . +- Sign the contributor agreement at , then either send by postal mail to the address provided, or scan and email it to . This offers both copyright protection and ensures that the Plone Foundation is able to exercise some control over the codebase, ensuring it is not appropriated for someone's unethical purposes. For questions about why the agreement is required, please see [About the Plone Contributor Agreement ](https://plone.org/foundation/contributors-agreement). @@ -54,6 +54,7 @@ A common way to start contributing is to participate in a [Plone sprint](https:/ **Welcome to the Plone community!** + ## Dealing with pull requests on GitHub Before we can merge a pull request, we must ensure that the author has signed the Plone Contributor Agreement. @@ -61,6 +62,6 @@ Before we can merge a pull request, we must ensure that the author has signed th If they're listed in either the [Developers](https://github.com/orgs/plone/teams/developers/members) or [Contributors](https://github.com/orgs/plone/teams/contributors/members) team, the author has signed the Plone Contributor Agreement, so we can go ahead and merge. If they aren't listed there, they may have signed and returned the Plone Contributor Agreement, but they were not yet added to a team. -You can ask to verify. +You can ask agreements@plone.org to verify. Pull requests without a signed Plone Contributor Agreement can only be merged in trivial cases, and only by the release manager. diff --git a/coredev/continous-integration.md b/coredev/continous-integration.md index 3f225f7f2..49eb23d35 100644 --- a/coredev/continous-integration.md +++ b/coredev/continous-integration.md @@ -19,6 +19,7 @@ Build breakages are a normal and expected part of the development process. Our aim is to find errors and eliminate them as quickly as possible, without expecting perfection and zero errors. Though, there are some essential rules that needs to be followed in order to achieve a stable build. + ## 1) Don't check in on a broken build Do not make things more complicated for the developer who is responsible for breaking the build. @@ -37,6 +38,7 @@ If this is the case, there is no way around breaking a single build for a certai In this case run the all tests locally with all the changes and commit them within a time frame of ten minutes. ``` + ## 2) Always run all commit tests locally before committing Following this practice ensures the build stays green, and other developers can continue to work without breaking the first rule. @@ -48,28 +50,33 @@ Furthermore, a common source of errors on check-in is to forget to add some file If you follow this rule and your local build passes, you can be sure that this is because someone else checked in in the meantime, or because you forgot to add a new class or configuration file that you have been working on into the version control system. + ## 3) Wait for commit tests to pass before moving on Always monitor the build's progress, and fix the problem right away if it fails. You have a far better chance of fixing the build, if you just introduced a regression than later. Also another developer might have committed in the meantime (by breaking rule 1), making things more complicated for yours. + ## 4) Never go home on a broken build Taking into account the first rule of CI ("Don't check in on a broken build"), breaking the build essentially stops all other developers from working on it. Therefore going home on a broken build (or even on a build that has not finished yet) is **not** acceptable. It will prevent all the other developers to stop working on the build or fixing the errors that you introduced. + ## 5) Always be prepared to revert to the previous revision In order for the other developers to be able to work on the build, you should always be prepared to revert to the previous (passing) revision. + ## 6) Time-box fixing before reverting When the build breaks on check-in, try to fix it for ten minutes. If, after ten minutes, you aren't finished with the solution, revert to the previous version from your version control system. This way you will allow other developers to continue to work. + ## 7) Don't comment out failing tests Once you begin to enforce the previous rule, the result is often that developers start commenting out failing tests in order to get the build passing again as quick as possible. @@ -80,6 +87,7 @@ This means that we either caused a regression, made assumptions that are no long You should always either fix the code (if a regression has been found), modify the test (if one of the assumptions has changed), or delete it (if the functionality under test no longer exists). + ## 8) Take responsibility for all breakages that result from your changes If you commit a change and all the tests you wrote pass, but others break, the build is still broken. @@ -93,6 +101,7 @@ If you think you hit such a test, try to fix it (better) or re-run the Jenkins j In any case the developer who made the commit is responsible to make it pass. + ## Further Reading Those rules were taken from the excellent book "Continuous Delivery" by Jez Humble and David Farley (Addison Wesley), and have been adopted and rewritten for the Plone community. diff --git a/coredev/contributors_agreement_explained.md b/coredev/contributors_agreement_explained.md index 2915b5e61..ef04222b0 100644 --- a/coredev/contributors_agreement_explained.md +++ b/coredev/contributors_agreement_explained.md @@ -17,7 +17,8 @@ Prospective contributors to the Plone code base are required to sign a contribut This document explains the purposes of this, along with questions and answers about what this means. -The Plone Contributor's Agreement can be found at . +The Plone Contributor's Agreement can be found at https://plone.org/foundation/contributors-agreement. + ## About the Plone Contributor Agreement @@ -26,9 +27,10 @@ Prior to the Foundation, the intellectual property of Plone was jointly held by The community members who formed the Foundation felt that having the Foundation hold these rights provides several benefits: -1. **Minimizing confusion / maximizing business compatibility** -- Organizations considering adopting Plone have a simple answer for "Who owns this?", rather than a more complicated answer that might scare away the legally-cautious. -2. **Trademark protection** -- By having the Foundation hold the trademarks and rights to the Plone branding assets, it can effectively protect these from unfair use. -3. **Guarantee of future Open Source versions** -- The Foundation's contributor agreement ensures that there will **always** be an OSI-approved version of Plone. +1. **Minimizing confusion / maximizing business compatibility** -- Organizations considering adopting Plone have a simple answer for "Who owns this?", rather than a more complicated answer that might scare away the legally-cautious. +2. **Trademark protection** -- By having the Foundation hold the trademarks and rights to the Plone branding assets, it can effectively protect these from unfair use. +3. **Guarantee of future Open Source versions** -- The Foundation's contributor agreement ensures that there will **always** be an OSI-approved version of Plone. + ## Questions and answers @@ -92,7 +94,7 @@ How much would a non-GPL version of Plone cost? > Despite this, though, many large and excellent contributions—such as Archetypes—have been made, and the Foundation hopes that companies will continue to do so. > In any event, a company that purchases a non-GPL license (should such ever become available) is contributing financial resources to our community, which can be used to further develop, market, and protect the GPL version of Plone. -- -- -- +- https://plone.org/foundation/contributors-agreement/agreement.pdf +- https://github.com/collective +- https://github.com/plone - [Policy for Contributor Agreements and patches](https://plone.org/foundation/materials/foundation-resolutions/patch-policy-052011) diff --git a/coredev/documentation.md b/coredev/documentation.md index bbaec73bc..bebf84e09 100644 --- a/coredev/documentation.md +++ b/coredev/documentation.md @@ -16,12 +16,14 @@ For general guidance for contributing documentation, see {doc}`contributing/inde For documentation authors, see {doc}`contributing/authors`. + ## Documentation of Plone -The comprehensive resource for Plone documentation is . +The comprehensive resource for Plone documentation is https://6.docs.plone.org/. The documentation repository is on [GitHub](https://github.com/plone/documentation). Information for how to contribute to documentation can be found at {doc}`contributing/index`. + ## Documenting a package At the very least, your package should include the following forms of documentation. @@ -34,11 +36,12 @@ It should be formatted using [GitHub flavored Markdown](https://github.github.co `README.md` should include: -- A brief description of the package's purpose. -- Installation information (How do I get it working?) -- Compatibility information (what versions of Plone does it work with?) -- Links to other sources of documentation. -- Links to issue trackers, mailing lists, and other ways to get help. +- A brief description of the package's purpose. +- Installation information (How do I get it working?) +- Compatibility information (what versions of Plone does it work with?) +- Links to other sources of documentation. +- Links to issue trackers, mailing lists, and other ways to get help. + ### The manual (narrative documentation) @@ -46,26 +49,27 @@ The manual goes into further depth for people who want to know all about how to It includes topics like: -- What are its features -- How to use them (in English—not doctests!) -- Information about architecture -- Common gotchas +- What are its features +- How to use them (in English—not doctests!) +- Information about architecture +- Common gotchas The manual should consider various audiences who may need different types of information: -- End users who use Plone for content editing, but don't manage the site. -- Site administrators who install and configure the package. -- Integrators who need to extend the functionality of the package in code. -- System administrators who need to maintain the server running the software. +- End users who use Plone for content editing, but don't manage the site. +- Site administrators who install and configure the package. +- Integrators who need to extend the functionality of the package in code. +- System administrators who need to maintain the server running the software. Simple packages with limited functionality can get by with a single page of narrative documentation. In this case, it's simplest to include it in an extended `README.md`. -Some excellent examples of a single-page README are and . +Some excellent examples of a single-page README are https://pypi.org/project/plone.outputfilters/ and https://github.com/plone/plone.app.caching. If your project is moderately complex, you may want to set up your documentation with multiple pages. The preferred way to do this is to add Sphinx to your project, and host your docs on readthedocs.org, so that it rebuilds the documentation whenever you push to GitHub. If you do this, your `README.md` must link off site to the documentation. + ### Reference or API documentation An API reference provides information about the package's public API (that is, the code that the package exposes for use from external code). @@ -73,6 +77,7 @@ It is meant for random access to remind the reader of how a particular class or If the codebase is written with docstrings, API documentation can be automatically generated using Sphinx. + ### Changes or history ```{todo} @@ -100,6 +105,7 @@ See for a fu If a change was related to a bug in the issue tracker, the changelog entry should include a link to that issue. + ### Licenses Information about the open source license used for the package should be placed within the `docs` directory. diff --git a/coredev/getting-started-with-development.md b/coredev/getting-started-with-development.md index 109b4a594..003e6a7f2 100644 --- a/coredev/getting-started-with-development.md +++ b/coredev/getting-started-with-development.md @@ -16,19 +16,22 @@ Needs updating to Plone6, but contains useful info This document assumes you want to run the current latest Plone source, fix a bug in Plone, or test an add-on in the context of the latest code, and will detail the full process. For how to write Plone Improvement Proposals (PLIPs), read {doc}`plips`. + ## Version support policy If you are triaging or fixing bugs, keep in mind that Plone has a [version support policy](https://plone.org/download/release-schedule#91815aec-0513-40e0-a804-55ea787a8c68). + ## Dependencies -- git. See [Set up Git](https://docs.github.com/en/get-started/quickstart/set-up-git). -- [Python](https://python.org/). See the [current supported versions of Python](https://plone.org/download/release-schedule). -- If you are on macOS, you will need to install [XCode](https://developer.apple.com/xcode/). +- git. See [Set up Git](https://docs.github.com/en/get-started/quickstart/set-up-git). +- [Python](https://python.org/). See the [current supported versions of Python](https://plone.org/download/release-schedule). +- If you are on macOS, you will need to install [XCode](https://developer.apple.com/xcode/). You can do this through the App Store or registering through the Apple Developer Program. -- [Pillow](https://pypi.org/project/Pillow/). -- [GCC](https://gcc.gnu.org/) in order to compile ZODB, Zope and lxml. -- [libxml2 and libxslt](https://gitlab.gnome.org/GNOME/libxslt/-/releases), including development headers. +- [Pillow](https://pypi.org/project/Pillow/). +- [GCC](https://gcc.gnu.org/) in order to compile ZODB, Zope and lxml. +- [libxml2 and libxslt](https://gitlab.gnome.org/GNOME/libxslt/-/releases), including development headers. + (setup-development-environment)= @@ -67,8 +70,9 @@ or as a WSGI service with: To login, the defaults are: -- username: admin -- password: admin +- username: admin +- password: admin + ## Switching branches @@ -98,6 +102,7 @@ The line with a `*` by it will indicate the branch on which you are currently wo Make sure to rerun buildout if you were in a different branch earlier to get the correct versions of packages, otherwise you will get some weird behavior. ``` + ## Jenkins and mr.roboto Plone has a continuous integration (CI) setup and follows CI rules. @@ -112,32 +117,33 @@ Build breakages are a normal and expected part of the development process. Our aim is to find errors and eliminate them as quickly as possible, without expecting perfection and zero errors. Though, there are some essential practices that need to be followed in order to achieve a stable build: -1. Don't check in on a broken build. Check Jenkins first. -2. Always run all commit tests locally before committing. -3. Wait for commit tests to pass before moving on. -4. Never go home on a broken build. -5. Always be prepared to revert to the previous revision. -6. Time-box fixing before reverting. -7. Don't comment out failing tests. -8. Take responsibility for all breakages that result from your changes. +1. Don't check in on a broken build. Check Jenkins first. +2. Always run all commit tests locally before committing. +3. Wait for commit tests to pass before moving on. +4. Never go home on a broken build. +5. Always be prepared to revert to the previous revision. +6. Time-box fixing before reverting. +7. Don't comment out failing tests. +8. Take responsibility for all breakages that result from your changes. See {doc}`continous-integration` for more information. Since it can be burdensome to check this manually, install the tools locally to always see the current state of the Plone CI Server: -- For Linux and X11 environments, there is [BuildNotify](https://pypi.org/project/BuildNotify/). -- For macOS there is [CCMenu](http://ccmenu.org/). -- For windows there is [CCTray](https://cruisecontrolnet.org/cctray_download_plugin-2/). -- For Firefox there is [CruiseControl Monitor](https://addons.thunderbird.net/EN-US/firefox/addon/cruisecontrol-monitor/?src=cb-dl-name) (no longer supported), and many other [Jenkins plugins](https://addons.mozilla.org/en-US/firefox/search/?q=jenkins). +- For Linux and X11 environments, there is [BuildNotify](https://pypi.org/project/BuildNotify/). +- For macOS there is [CCMenu](http://ccmenu.org/). +- For windows there is [CCTray](https://cruisecontrolnet.org/cctray_download_plugin-2/). +- For Firefox there is [CruiseControl Monitor](https://addons.thunderbird.net/EN-US/firefox/addon/cruisecontrol-monitor/?src=cb-dl-name) (no longer supported), and many other [Jenkins plugins](https://addons.mozilla.org/en-US/firefox/search/?q=jenkins). These tools were built to parse a specific file that CruiseControl, another CI tool, generated. Jenkins generates this file too. You can configure your notifier of choice with this url: `https://jenkins.plone.org/cc.xml` [which is a 404, LOL!] + ## Check out packages to fix Most packages are not in {file}`src/` by default, so you can use `mr.developer` to get the latest and make sure you are always up to date. -It can be a little daunting at first to find out which packages cause the bug in question, but just ask in if you need some help. +It can be a little daunting at first to find out which packages cause the bug in question, but just ask in https://community.plone.org/ if you need some help. Once you know which packages you want, pull their source. You can get the source of the package with `mr.developer` and the checkout command, or you can go directly to editing {file}`checkouts.cfg`. @@ -175,6 +181,7 @@ In both methods, `mr.developer` will download the source from GitHub (or otherwi You can repeat this process with as many or as few packages as you need. For some more tips on working with `mr.developer`, please read {doc}`mrdeveloper`. + ## Testing Locally To run a test for the specific module you modify: @@ -200,6 +207,7 @@ you may just let jenkins do this part for you. More on that below. ``` + ## Updating `CHANGES.rst` and `checkouts.cfg` Once all the tests are running locally on your machine, you are **ALMOST** ready to commit the changes. @@ -224,30 +232,32 @@ Not that you would ever skip running all tests. If your bug is in more than one release, for example 5.2 and 6.0, please checkout both branches, and add it to the file {file}`checkouts.cfg`. + ## Commits and pull requests Review the following checklist: -- Did you fix the original bug? -- Is your code consistent with our [Style Guides](https://5.docs.plone.org/develop/styleguide/index.html)? -- Did you remove any extra code and lingering pdbs? -- Did you write a test case for that bug? -- DO all test cases for the modules and Plone pass? -- Did you update {file}`CHANGES.rst` in each packages you touched? -- Did you add your changed packages to {file}`checkouts.cfg`? +- Did you fix the original bug? +- Is your code consistent with our [Style Guides](https://5.docs.plone.org/develop/styleguide/index.html)? +- Did you remove any extra code and lingering pdbs? +- Did you write a test case for that bug? +- DO all test cases for the modules and Plone pass? +- Did you update {file}`CHANGES.rst` in each packages you touched? +- Did you add your changed packages to {file}`checkouts.cfg`? If you answered *YES* to all of these questions, then you are ready to push your changes! A couple quick reminders: -- Only commit directly to the development branch if you're confident that your code won't break anything badly and the changes are small and fairly trivial. +- Only commit directly to the development branch if you're confident that your code won't break anything badly and the changes are small and fairly trivial. Otherwise, please create a `pull request` (more on that below). -- Please try to make one change per commit. +- Please try to make one change per commit. If you are fixing three bugs, make three commits. That way, it is easier to see what was done when, and easier to roll back any changes if necessary. If you want to make large changes cleaning up whitespace or renaming variables, it is especially important to do so in a separate commit for this reason. -- We have a few angels that follow the changes and each commit to see what happens to their favourite CMS! +- We have a few angels that follow the changes and each commit to see what happens to their favourite CMS! If you commit something REALLY sketchy, they will politely contact you, most likely after immediately reverting changes. - There are no official people assigned to this so if you are especially nervous, ask in . + There are no official people assigned to this so if you are especially nervous, ask in https://community.plone.org/. + ## Commit to `Products.CMFPlone` @@ -309,7 +319,7 @@ git checkout 4.2 git merge my-awesome-feature-4.2 ``` -### Branches and forks and direct commits - oh my +### Branches and forks and direct commits - oh my! ```{note} This section needs a rewrite. @@ -324,10 +334,10 @@ For Plone, this would be the version branch, whereas for most other packages thi HOWEVER, there are a few situations where a branch is appropriate. If you: -- are just getting started -- are not sure about your changes -- want feedback or code review -- are implementing a non-trivial change +- are just getting started +- are not sure about your changes +- want feedback or code review +- are implementing a non-trivial change then you should create a branch of whatever packages you are using, and then use the [pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) feature of GitHub to get review. Everything about this process would be the same except you need to work on a branch. @@ -359,12 +369,13 @@ This will turn your request into a pull request on the main branch. There are people who look once a week or more for pending pull requests and will confirm whether or not it's a good fix, and give you feedback where necessary. The reviewers are informal and very nice, so don't worry. They are there to help! -If you want immediate feedback, visit with the pull request link and ask for a review. +If you want immediate feedback, visit https://community.plone.org/ with the pull request link and ask for a review. ```{note} You still need to update the file {file}`checkouts.cfg` in the correct branches of `buildout.coredev`! ``` + ## Finalize issues If you are working from an issue, please don't forget to go back to the issue, and add a link to the change set. @@ -372,6 +383,7 @@ We don't have integration with GitHub yet so it's a nice way to track changes. It also lets the reporter know that you care. If the bug is really bad, consider pinging the release manager and asking them to make a release. + ## FAQ How do I know when my package got made? diff --git a/coredev/git.md b/coredev/git.md index 992de6aa6..10696f8d3 100644 --- a/coredev/git.md +++ b/coredev/git.md @@ -17,17 +17,19 @@ All this can go, it's redundant Our repository on GitHub has the following layout: -- **feature branches**: +- **feature branches**: All development for new features must be done in dedicated branches, normally one branch per feature. -- **main** or **master** **branch**: +- **main** or **master** **branch**: when features get completed they are merged into the master branch; bugfixes are commited directly on the master branch, -- **tags**: +- **tags**: whenever we create a new release, we tag the repository so we can later retrace our steps, or rerelease versions. + ## Git basics Some introductory definitions and concepts, if you are already familiar enough with Git, head to next section: {ref}`general-guidelines-label`. + ### Mental working model With Git (as well as all modern [DVCS](http://en.wikipedia.org/wiki/Distributed_revision_control)), distributing changes to others is a two steps process (contrary to traditional VCS like `svn`). @@ -44,6 +46,7 @@ You can freely fix/change/remove/rework/update/... your commits afterwards. Push your changes whenever you are sure they are what you, and others, expect them to be. + ### Concepts In Git there are: diff --git a/coredev/guidelines.md b/coredev/guidelines.md index a931c3eb1..331c25e34 100644 --- a/coredev/guidelines.md +++ b/coredev/guidelines.md @@ -23,34 +23,35 @@ Let's bring you up to speed with the minimum you need to know to start contribut ## Create an issue -- If you know the issue is for a specific package, you can add an issue there. +- If you know the issue is for a specific package, you can add an issue there. When in doubt, create one in the [CMFPlone issue tracker](https://github.com/plone/Products.CMFPlone/issues). -- Please specify a few things: +- Please specify a few things: - - What steps reproduce the problem? - - What do you expect when you do that? - - What happens instead? - - Which Plone version are you using? + - What steps reproduce the problem? + - What do you expect when you do that? + - What happens instead? + - Which Plone version are you using? -- If it is a visual issue, can you add a screen shot? +- If it is a visual issue, can you add a screen shot? -- If there is an error in the Site Setup error log, please include it. +- If there is an error in the Site Setup error log, please include it. Especially a traceback is helpful. Click on the 'Display traceback as text' link if you see it in the error log. + ## Create a pull request -- Legally, you can NOT contribute code unless you have signed the {doc}`contributor agreement `. +- Legally, you can NOT contribute code unless you have signed the {doc}`contributor agreement `. This means that we can NOT accept pull requests from you unless this is done, so please don't put the code reviewers at risk and do it anyways. -- Add a changelog entry as file in the news directory. +- Add a changelog entry as file in the news directory. For helpful instructions, please see: -- For new features, an addition to README.rst is probably needed. +- For new features, an addition to README.rst is probably needed. A package may include other documentation that needs updating. -- All text that can be shown in a browser must be translatable. +- All text that can be shown in a browser must be translatable. Please mark all such strings as translatable. -- Be nice and use code quality checkers like flake8 and jshint. -- See if you can use git to squash multiple commits into one where this makes sense. +- Be nice and use code quality checkers like flake8 and jshint. +- See if you can use git to squash multiple commits into one where this makes sense. If you are not comfortable with git, never mind. -- If after reading this you become hesitant: don't worry. +- If after reading this you become hesitant: don't worry. You can always create a pull request, mark it as WIP (work in progress), and improve the above points later. diff --git a/coredev/index.md b/coredev/index.md index 38bf4fc7b..41192a357 100644 --- a/coredev/index.md +++ b/coredev/index.md @@ -16,6 +16,7 @@ Most of this can go This part describes the process of development in Plone. It is primarily a technical resource for setting up your development environment, fixing bugs, and writing Plone Improvement Proposals (PLIPs). + ## Plone Contributor Agreement You must sign the [Plone Contributor Agreement](https://plone.org/foundation/contributors-agreement). @@ -23,6 +24,7 @@ You must sign the [Plone Contributor Agreement](https://plone.org/foundation/con We can **NOT** accept pull requests from you until you have signed and returned the Contributor Agreement, and been approved. Please don't put the code reviewers at risk by ignoring this requirement. + ## Contents ```{toctree} @@ -40,6 +42,7 @@ git package-dependencies ``` + ## Additional material These are some documents used as reference for this documentation. @@ -61,4 +64,4 @@ The style guides are ancient and need to be overhauled. Documenation's style is guided by Vale and the Microsoft Style Guide. See [Contributing to Documentation](https://6.docs.plone.org/contributing/index.html). -Our coding style guides are located at the [Plone Style Guide]( section. +Our coding style guides are located at the [Plone Style Guide](https://5.docs.plone.org/develop/styleguide/index.html section. diff --git a/coredev/mrdeveloper.md b/coredev/mrdeveloper.md index f1a280f21..f0480b0c1 100644 --- a/coredev/mrdeveloper.md +++ b/coredev/mrdeveloper.md @@ -14,7 +14,7 @@ Review, but keep # `mr.developer` This buildout uses `mr.developer` to manage package development. -See for more information, or run `bin/develop help` for a list of available commands. +See https://pypi.org/project/mr.developer/ for more information, or run `bin/develop help` for a list of available commands. The most common workflow to get all the latest updates is: diff --git a/coredev/packages-dependencies.md b/coredev/packages-dependencies.md index 2f8ba1145..8f95a4f70 100644 --- a/coredev/packages-dependencies.md +++ b/coredev/packages-dependencies.md @@ -15,20 +15,22 @@ Needs grammar/style check, and re-do the ASCII art as Mermaid diagram for added This chapter describes the architecture of Plone's packages and dependencies. + ## Motivation In the past, lots of indirections were introduced in Plone's packages and dependecies. Our goal in the long run is to untangle them and get a direct dependency graph. This document shows the current state as an orientation. + ## Overview There are multiple level of dependencies: -- package level (`setup.py`/`setup.cfg`/`pyproject.toml`) -- Python level (imports) -- ZCML level (includes) -- testing (need for layers, such as functional testing) +- package level (`setup.py`/`setup.cfg`/`pyproject.toml`) +- Python level (imports) +- ZCML level (includes) +- testing (need for layers, such as functional testing) We do not have any circular dependencies at the package level anymore. This was solved already. @@ -36,6 +38,7 @@ This was solved already. Nevertheless we have indirection on all other levels. Since Plone consists of a lot of packages, it is complex to untangle those. + ## Mental model A base mental model for how Plone is organized in Plone 6 since alpha 4 is shown in the following diagram: @@ -97,8 +100,9 @@ A base mental model for how Plone is organized in Plone 6 since alpha 4 is shown As a rough model we have two packages as dividing lines: -1. `Products.CMFPlone` -2. `plone.base` +1. `Products.CMFPlone` +2. `plone.base` + ## Packages in detail @@ -106,256 +110,263 @@ If we look deeper into those, we have more sub-dividers, but first group all int Then, based on the 6.0.0.a4 release, these are the packages: + ### Above `Products.CMFPlone` -- Plone -- plone.api -- plone.app.iterate -- plone.app.upgrade -- plone.restapi -- plone.volto -- Products.CMFPlacefulWorkflow +- Plone +- plone.api +- plone.app.iterate +- plone.app.upgrade +- plone.restapi +- plone.volto +- Products.CMFPlacefulWorkflow + ### Between `Products.CMFPlone` and `plone.base` -- collective.monkeypatcher -- plone.app.caching -- plone.app.content -- plone.app.contentlisting -- plone.app.contentmenu -- plone.app.contentrules -- plone.app.contenttypes -- plone.app.customerize -- plone.app.dexterity -- plone.app.discussion -- plone.app.event -- plone.app.i18n -- plone.app.intid -- plone.app.layout -- plone.app.linkintegrity -- plone.app.locales -- plone.app.lockingbehavior -- plone.app.multilingual -- plone.app.portlets -- plone.app.querystring -- plone.app.redirector -- plone.app.registry -- plone.app.relationfield -- plone.app.textfield -- plone.app.theming -- plone.app.users -- plone.app.uuid -- plone.app.versioningbehavior -- plone.app.viewletmanager -- plone.app.vocabularies -- plone.app.widgets -- plone.app.workflow -- plone.app.z3cform -- plone.browserlayer -- plone.cachepurging -- plone.contentrules -- plone.formwidget.namedfile -- plone.formwidget.recurrence -- plone.i18n -- plone.namedfile -- plone.outputfilters -- plone.portlet.collection -- plone.portlet.static -- plone.portlets -- plone.protect -- plone.resourceeditor -- plone.rfc822 -- plone.schemaeditor -- plone.session -- plone.staticresources -- plone.stringinterp -- plone.theme -- plonetheme.barceloneta -- Products.isurlinportal +- collective.monkeypatcher +- plone.app.caching +- plone.app.content +- plone.app.contentlisting +- plone.app.contentmenu +- plone.app.contentrules +- plone.app.contenttypes +- plone.app.customerize +- plone.app.dexterity +- plone.app.discussion +- plone.app.event +- plone.app.i18n +- plone.app.intid +- plone.app.layout +- plone.app.linkintegrity +- plone.app.locales +- plone.app.lockingbehavior +- plone.app.multilingual +- plone.app.portlets +- plone.app.querystring +- plone.app.redirector +- plone.app.registry +- plone.app.relationfield +- plone.app.textfield +- plone.app.theming +- plone.app.users +- plone.app.uuid +- plone.app.versioningbehavior +- plone.app.viewletmanager +- plone.app.vocabularies +- plone.app.widgets +- plone.app.workflow +- plone.app.z3cform +- plone.browserlayer +- plone.cachepurging +- plone.contentrules +- plone.formwidget.namedfile +- plone.formwidget.recurrence +- plone.i18n +- plone.namedfile +- plone.outputfilters +- plone.portlet.collection +- plone.portlet.static +- plone.portlets +- plone.protect +- plone.resourceeditor +- plone.rfc822 +- plone.schemaeditor +- plone.session +- plone.staticresources +- plone.stringinterp +- plone.theme +- plonetheme.barceloneta +- Products.isurlinportal + ### The foundation below `plone.base` + #### Plone world -- borg.localrole -- plone.alterego -- plone.autoform -- plone.autoinclude -- plone.batching -- plone.behavior -- plone.caching -- plone.dexterity -- plone.event -- plone.folder -- plone.indexer -- plone.intelligenttext -- plone.keyring -- plone.locking -- plone.memoize -- plone.registry -- plone.resource -- plone.rest -- plone.scale -- plone.schema -- plone.subrequest -- plone.supermodel -- plone.transformchain -- plone.uuid -- plone.z3cform -- Products.DateRecurringIndex -- Products.ExtendedPathIndex -- Products.MimetypesRegistry -- Products.PlonePAS -- Products.PortalTransforms -- Products.statusmessages +- borg.localrole +- plone.alterego +- plone.autoform +- plone.autoinclude +- plone.batching +- plone.behavior +- plone.caching +- plone.dexterity +- plone.event +- plone.folder +- plone.indexer +- plone.intelligenttext +- plone.keyring +- plone.locking +- plone.memoize +- plone.registry +- plone.resource +- plone.rest +- plone.scale +- plone.schema +- plone.subrequest +- plone.supermodel +- plone.transformchain +- plone.uuid +- plone.z3cform +- Products.DateRecurringIndex +- Products.ExtendedPathIndex +- Products.MimetypesRegistry +- Products.PlonePAS +- Products.PortalTransforms +- Products.statusmessages + #### Zope ecosystem -- Chameleon -- diazo -- five.customerize -- five.intid -- five.localsitemanager -- icalendar -- Products.CMFCore -- Products.CMFDiffTool -- Products.CMFDynamicViewFTI -- Products.CMFEditions -- Products.CMFUid -- Products.DCWorkflow -- Products.ExternalMethod -- Products.GenericSetup -- Products.MailHost -- Products.PluggableAuthService -- Products.PluginRegistry -- Products.PythonScripts -- Products.Sessions -- Products.SiteErrorLog -- Products.StandardCacheManagers -- Products.ZopeVersionControl -- repoze.xmliter -- webresource -- z3c.caching -- z3c.form -- z3c.formwidget.query -- z3c.objpath -- z3c.pt -- z3c.relationfield -- z3c.zcmlhook -- zc.recipe.egg -- zc.relation -- zodbverify -- zope.copy -- zope.intid -- zope.keyreference +- Chameleon +- diazo +- five.customerize +- five.intid +- five.localsitemanager +- icalendar +- Products.CMFCore +- Products.CMFDiffTool +- Products.CMFDynamicViewFTI +- Products.CMFEditions +- Products.CMFUid +- Products.DCWorkflow +- Products.ExternalMethod +- Products.GenericSetup +- Products.MailHost +- Products.PluggableAuthService +- Products.PluginRegistry +- Products.PythonScripts +- Products.Sessions +- Products.SiteErrorLog +- Products.StandardCacheManagers +- Products.ZopeVersionControl +- repoze.xmliter +- webresource +- z3c.caching +- z3c.form +- z3c.formwidget.query +- z3c.objpath +- z3c.pt +- z3c.relationfield +- z3c.zcmlhook +- zc.recipe.egg +- zc.relation +- zodbverify +- zope.copy +- zope.intid +- zope.keyreference + #### Zope core -- AccessControl -- Acquisition -- AuthEncoding -- beautifulsoup4 -- BTrees -- DateTime -- DocumentTemplate -- ExtensionClass -- Missing -- MultiMapping -- Persistence -- persistent -- Products.BTreeFolder2 -- Products.ZCatalog -- Record -- RestrictedPython -- transaction -- zc.lockfile -- ZConfig -- zdaemon -- ZEO -- zExceptions -- ZODB -- ZODB3 -- zodbpickle -- Zope -- zope.annotation -- zope.app.locales -- zope.browser -- zope.browsermenu -- zope.browserpage -- zope.browserresource -- zope.cachedescriptors -- zope.component -- zope.componentvocabulary -- zope.configuration -- zope.container -- zope.contentprovider -- zope.contenttype -- zope.datetime -- zope.deferredimport -- zope.deprecation -- zope.dottedname -- zope.event -- zope.exceptions -- zope.filerepresentation -- zope.globalrequest -- zope.hookable -- zope.i18n -- zope.i18nmessageid -- zope.interface -- zope.lifecycleevent -- zope.location -- zope.pagetemplate -- zope.processlifetime -- zope.proxy -- zope.ptresource -- zope.publisher -- zope.ramcache -- zope.schema -- zope.security -- zope.sendmail -- zope.sequencesort -- zope.site -- zope.size -- zope.structuredtext -- zope.tal -- zope.tales -- zope.testbrowser -- zope.testing -- zope.traversing -- zope.viewlet -- Zope2 +- AccessControl +- Acquisition +- AuthEncoding +- beautifulsoup4 +- BTrees +- DateTime +- DocumentTemplate +- ExtensionClass +- Missing +- MultiMapping +- Persistence +- persistent +- Products.BTreeFolder2 +- Products.ZCatalog +- Record +- RestrictedPython +- transaction +- zc.lockfile +- ZConfig +- zdaemon +- ZEO +- zExceptions +- ZODB +- ZODB3 +- zodbpickle +- Zope +- zope.annotation +- zope.app.locales +- zope.browser +- zope.browsermenu +- zope.browserpage +- zope.browserresource +- zope.cachedescriptors +- zope.component +- zope.componentvocabulary +- zope.configuration +- zope.container +- zope.contentprovider +- zope.contenttype +- zope.datetime +- zope.deferredimport +- zope.deprecation +- zope.dottedname +- zope.event +- zope.exceptions +- zope.filerepresentation +- zope.globalrequest +- zope.hookable +- zope.i18n +- zope.i18nmessageid +- zope.interface +- zope.lifecycleevent +- zope.location +- zope.pagetemplate +- zope.processlifetime +- zope.proxy +- zope.ptresource +- zope.publisher +- zope.ramcache +- zope.schema +- zope.security +- zope.sendmail +- zope.sequencesort +- zope.site +- zope.size +- zope.structuredtext +- zope.tal +- zope.tales +- zope.testbrowser +- zope.testing +- zope.traversing +- zope.viewlet +- Zope2 + #### Libraries -- attrs -- cffi -- cssselect -- decorator -- docutils -- feedparser -- future -- importlib_metadata -- jsonschema -- Markdown -- multipart -- Paste -- PasteDeploy -- piexif -- Pillow -- pycparser -- PyJWT -- pyrsistent -- python_dotenv -- python_gettext -- requests -- roman -- sgmllib3k -- simplejson -- soupsieve -- Unidecode -- urllib3 -- waitress -- WebOb -- WebTest -- WSGIProxy2 -- zipp +- attrs +- cffi +- cssselect +- decorator +- docutils +- feedparser +- future +- importlib_metadata +- jsonschema +- Markdown +- multipart +- Paste +- PasteDeploy +- piexif +- Pillow +- pycparser +- PyJWT +- pyrsistent +- python_dotenv +- python_gettext +- requests +- roman +- sgmllib3k +- simplejson +- soupsieve +- Unidecode +- urllib3 +- waitress +- WebOb +- WebTest +- WSGIProxy2 +- zipp diff --git a/coredev/plip-review.md b/coredev/plip-review.md index 074a182fa..267b55902 100644 --- a/coredev/plip-review.md +++ b/coredev/plip-review.md @@ -15,6 +15,7 @@ Combine with PLIP page, remove obsolete technologies, go over language A Plone Improvement Proposal (PLIP) is a formal process to propose a change to improve Plone. + ## Expectations A good PLIP review takes about four hours. @@ -22,6 +23,7 @@ Please plan accordingly. When you are done, if you have access to core, commit the review to the `plips` folder, and reference the PLIP in your commit message. If you do not have access, attach your review to the PLIP ticket itself. + ## Setting up the environment Follow the instructions in {doc}`getting-started-with-development`. @@ -32,43 +34,48 @@ Instead of running the buildout with the default buildout file, you will run the ./bin/buildout -c plips/plipXXXX.cfg ``` + ## Functionality review This section describes the topics that may be addressed in a PLIP review, depending on the nature of the PLIP itself. + ### General -- Does the PLIP actually do what the implementers proposed? +- Does the PLIP actually do what the implementers proposed? Are there incomplete variations? -- Were there any errors running buildout? +- Were there any errors running buildout? Did the migration(s) work? -- Do error and status messages make sense? +- Do error and status messages make sense? Are they properly internationalized? -- Are there any performance considerations? +- Are there any performance considerations? Has the implementer addressed them, if so? + ### Bugs -- Are there any bugs? +- Are there any bugs? Nothing is too big nor small. -- Do fields handle wacky data? +- Do fields handle wacky data? How about strings in date fields, or nulls in required? -- Is validation up to snuff and sensical? +- Is validation up to snuff and sensical? Is it too restrictive or not restrictive enough? + ### Usability Issues -- Is the implementation usable? -- How will novice end users respond to the change? -- Does this PLIP need a usability review? +- Is the implementation usable? +- How will novice end users respond to the change? +- Does this PLIP need a usability review? If you think this PLIP needs a usability review, change the state to "please review" and add a note in the comments. -- Is the PLIP consistent with the rest of Plone? +- Is the PLIP consistent with the rest of Plone? For example, if there is control panel configuration, does the new form fit in with the rest of the panels? -- Does everything flow nicely for novice and advanced users? +- Does everything flow nicely for novice and advanced users? Is there any workflow that feels odd? -- Are there any new permissions and do they work properly? +- Are there any new permissions and do they work properly? Does their role assignment make sense? + ### Documentation Issues - Is the corresponding documentation for the end user, be it developer or Plone user, sufficient? @@ -80,20 +87,23 @@ This way the implementer can find help if they need it. Also set a priority for the ticket. The PLIP will not be merged until all blockers and critical bugs are fixed. + ### Code Review + #### Python -- Is this code maintainable? -- Is the code properly documented? -- Does the code adhere to PEP8 standards (more or less)? -- Are they importing deprecated modules? +- Is this code maintainable? +- Is the code properly documented? +- Does the code adhere to PEP8 standards (more or less)? +- Are they importing deprecated modules? + #### JavaScript -- Does the JavaScript meet our set of JavaScript standards? +- Does the JavaScript meet our set of JavaScript standards? See our section about [JavaScript](https://5.docs.plone.org/develop/addons/javascript/index.html) and the [JavaScript Style Guide](https://5.docs.plone.org/develop/styleguide/javascript.html). -- Does the JavaScript work in all currently supported browsers? +- Does the JavaScript work in all currently supported browsers? Is it performant? ```{todo} @@ -103,7 +113,7 @@ See https://github.com/plone/documentation/issues/1330 #### ME/TAL -- Does the PLIP use views appropriately, avoiding too much logic? -- Is there any code in a loop that could potentially be a performance issue? -- Are there any deprecated or old style ME/TAL lines of code, such as using `DateTime`? -- Is the rendered HTML compliant with standards? Are IDs and classes used appropriately? +- Does the PLIP use views appropriately, avoiding too much logic? +- Is there any code in a loop that could potentially be a performance issue? +- Are there any deprecated or old style ME/TAL lines of code, such as using `DateTime`? +- Is the rendered HTML compliant with standards? Are IDs and classes used appropriately? diff --git a/coredev/plips.md b/coredev/plips.md index 5de254d16..90b071eac 100644 --- a/coredev/plips.md +++ b/coredev/plips.md @@ -18,10 +18,12 @@ It is a change to a Plone package that would affect everyone. PLIPs go through a different process than bug fixes because of their broad reaching effect. The Plone Framework Team reviews all PLIPs to be sure that it's in the best interest of the broader community to be implemented and that it is of high quality. + ## Frequently asked questions about PLIPs This section provides detailed answers to common questions about PLIPs. + ### PLIP or bugfix? In general, anything that changes the API of Plone in the backend or the user interface (UI) on the front end should be filed as a PLIP. @@ -30,6 +32,7 @@ The Framework Team is eager to reduce its own workload and will reclassify it fo If the change you are proposing is not in the scope of a PLIP, a GitHub pull request or issue is the right format. The key point here is that each change must be documented, allowing it to be tracked and understood. + ### Who can submit PLIPs? Anyone who has signed a Plone Contributor Agreement can work on a PLIP. @@ -47,6 +50,7 @@ If you have ideas on new interactions or UI your ideas are more than welcome. We will help you pair up with implementers if needed. + ### What is a PLIP champion? When you submit your PLIP and it is approved, a Framework Team member who is especially excited about seeing the PLIP completed will be assigned to your PLIP as a champion. @@ -55,14 +59,15 @@ They are there to push you through completion, as well as answer any questions a A champion fulfill the following tasks. -- Answer any questions the PLIP implementor has, technical or otherwise. -- Encourage the PLIP author by constantly giving feedback and encouragement. -- Keep the implementer aware of timelines, and push to get things done on time. -- Assist with finding additional help when needed to complete the implementation in a timely matter. +- Answer any questions the PLIP implementor has, technical or otherwise. +- Encourage the PLIP author by constantly giving feedback and encouragement. +- Keep the implementer aware of timelines, and push to get things done on time. +- Assist with finding additional help when needed to complete the implementation in a timely matter. Keep in mind that champions are in passive mode by default. If you need help or guidance, please reach out to them as soon as possible to activate help mode. + ### Can I get involved in other ways? If you want to experience the process and how it works, help us review PLIPs as the implementations finish up. @@ -76,6 +81,7 @@ Then, follow the instructions for {doc}`reviewing a PLIP `. Thank you in advance! + ### When can I submit a PLIP? Today, tomorrow, any time! @@ -84,6 +90,7 @@ After the PLIP is accepted, the Framework Team will try to judge complexity and You can begin work immediately, and we encourage submitting fast and furious. + ### When is the PLIP due? **Summary: As soon as you get it done.** @@ -95,27 +102,30 @@ In general, we don't want to track a PLIP for more than a year. If your PLIP is accepted and we haven't seen activity in over a year, we will probably ask you to restart the whole process. + ### What happens if your PLIP is not accepted? If a PLIP isn't accepted in core, it doesn't mean it's a bad idea. It is often the case that there are competing implementations, and we want to see it vetted as an add-on before "blessing" a preferred implementation. + ## Process Overview -1. Submit a PLIP at any time. -2. PLIP is approved for inclusion into core for a given release. -3. Developer implements PLIP (code, tests, documentation). -4. PLIP is submitted for review by developer. -5. Framework Team reviews the PLIP and gives feedback. -6. Developer addresses concerns in feedback and re-submits the PLIP, if necessary. -7. This may go back and forth a few times, until both the Framework Team and developer are happy with the result. -8. PLIP is approved for merge. +1. Submit a PLIP at any time. +2. PLIP is approved for inclusion into core for a given release. +3. Developer implements PLIP (code, tests, documentation). +4. PLIP is submitted for review by developer. +5. Framework Team reviews the PLIP and gives feedback. +6. Developer addresses concerns in feedback and re-submits the PLIP, if necessary. +7. This may go back and forth a few times, until both the Framework Team and developer are happy with the result. +8. PLIP is approved for merge. In rare circumstances, a PLIP will be rejected. This is usually the result of the developer not responding to feedback or dropping out of the process. Hang in there! -9. After all other PLIPs are merged, a release is cut. +9. After all other PLIPs are merged, a release is cut. Standby for bugs! + (how-to-submit-a-plip)= ## How to submit a PLIP @@ -145,15 +155,16 @@ Others may be able to point out risks or even offer up better or existing soluti Please note a few things: -- It is very rare that the "Risks" section will be empty or none. -- If you find this is the case, and your PLIP is anything more than trivial, maybe some more vetting should be done. -- The seconder field is REQUIRED. +- It is very rare that the "Risks" section will be empty or none. +- If you find this is the case, and your PLIP is anything more than trivial, maybe some more vetting should be done. +- The seconder field is REQUIRED. We will send the PLIP back to you if it is not filled in. Currently, this is just someone else who thinks your PLIP is a good idea, a +1. In the near future, we will start asking that the seconder is either a coding partner, or someone who is willing and able to finish the PLIP should something happen to the implementer. + ### Evaluating PLIPs After you submit your PLIP, the Framework Team will meet within a couple weeks, and let you know if the PLIP is accepted. @@ -166,38 +177,41 @@ Please keep your eyes and inbox open for changes. These are the criteria by which the framework team will review your work: -- What is size and status of the work needed to be done? -- Is it already an add-on and well established? -- Is this idea well baked and expressed clearly? -- Does the work proposed belong in Plone now, or in the future? -- Is this PLIP more appropriate as a qualified add-on? -- Is this PLIP too risky? +- What is size and status of the work needed to be done? +- Is it already an add-on and well established? +- Is this idea well baked and expressed clearly? +- Does the work proposed belong in Plone now, or in the future? +- Is this PLIP more appropriate as a qualified add-on? +- Is this PLIP too risky? See the {doc}`plip-review` page for more information. + ## Implementing your PLIP You can start the development at any time, but if you are going to modify Plone itself, it is a good idea to wait to see if your idea is approved. + ### General Rules -- Any new packages must be in a branch in the `plone` namespace in GitHub. +- Any new packages must be in a branch in the `plone` namespace in GitHub. You don't have to develop there, but it must be there when submitted. We recommend using branches off of the repositories under the Plone GitHub organization, and will detail that below. -- Most importantly, the PLIP reviewers must be able run buildout and everything should "just work"™. -- Any new code must: +- Most importantly, the PLIP reviewers must be able run buildout and everything should "just work"™. +- Any new code must: - - Be {doc}`properly documented `. - - Have clear code. - - [Follow our style guides](https://5.docs.plone.org/develop/styleguide/index.html). + - Be {doc}`properly documented `. + - Have clear code. + - [Follow our style guides](https://5.docs.plone.org/develop/styleguide/index.html). For convenience and better code quality use Python, JavaScript, and other code linting plugins in your editor. - - [Be tested](https://5.docs.plone.org/develop/testing/index.html). + - [Be tested](https://5.docs.plone.org/develop/testing/index.html). ```{todo} Update links from Plone 5 to Plone 6 Documentation, once content is migrated. See https://github.com/plone/documentation/issues/1330 and other issues. ``` + ### Creating a new PLIP branch Create a buildout configuration file for your PLIP in the `plips` folder. @@ -232,6 +246,7 @@ zcml += Use the same naming convention when you branch existing packages. You should always branch packages when working on PLIPs. + ### Working on a PLIP To work on a PLIP, you bootstrap buildout, and then invoke buildout with your PLIP configuration: @@ -258,15 +273,16 @@ installed = .installed.cfg var = ./var ``` + ### Finishing up Before marking your PLIP as ready for review, please add a file to give a set of instructions to the PLIP reviewer. This file should be called {file}`plip__notes.txt`. This should include, but is not limited to: -- URLs pointing to all documentation created and updated -- Any concerns and issues still remaining -- Any weird buildout things +- URLs pointing to all documentation created and updated +- Any concerns and issues still remaining +- Any weird buildout things Once you have finished, update your PLIP issue to indicate that it is ready for review. The Framework Team will assign 2-3 people to review your PLIP. diff --git a/coredev/release.md b/coredev/release.md index 674bd5b2a..3d4ff8ac8 100644 --- a/coredev/release.md +++ b/coredev/release.md @@ -15,6 +15,7 @@ Can stay, as it needs a place to live. Check in with Release Managers to update This chapter describes the process to release Plone and its packages. + ## Release process for Plone packages To keep the Plone software stack maintainable, the Python egg release process must be automated to a high degree. @@ -29,20 +30,21 @@ This command includes the following requirements. All files mentioned in this list may be written in Markdown or reStructuredText and have the appropriate file name suffix. ``` -- All releases must be hosted on PyPI. -- All versions must be tagged in version control. -- Each package must have a {file}`README` file with links to the version control repository and issue tracker. -- {file}`CHANGES` ({file}`docs/HISTORY`) must be always up-to-date and must contain list of functional changes which may affect package users. -- {file}`CHANGES` must contain release dates. -- {file}`README` and {file}`CHANGES` must be visible on PyPI. -- Released eggs must contain generated gettext `.mo` files, but these files must not be committed to the repository. +- All releases must be hosted on PyPI. +- All versions must be tagged in version control. +- Each package must have a {file}`README` file with links to the version control repository and issue tracker. +- {file}`CHANGES` ({file}`docs/HISTORY`) must be always up-to-date and must contain list of functional changes which may affect package users. +- {file}`CHANGES` must contain release dates. +- {file}`README` and {file}`CHANGES` must be visible on PyPI. +- Released eggs must contain generated gettext `.mo` files, but these files must not be committed to the repository. The `.mo` files can be created with the `zest.pocompile` add-on, which should be installed together with `zest.releaser`. -- `.gitignore` and `MANIFEST.in` must reflect the files going in to the egg (must include page template, po files). +- `.gitignore` and `MANIFEST.in` must reflect the files going in to the egg (must include page template, po files). ```{seealso} [High quality automated package releases for Python with `zest.releaser`](https://opensourcehacker.com/2012/08/14/high-quality-automated-package-releases-for-python-with-zest-releaser/). ``` + ## Special packages The Plone Release Team releases the core Plone packages. @@ -58,13 +60,14 @@ These are: `plone.app.locales` : Please leave this to the i18n team lead, Vincent Fretin. + ## Plone core release process checklist -1. Check Jenkins status. +1. Check Jenkins status. Check the latest Plone coredev job on [Jenkins](https://jenkins.plone.org/). It should be green, but if it is not, fix the problem first. -2. Check out `buildout.coredev`. +2. Check out `buildout.coredev`. ```shell git clone git@github.com:plone/buildout.coredev.git @@ -74,45 +77,45 @@ These are: bin/buildout -c buildout.cfg ``` -3. Check packages for updates. +3. Check packages for updates. Check all packages for updates, add to or remove from `checkouts.cfg` accordingly. This script may help: ```shell bin/manage report --interactive ``` - + This step should not be needed, because we do the check for every single commit, but people may still have forgotten to add a package to the `checkouts.cfg` file. -4. Check packages individually. +4. Check packages individually. Use the `bin/fullrelease` script from the core development buildout. This includes extra checks that we have added in `plone.releaser`. It guides you through all the next steps. - 1. Check changelog. + 1. Check changelog. Check if `CHANGES` is up-to-date. All changes since the last release should be included. A "Fixes" or "New" header should be included, with the relevant changes under it. Upgrade notes are best placed here as well. Compare `git log HEAD...` with `CHANGES`, or from `zest.releaser` use the command `lasttaglog `. - 2. Run [pyroma](https://pypi.org/project/pyroma/). - 3. Run [check-manifest](https://pypi.org/project/check-manifest/). - 4. Check package "best practices" (`README`, `CHANGES`, `src` directory). - 5. Check if the version in `setup.py` is correct and follows our versioning best practice. - 6. Make a release (zest.releaser: `bin/fullrelease`) - 7. Remove packages from auto-checkout section in `checkouts.cfg` and update `versions.cfg`. - -5. Make sure `plone.app.upgrade` contains an upgrade step for the future Plone release. -6. Update CMFPlone version in `profiles/default/metadata.xml`. -7. Create an issue in to ask the i18n team lead @vincentfretin to do a `plone.app.locales` release. -8. Create a pending release (directory) on [dist.plone.org](https://dist.plone.org/). - - 1. Copy all core packages there. - 2. Possibly make an alpha or beta release of CMFPlone. - 3. Copy the `versions.cfg` file from coredev to there. - -9. Write an email to the Plone developers list announcing a pending release. + 2. Run [pyroma](https://pypi.org/project/pyroma/). + 3. Run [check-manifest](https://pypi.org/project/check-manifest/). + 4. Check package "best practices" (`README`, `CHANGES`, `src` directory). + 5. Check if the version in `setup.py` is correct and follows our versioning best practice. + 6. Make a release (zest.releaser: `bin/fullrelease`) + 7. Remove packages from auto-checkout section in `checkouts.cfg` and update `versions.cfg`. + +5. Make sure `plone.app.upgrade` contains an upgrade step for the future Plone release. +6. Update CMFPlone version in `profiles/default/metadata.xml`. +7. Create an issue in to ask the i18n team lead @vincentfretin to do a `plone.app.locales` release. +8. Create a pending release (directory) on [dist.plone.org](https://dist.plone.org/). + + 1. Copy all core packages there. + 2. Possibly make an alpha or beta release of CMFPlone. + 3. Copy the `versions.cfg` file from coredev to there. + +9. Write an email to the Plone developers list announcing a pending release. 10. Update `plone.app.locales` version. 11. Create a unified changelog. @@ -124,7 +127,7 @@ These are: 13. Update the "-latest" link on [dist.plone.org](https://dist.plone.org/). 14. For Plone 5.x versions only, create the new release on [Launchpad](https://launchpad.net/plone/). 15. Create a release page on [plone.org](https://plone.org/download/releases) -16. Send links to the installers list at . +16. Send links to the installers list at plone-installers@lists.sourceforge.net. 17. Wait for installers to be uploaded to Launchpad, with a link to the plone.org release page. 18. Publish release page on plone.org. 19. Update plone.org homepage links to point to the new release. diff --git a/coredev/roboto.md b/coredev/roboto.md index a195e0ade..ef2e7a109 100644 --- a/coredev/roboto.md +++ b/coredev/roboto.md @@ -21,30 +21,31 @@ Add brief description of what is Mr. Roboto and what it does. When a push happens on GitHub, `mr.roboto` is triggered and it starts to analyze the push. -- If it's on `buildout-coredev`, it starts the job of the branch that has been pushed. +- If it's on `buildout-coredev`, it starts the job of the branch that has been pushed. In this case, we send to `plone-cvs` the commit to keep track of the commits on that list. -- If it's on a package that's on the {file}`sources.cfg` of a `buildout-coredev`, it starts the coredev jobs that are linked to that package and a kgs job with that package. +- If it's on a package that's on the {file}`sources.cfg` of a `buildout-coredev`, it starts the coredev jobs that are linked to that package and a kgs job with that package. This kgs job is a snapshot of the last working version of the `buildout.coredev` with the newest version of the package that is involved on the push. These jobs are really fast, as we only test the package applied to the kgs Plone and Python version `coredev` buildout. -- If it's on a PLIP specification, it runs the job that is configured Through The Web on the `mr.roboto` interface at . +- If it's on a PLIP specification, it runs the job that is configured Through The Web on the `mr.roboto` interface at http://jenkins.plone.org/roboto/plips. ```{todo} `http://jenkins.plone.org/roboto/plips` is obsolete, and returns a 404 not found. ``` + ## Job finishes When Jenkins finishes a job, it makes a callback to `mr.roboto`, which in turn does the following: -- If it comes from a `coredev` job, when all the `coredev` jobs related to that push are finished, it writes a comment on the GitHub commit with all the information. +- If it comes from a `coredev` job, when all the `coredev` jobs related to that push are finished, it writes a comment on the GitHub commit with all the information. It does this one time only, with all the information, so no more empty mails from the GitHub notification system. -- If it comes from a kgs job and all the kgs jobs are finished, (that may take max 10 min) and some have failed, we send an email to the testbot mailing list saying that a commit failed on the kgs job. +- If it comes from a kgs job and all the kgs jobs are finished, (that may take max 10 min) and some have failed, we send an email to the testbot mailing list saying that a commit failed on the kgs job. We also send an email to [plone-cvs](https://sourceforge.net/projects/plone/lists/plone-cvs) with the information to keep track of all the commits. -- If it comes from a kgs job and all the kgs jobs are finished, and all are working, we send an email to [plone-cvs](https://sourceforge.net/projects/plone/lists/plone-cvs) with the information to keep track of all the commits. +- If it comes from a kgs job and all the kgs jobs are finished, and all are working, we send an email to [plone-cvs](https://sourceforge.net/projects/plone/lists/plone-cvs) with the information to keep track of all the commits. For all kgs jobs jenkins sends an email to the author with the results when is finished. -All the notifications have an URL similar to . +All the notifications have an URL similar to http://jenkins.plone.org/roboto/get_info?push=9a183de85b3f48abb363fa8286928a10. ```{todo} http://jenkins.plone.org/roboto/get_info?push=9a183de85b3f48abb363fa8286928a10 is obsolete, and returns a 404 not found. @@ -52,9 +53,9 @@ http://jenkins.plone.org/roboto/get_info?push=9a183de85b3f48abb363fa8286928a10 i On this URL, there is the commit hash, who committed it, the diff, the files, and the result for each Jenkins job. -- [plone-testbot](https://lists.plone.org/mailman/listinfo/plone-testbot) mailing list receives messages only when a test fails on the kgs environment, and may take up to ten minutes from the push. -- [plone-cvs](https://sourceforge.net/projects/plone/lists/plone-cvs) always has the commit, diff, and the information, and it may take ten minutes to get there after the push. -- The author receives the results of tests failing against kgs after ten minutes after the push. +- [plone-testbot](https://lists.plone.org/mailman/listinfo/plone-testbot) mailing list receives messages only when a test fails on the kgs environment, and may take up to ten minutes from the push. +- [plone-cvs](https://sourceforge.net/projects/plone/lists/plone-cvs) always has the commit, diff, and the information, and it may take ten minutes to get there after the push. +- The author receives the results of tests failing against kgs after ten minutes after the push. ```{note} In case of integration errors with other packages that may fail because of the push, kgs will not be aware of that. diff --git a/coredev/troubleshooting.md b/coredev/troubleshooting.md index 7dcc0f98c..61a94d3f3 100644 --- a/coredev/troubleshooting.md +++ b/coredev/troubleshooting.md @@ -15,11 +15,13 @@ Needs review. In general, a 'troubleshooting' page is nice, but this looks outda This chapter describes how to troubleshoot development issues in Plone. + ## Buildout issues Buildout can be frustrating for those unfamiliar with parsing through autistic robot language. These errors are almost always a quick fix, and a little bit of understanding goes a long way. + ### Errors running `bootstrap.py` You may not even get to running buildout, and then you will already have an error. @@ -62,6 +64,7 @@ You may get the same error above again, but now that you know how to fix it, you Hooray! + ### When `mr.developer` is unhappy `mr.developer` is never unhappy, except when it is. @@ -107,6 +110,7 @@ allow-hosts += sphinx.pocoo.org Again, this is only necessary if the package wasn't found in the end. + ### `mr.developer` path errors ```console @@ -121,18 +125,21 @@ To fix, do: ln -s plips/.mr.developer.cfg ``` + ## Other random issues ```{TODO} These need to be revalidated ``` + ### Dirty packages ```console ERROR: Can't update package 'Some package', because it's dirty. ``` + #### Fix `mr.developer` is complaining because a file has been changed or added, but not committed. @@ -140,6 +147,7 @@ ERROR: Can't update package 'Some package', because it's dirty. Use `bin/develop update --force`. Adding `*.pyc *~.nib *.egg-info .installed.cfg *.pt.py *.cpt.py *.zpt.py *.html.py *.egg` to your subversion configuration's `global-ignores` has been suggested as a more permanent solution. + ### No module named zope 2 ```console @@ -149,6 +157,7 @@ ImportError: No module named Zope2" when building using a PLIP cfg file. Appears to not actually be the case. Delete {file}`mkzopeinstance.py` from {file}`bin/`, and rerun buildout to correct this if you're finding it irksome. + ### Can't open file '/Startup/run.py' Two possible fixes. @@ -158,6 +167,7 @@ If you use Python 2.4 by mistake, use 2.6 instead. Or you may need to make sure you run `bin/buildout …` after `bin/develop …`. Try removing {file}`parts/*`, {file}`bin/*`, {file}`.installed.cfg`, then re-bootstrap and re-run buildout, develop, buildout. + ### Missing PIL {file}`pil.cfg` is included within this buildout to aid in PIL installation. @@ -165,6 +175,7 @@ Run {command}`bin/buildout -c pil.cfg` to install. This method does not work on Windows. We're unable to run it by default. + ### Modified egg issues {command}`bin/develop status` is showing that the `Products.CMFActionIcons` egg has been modified, but I haven't touched it. From 6449526e325e2d4da45e27fefe1228b052ebe01a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 19 Jun 2024 00:28:08 -0700 Subject: [PATCH 282/810] Minor grammar fixes, restore whitespace, one line per sentence, emphasis not strong --- .../core/continuous-integration.md | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/docs/contributing/core/continuous-integration.md b/docs/contributing/core/continuous-integration.md index ed195183b..9cf3e6fda 100644 --- a/docs/contributing/core/continuous-integration.md +++ b/docs/contributing/core/continuous-integration.md @@ -13,7 +13,8 @@ The {term}`CI` system at [jenkins.plone.org](https://jenkins.plone.org) is a sha Build breakages are a normal and expected part of the development process. The aim is to find errors and remove them as quickly as possible, without expecting perfection and zero errors. -Though, there are some essential practices that you need follow to achieve a stable build: +However, there are some essential practices that you need follow to achieve a stable build: + ## 1) Don't check in on a broken build @@ -26,43 +27,52 @@ Checking in further changes and triggering new builds will complicate matters an If the build is broken over a longer period of time (more than a couple of hours) you should either: -- notify the developer who is responsible for the breakage -- fix the problem yourself -- or revert the commit so you and others can continue to work. +- notify the developer who is responsible for the breakage +- fix the problem yourself +- revert the commit so you and others can continue to work ```{note} There is one exception to this rule. Sometimes there are changes or tests that depend on changes in other packages. If this is the case, there is no way around breaking a single build for a certain period of time. -In this case run the all tests locally with all the changes and commit them within a time frame of ten minutes. +In this case, run the all tests locally with all the changes and commit them within a time frame of ten minutes. ``` + ## 2) Always run all commit tests locally before committing Follow this practice so the build stays green, and other developers can continue to work without breaking the first rule. -Remember that Plone development can happen all over the world, at all times. So other developers may have checked in changes since your last synchronization. These may interact with your work. +Remember that Plone development can happen all over the world, at all times. +Other developers may have checked in changes since your last synchronization. +These may interact with your work. -Therefore it's essential that you check out ({command}`git pull`) and run the tests again before you push your changes to GitHub. +Therefore it's essential that you merge changes from the main branch into your feature branch, then run the tests again, before you push your changes to GitHub. A common source of errors on check-in is to forget to add some files to the repository. -Use {command}`git status` to check and correct for this. Also double-check to not check in files that should not be part of a package, such as editor configuration files. +Use {command}`git status` to check and correct for this. +Also double-check to not check in files that should not be part of a package, such as editor configuration files and git submodules. + ## 3) Wait for commit tests to pass before moving on Always monitor the build's progress, and fix the problem right away if it fails. -You have a far better chance of fixing the build, if you just introduced a regression than later. +If you introduced a regression, you have a far better chance of fixing the build sooner than later. Also another developer might have committed in the meantime (by breaking rule 1), making things more complicated for you. + ## 4) Never go home on a broken build -Take into account the first rule of CI ("Don't check in on a broken build"): breaking the build essentially stops all other developers from working on it. -Therefore going home on a broken build (or even on a build that has not finished yet) is **not** acceptable. -It will prevent all other developers to stop working or they will need to fix the errors that you introduced. +Take into account the first rule of CI ("Don't check in on a broken build"). +Breaking the build essentially stops all other developers from working on it. +Therefore going home on a broken build—or even on a build that has not finished yet—is _not_ acceptable. +It will prevent all other developers from working, or they will need to fix the errors that you introduced. + ## 5) Always be prepared to revert to the previous revision -In order for other developers to be able to work on the build, you should always be prepared to revert to the previous (passing) revision. +For other developers to work on the build, you should always be prepared to revert to the previous passing revision. + ## 6) Time-box fixing before reverting @@ -70,28 +80,31 @@ When the build breaks on check-in, try to fix it for ten minutes. If, after ten minutes, you aren't finished with the solution, revert to the previous version from your version control system. This way you will allow other developers to continue to work. + ## 7) Don't comment out failing tests -Once you begin to enforce the previous rule, the result is often that developers start commenting out failing tests in order to get the build passing again as quick as possible. -While this impulse is understandable, it is **not acceptable**. +Once you begin to enforce the previous rule, the result is often that developers start commenting out failing tests in order to get the build passing again as quickly as possible. +While this impulse is understandable, it is _not acceptable_. The tests were passing for a while and then start to fail. This means that you either caused a regression, made assumptions that are no longer valid, or the application has changed the functionality being tested for a valid reason. You should always either fix the code (if a regression has been found), modify the test (if one of the assumptions has changed), or delete it (if the functionality under test no longer exists). + ## 8) Take responsibility for all breakages that result from your changes If you commit a change and all the tests you wrote pass, but others break, the build is still broken. This also applies to tests that fail in `buildout.coredev` and don't belong directly to the package you worked on. This means that you have introduced a regression bug into the application. -It is **your responsibility** to fix all tests that are not passing because of your changes. +It is _your responsibility_ to fix all tests that do not pass because of your changes. + +There are some tests in Plone that fail randomly, and the community is always working on fixing those. +If you think you hit such a test, try to fix it or re-run the Jenkins job to see if it passes again. -There are some tests in Plone that fail randomly, the community is always working on fixing those. -If you think you hit such a test, try to fix it (better) or re-run the Jenkins job to see if it passes again. +In any case, the developer who made the commit is responsible to make it pass. -In any case the developer who made the commit is responsible to make it pass. ## Further reading From 7d90a292fca07ed54f883b54cd0c8ac250f7d080 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 19 Jun 2024 01:02:04 -0700 Subject: [PATCH 283/810] Revise documentation.md with current resources --- docs/contributing/core/documentation.md | 65 ++++++++++++++++--------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/docs/contributing/core/documentation.md b/docs/contributing/core/documentation.md index 740b86881..70f3b299d 100644 --- a/docs/contributing/core/documentation.md +++ b/docs/contributing/core/documentation.md @@ -15,10 +15,11 @@ For documentation authors, see {doc}`/contributing/documentation/authors`. ## Documentation of Plone -The comprehensive resource for Plone documentation is . +The comprehensive resource for Plone documentation is https://6.docs.plone.org/. The documentation repository is on [GitHub](https://github.com/plone/documentation). Information for how to contribute to documentation can be found at {doc}`/contributing/documentation/index`. + ## Documenting a package At the very least, your package should include the following forms of documentation. @@ -31,51 +32,71 @@ It should be formatted using [GitHub flavored Markdown](https://github.github.co `README.md` should include: -- A brief description of the package's purpose. -- Installation information (How do I get it working?) -- Compatibility information (what versions of Plone does it work with?) -- Links to other sources of documentation. -- Links to issue trackers, mailing lists, and other ways to get help. +- A brief description of the package's purpose +- Installation information +- Version compatibility information +- Links to other sources of documentation +- Links to issue trackers, mailing lists, and other ways to get help + +```{seealso} +{ref}`github-community-health-files-label` +``` + ### The manual (narrative documentation) -The manual goes into further depth for people who want to know all about how to use the package. +The manual should go into further depth for people who want to know all about how to use the package. -It includes topics like: +It should include topics like: -- What are its features -- How to use them (in English — not doctests!) -- Information about architecture -- Common gotchas +- What are its features +- How to use them (in English—not doctests!) +- Information about architecture +- Common gotchas -The manual should consider various audiences who may need different types of information: +The manual should address various audiences who may need different types of information: -- End users who use Plone for content editing, but don't manage the site. -- Site administrators who install and configure the package. -- Integrators who need to extend the functionality of the package in code. -- System administrators who need to maintain the server running the software. +- End users who use Plone for content editing, but don't manage the site. +- Site administrators who install and configure the package. +- Integrators who need to extend the functionality of the package in code. +- System administrators who need to maintain the server running the software. Simple packages with limited functionality can get by with a single page of narrative documentation. In this case, it's simplest to include it in an extended `README.md`. -Some excellent examples of a single-page README are and . +Some excellent examples of a single-page README are https://pypi.org/project/plone.outputfilters/ and https://github.com/plone/plone.app.caching. If your project is moderately complex, you may want to set up your documentation with multiple pages. -The preferred way to do this is to add Sphinx to your project, and host your docs on [readthedocs.org](https://readthedocs.org), so that it rebuilds the documentation whenever you push to GitHub. +The preferred way to do this is to add Sphinx to your project, and host your docs on [readthedocs.org](https://about.readthedocs.com/), so that it rebuilds the documentation whenever you push to GitHub. If you do this, your `README.md` must link off site to the documentation. + ### Reference or API documentation An API reference provides information about the package's public API (that is, the code that the package exposes for use from external code). It is meant for random access to remind the reader of how a particular class or method works, rather than for reading in its entirety. -If the codebase is written with docstrings, API documentation can be automatically generated using Sphinx. +If the code base is written with docstrings, API documentation can be automatically generated using Sphinx. + ### Changes or history -Best practice is to set up [towncrier](https://pypi.org/project/towncrier/) so your package will have a clear and structured history of changes. +```{seealso} +- {ref}`contributing-change-log-label` +- Volto's [`towncrier.toml`](https://github.com/plone/volto/blob/main/packages/volto/towncrier.toml) as an example towncrier configuration file. +``` + ### Licenses -Information about the open source license used for the package should be placed within the `docs` directory. +Information about the open source license used for the package should be placed where GitHub can pick it up and display it as one of its [community health files](https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/creating-a-default-community-health-file). +The preferred location is at the root of the repository. For Plone core packages, this includes `LICENSE.md` and {file}`LICENSE.GPL`. + + +(github-community-health-files-label)= + +### GitHub community health files + +If your Plone core package lacks a specific community health file, then GitHub will pick up the one configured in the Plone GitHub organization repository [`.github`](https://github.com/plone/.github). +You can override the default files by placing your health file as described in the documentation of [GitHub community health files](https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/creating-a-default-community-health-file). From e2fb4f8bf4e3509e01b642b96a6bbc6b32d6a8ff Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 20 Jun 2024 03:44:22 -0700 Subject: [PATCH 284/810] - Set the stage for the purpose of this contributing how to guide. It's not an explanation or reference. - Purge git and GitHub material, and refer to first-time contributors. - Modify pre-requisites --- docs/contributing/core/index.md | 286 +++++++++++++++++--------------- 1 file changed, 156 insertions(+), 130 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 6c505c50a..de83cbb98 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -1,236 +1,262 @@ --- myst: html_meta: - "description": "Contributing to Plone 6 Core" - "property=og:description": "Contributing to Plone 6 Core" - "property=og:title": "Contributing to Plone 6 Core" - "keywords": "Plone, Plone Contributor Agreement, License, Code of Conduct" + "description": "Contribute to Plone 6 Core" + "property=og:description": "Contribute to Plone 6 Core" + "property=og:title": "Contribute to Plone 6 Core" + "keywords": "Plone, Plone Contributor Agreement, License" --- -# Contributing to Plone 6 core +# Contribute to Plone 6 core -This part describes the process of development in Plone core. -It's primarily a technical resource for setting up your development environment, fixing bugs, and writing Plone Improvement Proposals (PLIPs). +This guide describes the process of how to contribute to, and develop in, Plone core. +It expands upon {doc}`/contributing/index`. + +This guide assumes that you have basic knowledge of how to use git and GitHub. +If you have never contributed to Plone, or you lack basic knowledge of how to use git and GitHub, you should first read {doc}`/contributing/first-time` for more information. + +```{important} +You must {ref}`contributing-sign-and-return-the-plone-contributor-agreement-label` before your contribution can be accepted. +``` -It expands upon {doc}`/contributing/index` and, where applicable, {doc}`/contributing/first-time`. ## Version support policy -If you are fixing bugs, keep in mind that Plone has a [version support policy](https://plone.org/download/release-schedule) +Before you contribute to Plone core, check the [version support policy](https://plone.org/download/release-schedule) to see which versions of Plone are currently supported. -## Dependencies + +## Pre-requisites + +It is beyond the scope of this documentation to provide installation instructions for all pre-requisites for your operating system. +However, the following links and sections below may be helpful. ```{include} ../../volto/contributing/install-operating-system.md ``` -- {ref}`setup-build-installation-python-label` {SUPPORTED_PYTHON_VERSIONS} -- {ref}`setup-build-installation-gnu-make-label` -- [git](https://help.github.com/articles/set-up-git/) -- [Pillow](https://pypi.org/project/Pillow/). -- [libxml2 and libxslt](https://gitlab.gnome.org/GNOME/libxslt/-/releases), including development headers. -- [GCC](https://gcc.gnu.org/) to compile {term}`ZODB`, {term}`Zope` and {term}`lxml`. +- Python {SUPPORTED_PYTHON_VERSIONS} +- {term}`GNU make` +- {term}`Git` +- [libxml2 and libxslt](https://gitlab.gnome.org/GNOME/libxslt/-/releases), including development headers +- [GNU Compiler Collection (GCC)](https://gcc.gnu.org/) to compile {term}`ZODB`, {term}`Zope`, and {term}`lxml` + + +### Python + +Installing Python is beyond the scope of this documentation. +However, it is recommended to use a Python version manager, {term}`pyenv` that allows you to install multiple versions of Python on your development environment without destroying your system's Python. +Plone requires Python version {SUPPORTED_PYTHON_VERSIONS}. + + +### Make + +```{include} ../../volto/contributing/install-make.md +``` + -The first step in fixing a bug is getting this [buildout](https://github.com/plone/buildout.coredev) running. -Start with fixing the bug on the latest branch and then [backporting](https://en.wikipedia.org/wiki/Backporting) as necessary. -[GitHub](https://github.com/plone/buildout.coredev/) by default always points to the currently active branch. -Depending on the current development cycle there may exist a future branch. +### Git -At the moment 6.0 is the actively maintained stable branch and 6.1 is the future, currently unstable, active development branch. -More information on switching release branches is below. +```{include} ../../volto/contributing/install-git.md +``` + +### libxml2, libxslt, and GCC + +Consult the resources at the links above for installation instructions. +Package managers may facilitate installation. + + +## Install Plone core for development + +To set up a Plone 6 development environment, change your working directory to wherever you place your projects, and clone https://github.com/plone/buildout.coredev. + +```shell +cd [MY_PROJECTS] +git clone https://github.com/plone/buildout.coredev +cd buildout.coredev +``` -To set up a plone 6 development environment: +Now run the script to install Plone 6. ```shell -cd ~/buildouts # or wherever you want to put things -git clone -b 6.1 https://github.com/plone/buildout.coredev ./plone6devel -cd ./plone6devel ./bootstrap.sh ``` -If you run into issues in this process, please see {doc}`troubleshooting`. +If you run into issues in this process, see {doc}`troubleshooting`. -This will run for a long time if it's your first pull (approximately 20 minutes). -Once that's done pulling down eggs, you can start your new instance with: +This will run for a long time if it's your first pull (approximately 10-20 minutes, depending on network speed and your hardware). + +Once that's done, you can start an instance of Plone with the following command. ```shell ./bin/instance fg ``` -or as {term}`WSGI` service with:: +Alternatively, you can start Plone as a {term}`WSGI` service with the following command. ```shell ./bin/wsgi ``` -To login, the defaults are: +To visit your Plone instance, you can open the link http://0.0.0.0:8080 in a web browser. + +Click {guilabel}`View your Plone site` to do exactly that. -- username: admin -- password: admin +To login, the default credentials are the following. -## Switching branches +- username: `admin` +- password: `admin` -If the bug is specific to one branch or should be [backported](http://en.wikipedia.org/wiki/Backporting), -you can easily switch branches. The first time you get a branch, you must do: + +## Use the correct branch + +```{important} +This section applies to members of the GitHub `plone/developers` team, who have write access to repositories under the Plone GitHub organization. + +Members of the `plone/contributors` team do not have write access, and instead must follow the process to set up their remote upstream and origin branches as described in {ref}`set-up-your-environment-label`. +``` + +The current default and development branch of `buildout.coredev` is `6.1`. +Older versions are named according to their `major.minor` version. + +Always begin by checking out the git branch on which you want to work, usually called `origin`. +If you have not yet checked out a branch, then you need to track it with the `-t` option and specify the remote branch to track. +The following command will switch and track changes from the remote branch `origin/6.1`. ```shell git checkout -t origin/6.1 ``` -This should set up a local 6.1 branch tracking the one on GitHub. -From then on you can do: +If you check out a different branch, and want to return to the previous branch, you need to specify only the local branch. ```shell git checkout 6.1 ``` -To see what branch you are currently on, +Next pull down and merge any recent changes from the remote tracked repository with a single command. ```shell -git branch +git pull ``` -The line with a * by it will indicate which branch you are currently working on. - ```{important} -Make sure to rerun buildout if you were in a different branch earlier to get the correct versions of packages, otherwise you will get some weird behavior. +Make sure to rerun buildout for the current branch to get the correct versions of packages, otherwise you will get some weird behavior. ``` -## Jenkins and mr.roboto +Next create a new branch on which you want to work from the current branch, tracking the upstream Plone repository, and check it out. +It's a good idea to use a branch name that includes the issue number and is descriptive of what it resolves. -Plone has a continuous integration ({term}`CI`) setup and follows CI rules. +```shell +git switch -c 123-my-branch-name -t origin/6.1 +``` -When you push a change to any Plone package, the testing/CI package [mr.roboto](https://github.com/plone/mr.roboto) starts running all the tests to make sure that you don't break anything. -For each Plone and Python version it runs two jobs, one for the package itself (which will give you a fast feedback, within 10 minutes) and one on the full `coredev` build (which can take up to an hour, but makes sure no other packages are affected by your change). +Now you can edit your code without affecting the original branch. -See {doc}`continuous-integration` for more information. -## Check out packages to fix +## Edit packages -Most packages are not in {file}`src/` by default, so you can use `mr.developer` to get the latest and make sure you are always up to date. -It can be a little daunting at first to find out which packages cause the bug in question, you can ask in if you need some help. -Once you know which packages you want, pull their source. +First identify the names of the Plone packages you want to work on. +If you do not know, you can ask in the [Plone Community Forum](https://community.plone.org/). +Only a few packages are in {file}`src/` by default. -At the base of your buildout, open {file}`checkouts.cfg` and add your package if it's not already there: +Edit the file {file}`checkouts.cfg` at the root of the repository by adding the package names under the `auto-checkout` list. -```cfg +```{code-block} cfg +:emphasize-lines: 10- +[buildout] +always-checkout = force +# always-checkout = false auto-checkout = - # my modified packages - plone.app.caching - plone.caching - # others - ... +# These packages are always checked out: + docs + # +# These packages are manually added, or automatically added by mr.roboto: + # + plone.app.event + icalendar ``` -Then rerun buildout to get the source packages: +Then rerun buildout to install the source packages to edit. ```shell ./bin/buildout ``` -For some more tips on working with `mr.developer`, please read {doc}`mrdeveloper`. +```{seealso} +For tips on working with `mr.developer`, see {doc}`mrdeveloper`. +``` -## Testing locally -To run a test for the specific module you modify: +## Test locally + +If you change the expected behavior of a feature in a package, you should write a test to cover the change. + +To run a test for the specific package that you modified, use the `-m` option followed by the package name, as shown in the following example. ```shell ./bin/test -m plone.app.caching ``` -These should all run without error. -Please don't check in anything that doesn't succeed! -Now write a test case for the bug you are fixing, and make sure everything is running as it should. +If any test fails, do not commit and push the changes. +Instead write a test that passes. -After the module level tests run with your change, please make sure other modules aren't affected by the change by running the full suite, including robot-tests (remove the `--all` to run without robot tests): +After the package level tests pass with your change, you can run the full unit test suite to ensure other packages aren't affected by the change. +It takes 5-10 minutes to run the full unit test suite. ```shell -./bin/test --all +# Run unit tests +./bin/test ``` -```{note} -Tests take a long time to run. -Once you have enough experience in doing bugfixes, -you may let jenkins do this part for you. -More on that below. -``` - -## Updating `CHANGES.rst` and `checkouts.cfg` +If you run acceptance tests with the `--all` option, it will repeatedly launch and close browser windows that gain focus, disrupting you from doing any other work. +This takes 30-40 minutes to run. +If you can't afford this disruption, you can defer it to Jenkins. -Once all the tests run locally on your machine, you are **ALMOST** ready to commit the changes. -You must perform a couple housekeeping chores before moving on. +```shell +# Run acceptance tests +./bin/test --all +``` -You need to create a change note of what has been modified. -This change note will be collated for the next Plone release and is important for integrators and developers to be able to see what they will get if they upgrade. -Most packages are using [towncrier](https://pypi.org/project/towncrier/). -If that is the case, there will be a directory "news" in the package. Please follow the Towncrier format and put a note in that directory. +## Change log -For packages that haven't switched to using Towncrier, edit {file}`CHANGES.rst` (or {file}`CHANGES.txt`, or {file}`HISTORY.txt`) in each package you have modified and add a summary of the change. New changelog entries should be added at the top of {file}`CHANGES.rst`. +All changes require a change log entry. -Most importantly, if you didn't do it earlier, edit the file {file}`checkouts.cfg` in the buildout directory, and add your changes package to the `auto-checkout` list. -This lets the release manager know that the package has been updated, so that when the next release of Plone is cut, a new egg will be released, and Plone will need to pin to the next version of that package. -In other words, this is how your fix becomes an egg! +For packages that use [towncrier](https://pypi.org/project/towncrier/) to produce change logs, see {ref}`contributing-change-log-label`. -Note that there is a section separator called "# Test Fixes Only". -Make sure your egg is above that line, else your egg probably won't get made quickly. -This tells the release manager that any eggs below this line have tests that are updated, but no code changes. +For packages that don't use towncrier, edit either {file}`CHANGES.rst`, {file}`CHANGES.txt`, or {file}`HISTORY.txt` in each package you have modified, adding a summary of the change. +New change log entries should be added at the top of {file}`CHANGES.rst`. -Modifying the file {file}`checkouts.cfg` also triggers the buildbot, [jenkins](https://jenkins.plone.org/), to pull in the egg and run all the tests against the changes you just made. -If your bug fix is in more than one release, for example 6.1 and 6.0, please checkout both branches, and add it to the file {file}`checkouts.cfg` in both branches. +## Update `checkouts.cfg` -## Commits and pull requests +If you didn't do so earlier, edit the file {file}`checkouts.cfg` at the root, and add your changed packages only to the `auto-checkout` list. +Remove any packages that you previously added to this file, but did not change. +Leave any pre-existing packages in the original list. -Review the following checklist: +The Plone release manager will check this file to see which packages you have updated to make a proper release. -- Did you fix the original bug? -- Is your code consistently formatted? You can use the [Plone Meta](https://github.com/plone/meta) project to set up your development environment to be consistent with Plone community agreed best practices. -- Did you remove any extra code and lingering {term}`pdb` statements? -- Did you write a test case for that bug? -- DO all test cases for the modules and Plone pass? -- Did you write an update note (using Towncrier or via {file}`CHANGES.rst`) in each package you changed? -- Did you add your changed packages to {file}`checkouts.cfg`? +```{seealso} +{doc}`release` +``` -If you answered *Yes* to all, then you are ready to push your changes! -A couple of quick reminders: -- Never commit directly to the development branch. Create a `pull request` (more on that below). -- Please try to make one change per commit. - If you are fixing three bugs, make three commits. - That way, it's easier to see what was done when, and easier to roll back any changes if necessary. - If you want to make large changes cleaning up whitespace or renaming variables, it's especially important to do so in a separate commit for this reason. +## Create a pull request -## Branching and pull requests +After you have completed all the foregoing steps, push your changes to a remote branch and create a pull request in GitHub. -You should create a branch of whatever packages you are updating, and then use the [pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) feature of GitHub to get review. +If you are working from an issue, return to the original issue, and add a link to the pull request. -Take the `plone.app.caching` example. -After checking it out with `mr.developer`, create your own branch with: -```shell -cd src/plone.app.caching -git checkout -b my_descriptive_branch_name -``` +## Jenkins and mr.roboto -When you are ready to push your fix, push to a remote branch with: +Plone has a continuous integration ({term}`CI`) setup and follows CI rules. -```shell -git push origin my_descriptive_branch_name -``` +When you push a change to a Plone package, there may be GitHub workflows that run automatically. +The CI package [mr.roboto](https://github.com/plone/mr.roboto) will perform some checks and suggest that you run Jenkins after all other CI runs. -This will make a remote branch in GitHub. -Navigate to this branch in the GitHub user interface, and on the top right, there will be a button that says {guilabel}`Pull Request`. -This will turn your request into a pull request on the main branch. -There are people who look once a week or more for pending pull requests and will confirm whether it's a good fix, and give you feedback where necessary. -The reviewers are informal and nice, so don't worry. -They are there to help! -If you want immediate feedback, visit with the pull request link and ask for a review. +For each Plone and Python version, Jenkins runs two jobs: one for the package itself (which will give you a fast feedback, within 10 minutes) and one on the full `coredev` build (which can take up to an hour, but makes sure no other packages are affected by your change). -## Finalize issues +See {doc}`continuous-integration` for more information. -If you are working from an issue, please don't forget to go back to the issue, and add a link to the change set. -There is no automatic integration with GitHub yet so it's a nice way to track changes. -It also lets the reporter know that you care. ## Additional material From e719f682ed49853c2947d9e401caa6f628f273ca Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 20 Jun 2024 03:55:34 -0700 Subject: [PATCH 285/810] Pull in RTD PR review config --- .github/workflows/rtd-pr-preview.yml | 22 ++++++++++++++++++++++ .readthedocs.yaml | 25 +++++++++++++++++++++++++ Makefile | 13 ++++++------- 3 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/rtd-pr-preview.yml create mode 100644 .readthedocs.yaml diff --git a/.github/workflows/rtd-pr-preview.yml b/.github/workflows/rtd-pr-preview.yml new file mode 100644 index 000000000..bf7bd5aef --- /dev/null +++ b/.github/workflows/rtd-pr-preview.yml @@ -0,0 +1,22 @@ +# .github/workflows/rtd-pr-preview.yml +name: readthedocs/actions +on: + pull_request_target: + types: + - opened + # Execute this action only on PRs that touch + # documentation files. + # paths: + # - "docs/**" + +permissions: + pull-requests: write + +jobs: + documentation-links: + runs-on: ubuntu-latest + steps: + - uses: readthedocs/actions/preview@v1 + with: + project-slug: "plone6" + single-version: "true" diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 000000000..8beeb58c4 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,25 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.12" + commands: + # Cancel building pull requests when there aren't changes in the docs directory or YAML file. + # You can add any other files or directories that you'd like here as well, + # like your docs requirements file, or other files that will change your docs build. + # + # If there are no changes (git diff exits with 0) we force the command to return with 183. + # This is a special exit code on Read the Docs that will cancel the build immediately. + - | + if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && git diff --quiet origin/main -- docs/ .readthedocs.yaml requirements-initial.txt requirements.txt; + then + exit 183; + fi + - make rtd-pr-preview diff --git a/Makefile b/Makefile index ac8d6062a..98e33474b 100644 --- a/Makefile +++ b/Makefile @@ -224,18 +224,17 @@ livehtml: deps ## Rebuild Sphinx documentation on changes, with live-reload in --port 8050 \ -b html . "$(BUILDDIR)/html" $(SPHINXOPTS) $(O) -.PHONY: netlify -netlify: +.PHONY: rtd-pr-preview +rtd-pr-preview: ## Build pull request preview on Read the Docs pip install -r requirements-initial.txt pip install -r requirements.txt - pip install -r requirements-netlify.txt - git submodule init; \ - git submodule update; \ - pip install -e submodules/plone.api[test]; \ + git submodule init + git submodule update + pip install -e submodules/plone.api[test] ln -s ../submodules/volto/docs/source ./docs/volto ln -s ../submodules/plone.restapi ./docs/plone.restapi ln -s ../submodules/plone.api/docs ./docs/plone.api - cd $(DOCS_DIR) && sphinx-build -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html && cp ./netlify_robots.txt $(BUILDDIR)/html/robots.txt + cd $(DOCS_DIR) && sphinx-build -b html $(ALLSPHINXOPTS) ${READTHEDOCS_OUTPUT}/html/ .PHONY: storybook storybook: From 13871426e82eb8846be72f9a80037d47c5ddc0a4 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 20 Jun 2024 04:00:26 -0700 Subject: [PATCH 286/810] Use correct primary branch --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 8beeb58c4..9ae0eeee5 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -18,7 +18,7 @@ build: # If there are no changes (git diff exits with 0) we force the command to return with 183. # This is a special exit code on Read the Docs that will cancel the build immediately. - | - if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && git diff --quiet origin/main -- docs/ .readthedocs.yaml requirements-initial.txt requirements.txt; + if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && git diff --quiet origin/6.0 -- docs/ .readthedocs.yaml requirements-initial.txt requirements.txt; then exit 183; fi From d564e7fb895b6585f660bc92f6bc17363355d569 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 20 Jun 2024 04:03:13 -0700 Subject: [PATCH 287/810] Use RTD for pull request previews --- .github/workflows/rtd-pr-preview.yml | 22 ++++++++++++++++++++++ .readthedocs.yaml | 25 +++++++++++++++++++++++++ Makefile | 13 ++++++------- 3 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/rtd-pr-preview.yml create mode 100644 .readthedocs.yaml diff --git a/.github/workflows/rtd-pr-preview.yml b/.github/workflows/rtd-pr-preview.yml new file mode 100644 index 000000000..bf7bd5aef --- /dev/null +++ b/.github/workflows/rtd-pr-preview.yml @@ -0,0 +1,22 @@ +# .github/workflows/rtd-pr-preview.yml +name: readthedocs/actions +on: + pull_request_target: + types: + - opened + # Execute this action only on PRs that touch + # documentation files. + # paths: + # - "docs/**" + +permissions: + pull-requests: write + +jobs: + documentation-links: + runs-on: ubuntu-latest + steps: + - uses: readthedocs/actions/preview@v1 + with: + project-slug: "plone6" + single-version: "true" diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 000000000..8beeb58c4 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,25 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.12" + commands: + # Cancel building pull requests when there aren't changes in the docs directory or YAML file. + # You can add any other files or directories that you'd like here as well, + # like your docs requirements file, or other files that will change your docs build. + # + # If there are no changes (git diff exits with 0) we force the command to return with 183. + # This is a special exit code on Read the Docs that will cancel the build immediately. + - | + if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && git diff --quiet origin/main -- docs/ .readthedocs.yaml requirements-initial.txt requirements.txt; + then + exit 183; + fi + - make rtd-pr-preview diff --git a/Makefile b/Makefile index ac8d6062a..98e33474b 100644 --- a/Makefile +++ b/Makefile @@ -224,18 +224,17 @@ livehtml: deps ## Rebuild Sphinx documentation on changes, with live-reload in --port 8050 \ -b html . "$(BUILDDIR)/html" $(SPHINXOPTS) $(O) -.PHONY: netlify -netlify: +.PHONY: rtd-pr-preview +rtd-pr-preview: ## Build pull request preview on Read the Docs pip install -r requirements-initial.txt pip install -r requirements.txt - pip install -r requirements-netlify.txt - git submodule init; \ - git submodule update; \ - pip install -e submodules/plone.api[test]; \ + git submodule init + git submodule update + pip install -e submodules/plone.api[test] ln -s ../submodules/volto/docs/source ./docs/volto ln -s ../submodules/plone.restapi ./docs/plone.restapi ln -s ../submodules/plone.api/docs ./docs/plone.api - cd $(DOCS_DIR) && sphinx-build -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html && cp ./netlify_robots.txt $(BUILDDIR)/html/robots.txt + cd $(DOCS_DIR) && sphinx-build -b html $(ALLSPHINXOPTS) ${READTHEDOCS_OUTPUT}/html/ .PHONY: storybook storybook: From a8fd30bfccd5ff127294736c94caa52625ff8f81 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 20 Jun 2024 04:19:30 -0700 Subject: [PATCH 288/810] Update admins.md --- docs/contributing/documentation/admins.md | 163 +++++++++++++++------- 1 file changed, 116 insertions(+), 47 deletions(-) diff --git a/docs/contributing/documentation/admins.md b/docs/contributing/documentation/admins.md index e8d9591a3..fe3c2db89 100644 --- a/docs/contributing/documentation/admins.md +++ b/docs/contributing/documentation/admins.md @@ -4,7 +4,7 @@ myst: "description": "Administrators' guide to writing Plone Documentation. It covers automated deployments, hosting, automated testing, previewing, and importing external package documentation into Plone Documentation." "property=og:description": "Administrators' guide to writing Plone Documentation. It covers automated deployments, hosting, automated testing, previewing, and importing external package documentation into Plone Documentation." "property=og:title": "Administrators Guide" - "keywords": "Plone, Documentation, automated deployments, hosting, automated testing, importing external packages" + "keywords": "Plone, Documentation, automated deployments, hosting, automated testing, importing external packages, preview, build, pull request" --- (administrators-guide-label)= @@ -84,49 +84,118 @@ To make it easier for other contributors to work with your project, update the f Commit and push your changes to a remote, and submit a pull request against [`plone/documentation@6.0`](https://github.com/plone/documentation/compare). -## Add a project to Netlify - -To add a new site to Netlify to preview built documentation or storybooks, you need to add a new site to Netlify. - -1. Visit [Team Overview](https://app.netlify.com/teams/plone/overview). -1. Click {guilabel}`Add a new site` and select {guilabel}`Import an existing project`. -1. Click {guilabel}`Deploy with GitHub`. -1. Select {guilabel}`plone` for the GitHub organization. -1. Click {guilabel}`Configure Netlify on GitHub`. -1. Select the organization to where you want to install Netlify. -1. Click {guilabel}`Select repositories` and select the repository that you want to add. -1. Click {guilabel}`Update access`. -1. Netlify sends an email to members of the email group `admins` at `plone.org`, who need to review and approve the request. - However the email doesn't specify the repository, and admins will not know what to do. - You must send email to that group, including in your request the organization and repository, such as `plone/volto`. -1. The admin must login to GitHub as an organization owner, then navigate to the requested repository's {guilabel}`Settings`. [What else Admin person?] -1. The admin replies to the requestor, letting them know the request was approved. - -From here you need to update your repository to work with Netlify. -For an example, see the following files. - -- [Volto `Makefile`](https://github.com/plone/volto/blob/main/Makefile), specifically the `netlify` section. - This will become the command used to build docs on Netlify. -- [Volto `requirements-docs.txt`](https://github.com/plone/volto/blob/main/requirements-docs.txt) specifies the requirements to build the docs. -- [Volto `netlify.toml`](https://github.com/plone/volto/blob/main/netlify.toml) specifies when to build the docs, specifically only when there are changes to documentation files. - -Finally you need to configure your site in Netlify. -You may have done some of these steps earlier, but you might need to refine them. -The critical pieces are the following. - -1. From the dashboard, select the site to edit it. -1. Click {guilabel}`Site configuration`. -1. One time only, under {guilabel}`General > Site details` click {guilabel}`Change site name`. - A modal dialog appears. - Enter the site name using the pattern `ORGANIZATION_NAME-REPOSITORY_NAME`. - For example, `plone-components`. - Click {guilabel}`Save`. -1. Under {guilabel}`Build & deploy > Continuous deployment`, scroll to {guilabel}`Build settings`, and click {guilabel}`Configure`, then enter the following values. - - {guilabel}`Base directory`: `/` - - {guilabel}`Package directory`: `/` - - {guilabel}`Build command`: `make netlify`. - This is the command you would define in your `Makefile`. - - {guilabel}`Publish directory`: `_build/html`. - This is where the `make` command will output files. - - Finally click {guilabel}`Save`. -1. Under {guilabel}`Build & deploy > Continuous deployment`, scroll to {guilabel}`Branches and deploy contexts`, and click {guilabel}`Configure`, then enter appropriate values. +## Pull request preview builds + +To preview pull request builds of documentation or Storybooks on Read the Docs, you need to configure your project's repository and import it into Read the Docs. +You also need an account on Read the Docs and have write access to the repository. + + +### Configuration files + +The following are example files that you can use to configure your project for pull request previews on Read the Docs. + +- [Plone Sphinx Theme `Makefile`](https://github.com/plone/plone-sphinx-theme/blob/main/Makefile), specifically the `rtd-pr-preview` section. + This is the command to use to build documentation previews on Read the Docs. +- [Plone Sphinx Theme `requirements-initial.txt`](https://github.com/plone/plone-sphinx-theme/blob/main/requirements-initial.txt) specifies the initial Python packaging tool requirements to set up a virtual environment. +- [Plone Sphinx Theme `requirements-docs.txt`](https://github.com/plone/plone-sphinx-theme/blob/main/requirements-docs.txt) specifies the requirements to use Plone Sphinx Theme and build the docs. +- [Plone Sphinx Theme `conf.py`](https://github.com/plone/plone-sphinx-theme/blob/main/docs/conf.py) the Sphinx configuration file to build the docs. +- [Plone Sphinx Theme `.readthedocs.yaml`](https://github.com/plone/plone-sphinx-theme/blob/main/.readthedocs.yaml) specifies the configuration and command to build the docs. +- [Plone Sphinx Theme `.github/workflows/rtd-pr-preview.yml`](https://github.com/plone/plone-sphinx-theme/blob/main/.github/workflows/rtd-pr-preview.yml) specifies when to build the docs, specifically only when a pull request is opened against the `main` branch and there are changes to documentation files. + You might need to adjust the branch name, paths, and files to check for changes. + + +### Import your project + +After logging in to your Read the Docs account, you can import your project. + +1. Click {guilabel}`Add project`. +1. For {guilabel}`Repository name`, enter the GitHub organization, a forward slash, and the repository to import, for example, `plone/volto`. +1. Click {guilabel}`Continue`. +1. In the {guilabel}`Add project` screen, you can configure basic project settings, including its {guilabel}`Name`, {guilabel}`Repository URL`, {guilabel}`Default branch`, and {guilabel}`Language`. + The defaults are usually accurate. +1. Click {guilabel}`Next`. +1. A sample `.readthedocs.yaml` file is suggested, if you have not already added one. +1. Click {guilabel}`Finish`. + Read the Docs will redirect you to the project details, and start building the docs. + + +### Search engine indexing + +Many Plone projects currently self-host their official documentation at {doc}`/index`. +These projects get indexed by search engines. + +For pull request previews, unsupported branches or versions, or other situations, you most likely do not want search engines to index your documentation. +Your options include the following. + +- Deactivate your build +- Hide your build +- Create a custom {file}`robots.txt` file to discourage, but not absolutely prevent, search engine indexing + +For the last option, you can configure Sphinx to copy the {file}`robots.txt` file. +However, if you want to have two versions of a {file}`robots.txt` file—say one that allows indexing of your official documentation and another that discourages indexing—you can configure your automation to copy it into place with a command such as the following. + +```shell +cp source-path/block-robots.txt docs-root-path/robots.txt +``` + +```{seealso} +- [Automation rules](https://docs.readthedocs.io/en/stable/automation-rules.html) +- [Versions](https://docs.readthedocs.io/en/stable/versions.html) +- [Managing versions automatically](https://docs.readthedocs.io/en/stable/guides/automation-rules.html) +- [`robots.txt` support](https://docs.readthedocs.io/en/stable/reference/robots.html) +``` + + +### Cancel builds programmatically + +You might want to cancel a build programmatically when certain conditions are met. +You can do this through your {file}`.readthedocs.yaml` file. +Read the Docs covers a few scenarios in its documentation, [Cancel build based on a condition](https://docs.readthedocs.io/en/stable/build-customization.html#cancel-build-based-on-a-condition). + + +#### Build only on changes + +When there are no changes to documentation, it is not necessary to build it. +You can save time and energy by programmatically building documentation only when it changes. + +In your {file}`.readthedocs.yaml` file, you could use the following example. + +```yaml +version: 2 +build: + os: "ubuntu-22.04" + tools: + python: "3.12" + jobs: + post_checkout: + # Cancel building pull requests when there aren't changes in the docs directory or YAML file. + # You can add any other files or directories that you'd like here as well, + # like your docs requirements file, or other files that will change your docs build. + # + # If there are no changes (git diff exits with 0) we force the command to return with 183. + # This is a special exit code on Read the Docs that will cancel the build immediately. + - | + if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && git diff --quiet origin/main -- docs/ .readthedocs.yaml requirements-initial.txt requirements.txt; + then + exit 183; + fi +``` + + +#### Cancel builds on a branch + +If you have pull request preview builds enabled, any pull request to any branch will trigger a build. +If you do not want to build documentation on a specific branch, you can cancel a build programmatically through your {file}`.readthedocs.yaml` file. + +```yaml +version: 2 +build: + os: "ubuntu-22.04" + tools: + python: "3.12" + jobs: + post_checkout: + # Cancel the Read the Docs build + # https://docs.readthedocs.io/en/stable/build-customization.html#cancel-build-based-on-a-condition + - exit 183; +``` From d2d7db179de2ece5b57bd92d2469b4cf622d1044 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 21 Jun 2024 02:45:59 -0700 Subject: [PATCH 289/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index b844f3149..50bba48a5 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit b844f3149459f472837ac69ea204bdd90d5557e0 +Subproject commit 50bba48a5468cd6c102b8e26dd62b55d1bb1e37b From 51241440ed3150695beed85e61c3334b7789ed82 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 21 Jun 2024 03:11:44 -0700 Subject: [PATCH 290/810] bin/wsgi no workie --- docs/contributing/core/index.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index de83cbb98..31740b408 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -90,12 +90,6 @@ Once that's done, you can start an instance of Plone with the following command. ./bin/instance fg ``` -Alternatively, you can start Plone as a {term}`WSGI` service with the following command. - -```shell -./bin/wsgi -``` - To visit your Plone instance, you can open the link http://0.0.0.0:8080 in a web browser. Click {guilabel}`View your Plone site` to do exactly that. From ef84d0544d9dda5cf1fddce43832941a01984da1 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 21 Jun 2024 03:21:39 -0700 Subject: [PATCH 291/810] Update commit message --- docs/contributing/core/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 31740b408..cbf2c339c 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -139,7 +139,7 @@ Next create a new branch on which you want to work from the current branch, trac It's a good idea to use a branch name that includes the issue number and is descriptive of what it resolves. ```shell -git switch -c 123-my-branch-name -t origin/6.1 +git switch -c 123-thing-i-fixed -t origin/6.1 ``` Now you can edit your code without affecting the original branch. From b3f234761f12b845a70e92f2ce37b3451fb8ab7a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 21 Jun 2024 04:30:02 -0700 Subject: [PATCH 292/810] Update mrdeveloper.md --- docs/contributing/core/mrdeveloper.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/contributing/core/mrdeveloper.md b/docs/contributing/core/mrdeveloper.md index ce14a624d..db4b0aabf 100644 --- a/docs/contributing/core/mrdeveloper.md +++ b/docs/contributing/core/mrdeveloper.md @@ -4,30 +4,30 @@ myst: "description": "mr.developer" "property=og:description": "mr.developer" "property=og:title": "mr.developer" - "keywords": "mr.developer" + "keywords": "Plone, buildout, mr.developer" --- # `mr.developer` -This buildout uses `mr.developer` to manage package development. -See [mr.developer on pypi](https://pypi.org/project/mr.developer/) for more information, or run `bin/develop help` for a list of available commands. +Plone core uses `mr.developer` to manage package development. +See [`mr.developer` on PyPI](https://pypi.org/project/mr.developer/) for more information, or run `bin/develop help` for a list of available commands. -The most common workflow to get all the latest updates is: +To get all the latest updates, use the following commands. ```shell git pull bin/develop rebuild ``` -This will get you the latest `coredev` configuration, checkout and update all packages via git in src, and run buildout to configure the whole thing. +This will get you the latest `coredev` configuration, check out and update all packages via git in {file}`src`, and run buildout to configure the whole thing. -From time to time you can check if some old cruft has accumulated: +From time to time you can check if some old cruft has accumulated. ```shell bin/develop status ``` -If this prints any lines with a question mark in front, you can cleanup by: +If this prints any lines with a question mark in front, you can clean the cruft with the following command. ```shell bin/develop purge From 6f92024bd3c0cd683ce9cf03aa8cceee5d137d43 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 21 Jun 2024 04:41:52 -0700 Subject: [PATCH 293/810] Update package-dependencies.md, reverting whitespace changes --- .../contributing/core/package-dependencies.md | 508 +++++++++--------- 1 file changed, 259 insertions(+), 249 deletions(-) diff --git a/docs/contributing/core/package-dependencies.md b/docs/contributing/core/package-dependencies.md index d2270a395..de5c10c23 100644 --- a/docs/contributing/core/package-dependencies.md +++ b/docs/contributing/core/package-dependencies.md @@ -11,30 +11,32 @@ myst: This chapter describes the architecture of Plone's packages and dependencies. + ## Motivation -Plone has over the years developed many indirections in its packages and dependencies. +Over the years, Plone has developed many indirections in its packages and dependencies. The goal in the long run is to untangle them and get a simple dependency graph. -This document shows the current state, as orientation. +This document shows the current state, as an orientation to its architecture. + ## Overview There are multiple level of dependencies: -- package level (`setup.py`/`setup.cfg`/`pyproject.toml`) -- Python level (imports) -- ZCML level (includes) -- testing (need for layers, such as functional testing) +- package level (`setup.py`/`setup.cfg`/`pyproject.toml`) +- Python level (imports) +- ZCML level (includes) +- testing (need for layers, such as functional testing) -At some point there were circular dependencies at the package level. -This was solved. +Circular dependencies at the package level have now been resolved. Nevertheless there is indirection on all other levels. Since Plone consists of a lot of packages, it is complex to untangle those. + ## Mental model -A base mental model for how Plone is organized in Plone 6 is shown in the following diagram: +A base mental model for how Plone is organized in Plone 6, and is shown in the following diagram: ```{mermaid} block-beta @@ -45,11 +47,11 @@ block-beta Distributions block:dist plone.volto - plone.classic + plone.classicui end space block:core - coreaddons["Core addons"] + coreaddons["Core add-ons"] coreapi["Core APIs"] end space @@ -86,265 +88,273 @@ space ``` -As a rough model there are two packages as dividing lines: +As a rough model, there are two packages as dividing lines: + +1. `Products.CMFPlone` +2. `plone.base` -1. `Products.CMFPlone` -2. `plone.base` ## Packages in detail -Looking deeper into those, there are more sub-dividers, but first group all into the three groups: +Looking deeper into those packages, there are more sub-divisions, but first we place them into three groups: + ### Above `Products.CMFPlone` -- Plone -- plone.api -- plone.app.iterate -- plone.app.upgrade -- plone.restapi -- plone.volto -- Products.CMFPlacefulWorkflow +- Plone +- plone.api +- plone.app.iterate +- plone.app.upgrade +- plone.restapi +- plone.volto +- Products.CMFPlacefulWorkflow + ### Between `Products.CMFPlone` and `plone.base` -- collective.monkeypatcher -- plone.app.caching -- plone.app.content -- plone.app.contentlisting -- plone.app.contentmenu -- plone.app.contentrules -- plone.app.contenttypes -- plone.app.customerize -- plone.app.dexterity -- plone.app.discussion -- plone.app.event -- plone.app.i18n -- plone.app.intid -- plone.app.layout -- plone.app.linkintegrity -- plone.app.locales -- plone.app.lockingbehavior -- plone.app.multilingual -- plone.app.portlets -- plone.app.querystring -- plone.app.redirector -- plone.app.registry -- plone.app.relationfield -- plone.app.textfield -- plone.app.theming -- plone.app.users -- plone.app.uuid -- plone.app.versioningbehavior -- plone.app.viewletmanager -- plone.app.vocabularies -- plone.app.widgets -- plone.app.workflow -- plone.app.z3cform -- plone.browserlayer -- plone.cachepurging -- plone.contentrules -- plone.formwidget.namedfile -- plone.formwidget.recurrence -- plone.i18n -- plone.namedfile -- plone.outputfilters -- plone.portlet.collection -- plone.portlet.static -- plone.portlets -- plone.protect -- plone.resourceeditor -- plone.rfc822 -- plone.schemaeditor -- plone.session -- plone.staticresources -- plone.stringinterp -- plone.theme -- plonetheme.barceloneta -- Products.isurlinportal +- collective.monkeypatcher +- plone.app.caching +- plone.app.content +- plone.app.contentlisting +- plone.app.contentmenu +- plone.app.contentrules +- plone.app.contenttypes +- plone.app.customerize +- plone.app.dexterity +- plone.app.discussion +- plone.app.event +- plone.app.i18n +- plone.app.intid +- plone.app.layout +- plone.app.linkintegrity +- plone.app.locales +- plone.app.lockingbehavior +- plone.app.multilingual +- plone.app.portlets +- plone.app.querystring +- plone.app.redirector +- plone.app.registry +- plone.app.relationfield +- plone.app.textfield +- plone.app.theming +- plone.app.users +- plone.app.uuid +- plone.app.versioningbehavior +- plone.app.viewletmanager +- plone.app.vocabularies +- plone.app.widgets +- plone.app.workflow +- plone.app.z3cform +- plone.browserlayer +- plone.cachepurging +- plone.contentrules +- plone.formwidget.namedfile +- plone.formwidget.recurrence +- plone.i18n +- plone.namedfile +- plone.outputfilters +- plone.portlet.collection +- plone.portlet.static +- plone.portlets +- plone.protect +- plone.resourceeditor +- plone.rfc822 +- plone.schemaeditor +- plone.session +- plone.staticresources +- plone.stringinterp +- plone.theme +- plonetheme.barceloneta +- Products.isurlinportal + ### The foundation below `plone.base` + #### Plone world -- borg.localrole -- plone.alterego -- plone.autoform -- plone.autoinclude -- plone.batching -- plone.behavior -- plone.caching -- plone.dexterity -- plone.event -- plone.folder -- plone.indexer -- plone.intelligenttext -- plone.keyring -- plone.locking -- plone.memoize -- plone.registry -- plone.resource -- plone.rest -- plone.scale -- plone.schema -- plone.subrequest -- plone.supermodel -- plone.transformchain -- plone.uuid -- plone.z3cform -- Products.DateRecurringIndex -- Products.ExtendedPathIndex -- Products.MimetypesRegistry -- Products.PlonePAS -- Products.PortalTransforms -- Products.statusmessages +- borg.localrole +- plone.alterego +- plone.autoform +- plone.autoinclude +- plone.batching +- plone.behavior +- plone.caching +- plone.dexterity +- plone.event +- plone.folder +- plone.indexer +- plone.intelligenttext +- plone.keyring +- plone.locking +- plone.memoize +- plone.registry +- plone.resource +- plone.rest +- plone.scale +- plone.schema +- plone.subrequest +- plone.supermodel +- plone.transformchain +- plone.uuid +- plone.z3cform +- Products.DateRecurringIndex +- Products.ExtendedPathIndex +- Products.MimetypesRegistry +- Products.PlonePAS +- Products.PortalTransforms +- Products.statusmessages + #### Zope ecosystem -- Chameleon -- diazo -- five.customerize -- five.intid -- five.localsitemanager -- icalendar -- Products.CMFCore -- Products.CMFDiffTool -- Products.CMFDynamicViewFTI -- Products.CMFEditions -- Products.CMFUid -- Products.DCWorkflow -- Products.ExternalMethod -- Products.GenericSetup -- Products.MailHost -- Products.PluggableAuthService -- Products.PluginRegistry -- Products.PythonScripts -- Products.Sessions -- Products.SiteErrorLog -- Products.StandardCacheManagers -- Products.ZopeVersionControl -- repoze.xmliter -- webresource -- z3c.caching -- z3c.form -- z3c.formwidget.query -- z3c.objpath -- z3c.pt -- z3c.relationfield -- z3c.zcmlhook -- zc.recipe.egg -- zc.relation -- zodbverify -- zope.copy -- zope.intid -- zope.keyreference +- Chameleon +- diazo +- five.customerize +- five.intid +- five.localsitemanager +- icalendar +- Products.CMFCore +- Products.CMFDiffTool +- Products.CMFDynamicViewFTI +- Products.CMFEditions +- Products.CMFUid +- Products.DCWorkflow +- Products.ExternalMethod +- Products.GenericSetup +- Products.MailHost +- Products.PluggableAuthService +- Products.PluginRegistry +- Products.PythonScripts +- Products.Sessions +- Products.SiteErrorLog +- Products.StandardCacheManagers +- Products.ZopeVersionControl +- repoze.xmliter +- webresource +- z3c.caching +- z3c.form +- z3c.formwidget.query +- z3c.objpath +- z3c.pt +- z3c.relationfield +- z3c.zcmlhook +- zc.recipe.egg +- zc.relation +- zodbverify +- zope.copy +- zope.intid +- zope.keyreference + #### Zope core -- AccessControl -- Acquisition -- AuthEncoding -- beautifulsoup4 -- BTrees -- DateTime -- DocumentTemplate -- ExtensionClass -- Missing -- MultiMapping -- Persistence -- persistent -- Products.BTreeFolder2 -- Products.ZCatalog -- Record -- RestrictedPython -- transaction -- zc.lockfile -- ZConfig -- zdaemon -- ZEO -- zExceptions -- ZODB -- ZODB3 -- zodbpickle -- Zope -- zope.annotation -- zope.app.locales -- zope.browser -- zope.browsermenu -- zope.browserpage -- zope.browserresource -- zope.cachedescriptors -- zope.component -- zope.componentvocabulary -- zope.configuration -- zope.container -- zope.contentprovider -- zope.contenttype -- zope.datetime -- zope.deferredimport -- zope.deprecation -- zope.dottedname -- zope.event -- zope.exceptions -- zope.filerepresentation -- zope.globalrequest -- zope.hookable -- zope.i18n -- zope.i18nmessageid -- zope.interface -- zope.lifecycleevent -- zope.location -- zope.pagetemplate -- zope.processlifetime -- zope.proxy -- zope.ptresource -- zope.publisher -- zope.ramcache -- zope.schema -- zope.security -- zope.sendmail -- zope.sequencesort -- zope.site -- zope.size -- zope.structuredtext -- zope.tal -- zope.tales -- zope.testbrowser -- zope.testing -- zope.traversing -- zope.viewlet -- Zope2 +- AccessControl +- Acquisition +- AuthEncoding +- beautifulsoup4 +- BTrees +- DateTime +- DocumentTemplate +- ExtensionClass +- Missing +- MultiMapping +- Persistence +- persistent +- Products.BTreeFolder2 +- Products.ZCatalog +- Record +- RestrictedPython +- transaction +- zc.lockfile +- ZConfig +- zdaemon +- ZEO +- zExceptions +- ZODB +- ZODB3 +- zodbpickle +- Zope +- zope.annotation +- zope.app.locales +- zope.browser +- zope.browsermenu +- zope.browserpage +- zope.browserresource +- zope.cachedescriptors +- zope.component +- zope.componentvocabulary +- zope.configuration +- zope.container +- zope.contentprovider +- zope.contenttype +- zope.datetime +- zope.deferredimport +- zope.deprecation +- zope.dottedname +- zope.event +- zope.exceptions +- zope.filerepresentation +- zope.globalrequest +- zope.hookable +- zope.i18n +- zope.i18nmessageid +- zope.interface +- zope.lifecycleevent +- zope.location +- zope.pagetemplate +- zope.processlifetime +- zope.proxy +- zope.ptresource +- zope.publisher +- zope.ramcache +- zope.schema +- zope.security +- zope.sendmail +- zope.sequencesort +- zope.site +- zope.size +- zope.structuredtext +- zope.tal +- zope.tales +- zope.testbrowser +- zope.testing +- zope.traversing +- zope.viewlet +- Zope2 + #### Libraries -- attrs -- cffi -- cssselect -- decorator -- docutils -- feedparser -- future -- importlib_metadata -- jsonschema -- Markdown -- multipart -- Paste -- PasteDeploy -- piexif -- Pillow -- pycparser -- PyJWT -- pyrsistent -- python_dotenv -- python_gettext -- requests -- roman -- sgmllib3k -- simplejson -- soupsieve -- Unidecode -- urllib3 -- waitress -- WebOb -- WebTest -- WSGIProxy2 -- zipp +- attrs +- cffi +- cssselect +- decorator +- docutils +- feedparser +- future +- importlib_metadata +- jsonschema +- Markdown +- multipart +- Paste +- PasteDeploy +- piexif +- Pillow +- pycparser +- PyJWT +- pyrsistent +- python_dotenv +- python_gettext +- requests +- roman +- sgmllib3k +- simplejson +- soupsieve +- Unidecode +- urllib3 +- waitress +- WebOb +- WebTest +- WSGIProxy2 +- zipp From 57cd6fdd4d302ec4f1dbc579d983d7c303847c3a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 21 Jun 2024 04:49:49 -0700 Subject: [PATCH 294/810] Revert whitespace changes, restore TODO --- docs/contributing/core/plip-review.md | 65 ++++++++++++++++----------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/docs/contributing/core/plip-review.md b/docs/contributing/core/plip-review.md index 670838c93..aa979067d 100644 --- a/docs/contributing/core/plip-review.md +++ b/docs/contributing/core/plip-review.md @@ -11,14 +11,16 @@ myst: A Plone Improvement Proposal (PLIP) is a formal process to propose a change to improve Plone. + ## Expectations A good PLIP review takes about four hours. Please plan accordingly. -When you are done, if you have access to core, commit the review to the `plips` folder of [buildout.coredev](https://github.com/plone/buildout.coredev), and reference the PLIP in your commit message. +When you are done, if you have access to core, commit the review to the `plips` folder of [`buildout.coredev`](https://github.com/plone/buildout.coredev), and reference the PLIP in your commit message. If you do not have access, attach your review to the PLIP ticket itself. + ## Setting up the environment Follow the instructions in {doc}`index`. @@ -29,44 +31,48 @@ Instead of running the buildout with the default buildout file, you will run the ./bin/buildout -c plips/plip-XXXX.cfg ``` + ## Functionality review This section describes the topics that may be addressed in a PLIP review, depending on the nature of the PLIP itself. + ### General -- Does the PLIP actually do what the implementers proposed? +- Does the PLIP actually do what the implementers proposed? Are there incomplete variations? -- Were there any errors running buildout? +- Were there any errors running buildout? Did the migration(s) work? -- Do error and status messages make sense? +- Do error and status messages make sense? Are they properly internationalized? -- Are there any performance considerations? +- Are there any performance considerations? Has the implementer addressed them, if so? -- For changes in the UI, are they accessible for people using assisted technologies? + ### Bugs -- Are there any bugs? +- Are there any bugs? Nothing is too big nor small. -- Do fields handle wacky, incomplete or harmful data? +- Do fields handle wacky data? How about strings in date fields, or nulls in required? -- Is validation up to snuff and sensical? +- Is validation up to snuff and sensical? Is it too restrictive or not restrictive enough? + ### Usability Issues -- Is the implementation usable? -- How will novice end users respond to the change? -- Does this PLIP need a usability review? +- Is the implementation usable? +- How will novice end users respond to the change? +- Does this PLIP need a usability review? If you think this PLIP needs a usability review, change the state to "please review" and add a note in the comments. -- Is the PLIP consistent with the rest of Plone? +- Is the PLIP consistent with the rest of Plone? For example, if there is control panel configuration, does the new form fit in with the rest of the panels? -- Does everything flow nicely for novice and advanced users? +- Does everything flow nicely for novice and advanced users? Is there any workflow that feels odd? -- Are there any new permissions and do they work properly? +- Are there any new permissions and do they work properly? Does their role assignment make sense? + ### Documentation Issues - Is the corresponding documentation for the end user, be it developer or Plone user, sufficient? @@ -78,24 +84,33 @@ This way the implementer can find help if they need it. Also set a priority for the ticket. The PLIP will not be merged until all blockers and critical bugs are fixed. + ### Code Review + #### Python -- Is this code maintainable? -- Is the code properly documented? -- Does the code adhere to Plone best practices for formatting? -- Are they importing deprecated modules? +- Is this code maintainable? +- Is the code properly documented? +- Does the code adhere to PEP8 standards (more or less)? +- Are they importing deprecated modules? + #### JavaScript -- Does the JavaScript meet Plone's set of JavaScript standards? -- Does the JavaScript work in all currently supported browsers? +- Does the JavaScript meet our set of JavaScript standards? + See our section about [JavaScript](https://5.docs.plone.org/develop/addons/javascript/index.html) and the [JavaScript Style Guide](https://5.docs.plone.org/develop/styleguide/javascript.html). +- Does the JavaScript work in all currently supported browsers? Is it performant? +```{todo} +Update links from Plone 5 Documentation to Plone 6 Documentation, when they exist. +See https://github.com/plone/documentation/issues/1330 +``` + #### ME/TAL -- Does the PLIP use views appropriately, avoiding too much logic? -- Is there any code in a loop that could potentially be a performance issue? -- Are there any deprecated or old style ME/TAL lines of code, such as using `DateTime`? -- Is the rendered HTML compliant with standards? Are IDs and classes used appropriately? +- Does the PLIP use views appropriately, avoiding too much logic? +- Is there any code in a loop that could potentially be a performance issue? +- Are there any deprecated or old style ME/TAL lines of code, such as using `DateTime`? +- Is the rendered HTML compliant with standards? Are IDs and classes used appropriately? From e626b6569505c14e0a86e1d4ad819530031e7d61 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 21 Jun 2024 05:07:38 -0700 Subject: [PATCH 295/810] Revert whitespace muckery --- docs/contributing/core/plips.md | 58 ++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index 7f7b766d9..ed8e9e859 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -15,10 +15,12 @@ It is a change to a Plone package that would affect everyone. PLIPs go through a different process than bug fixes because of their broad reach. The Plone Framework Team reviews all PLIPs to make sure that it's in the best interest of the broader community, and that it's of high quality. + ## Frequently asked questions about PLIPs This section provides detailed answers to common questions about PLIPs. + ### PLIP or bugfix? In general, anything that changes the API of Plone in the backend or the user interface (UI) on the front end should be filed as a PLIP. @@ -27,6 +29,7 @@ The Framework Team will reclassify it if your proposal falls below the threshold If the change you are proposing is not in the scope of a PLIP, a GitHub pull request or issue is the right format. The key point here is that each change must be documented, allowing it to be tracked and understood. + ### Who can submit PLIPs? Anyone who has signed a Plone Contributor Agreement can work on a PLIP. @@ -51,10 +54,10 @@ They are there to help you through completion, answer questions and provide guid A champion fulfills the following tasks: -- Answer any questions the PLIP implementer has, technical or otherwise. -- Encourage the PLIP author by giving feedback and encouragement. -- Keep the implementer aware of timelines, and push to get things done on time. -- Assist with finding additional help when needed to complete the implementation in a timely matter. +- Answer any questions the PLIP implementor has, technical or otherwise. +- Encourage the PLIP author by constantly giving feedback and encouragement. +- Keep the implementer aware of timelines, and push to get things done on time. +- Assist with finding additional help when needed to complete the implementation in a timely matter. Keep in mind that champions are volunteers as well, and have other tasks in life. That means you will have to play an active role in asking for help or guidance. @@ -72,12 +75,14 @@ Then, follow the instructions for {doc}`reviewing a PLIP `. Thank you in advance! + ### When can I submit a PLIP? Today, tomorrow, any time! After the PLIP is accepted, the Framework Team will try to judge complexity and time to completion, and assign it to a milestone. + ### When is the PLIP due? **Summary: As soon as you get it done.** @@ -87,27 +92,30 @@ Sometimes life gets in the way, and a PLIP may have to be re-assigned to the fol In general, PLIPs shouldn't take more than a year, otherwise they should be closed. A new PLIP can follow up if there is more capacity to see it through. + ### What happens if your PLIP is not accepted? If a PLIP isn't accepted in core, it doesn't mean it's a bad idea. It is often the case that there are competing implementations, and the community wants to see it vetted as an add-on before "blessing" a particular implementation. + ## Process Overview -1. Submit a PLIP at any time. -2. PLIP is approved for inclusion into core for a given release. -3. Developer implements PLIP (code, tests, documentation). -4. PLIP is submitted for review by developer. -5. Framework Team reviews the PLIP and gives feedback. -6. Developer addresses concerns in feedback and re-submits the PLIP, if necessary. -7. This may go back and forth a few times, until both the Framework Team and developer are happy with the result. -8. PLIP is approved for merge. +1. Submit a PLIP at any time. +2. PLIP is approved for inclusion into core for a given release. +3. Developer implements PLIP (code, tests, documentation). +4. PLIP is submitted for review by developer. +5. Framework Team reviews the PLIP and gives feedback. +6. Developer addresses concerns in feedback and re-submits the PLIP, if necessary. +7. This may go back and forth a few times, until both the Framework Team and developer are happy with the result. +8. PLIP is approved for merge. In rare circumstances, a PLIP will be rejected. This is usually the result of the developer not responding to feedback or dropping out of the process. Hang in there! -9. After all other PLIPs are merged, a release is cut. +9. After all other PLIPs are merged, a release is cut. Standby for bugs! + (how-to-submit-a-plip)= ## How to submit a PLIP @@ -137,15 +145,16 @@ Others may be able to point out risks or even offer up better or existing soluti Please note a few things: -- It is very rare that the "Risks" section will be empty or none. -- If you find this is the case, and your PLIP is anything more than trivial, maybe some more vetting should be done. -- The seconder field is REQUIRED. +- It is very rare that the "Risks" section will be empty or none. +- If you find this is the case, and your PLIP is anything more than trivial, maybe some more vetting should be done. +- The seconder field is REQUIRED. The PLIP will be sent back to you if it is not filled in. Currently, this is just someone else who thinks your PLIP is a good idea, a +1. In the near future, the seconder should either a coding partner, or someone who is willing and able to finish the PLIP should something happen to the implementer. + ### Evaluating PLIPs After you submit your PLIP, the Framework Team will meet within a couple weeks, and let you know if the PLIP is accepted. @@ -158,19 +167,21 @@ Please keep your eyes and inbox open for changes. These are the criteria by which the framework team will review your work: -- What is the size and status of the work needed to be done? -- Is it already an add-on and well established? -- Is this idea well baked and expressed clearly? -- Does the work proposed belong in Plone now, or in the future? -- Is this PLIP more appropriate as a qualified add-on? -- Is this PLIP too risky? +- What is size and status of the work needed to be done? +- Is it already an add-on and well established? +- Is this idea well baked and expressed clearly? +- Does the work proposed belong in Plone now, or in the future? +- Is this PLIP more appropriate as a qualified add-on? +- Is this PLIP too risky? See the {doc}`plip-review` page for more information. + ## Implementing your PLIP You can start the development at any time, but if you are going to modify Plone itself, it is a good idea to wait to see if your idea is approved. + ### General Rules - Any new packages must be in a branch in the `plone` namespace in GitHub. @@ -189,6 +200,7 @@ Update links from Plone 5 to Plone 6 Documentation, once content is migrated. See https://github.com/plone/documentation/issues/1330 and other issues. ``` + ### Creating a new PLIP branch Create a buildout configuration file for your PLIP in the `plips` folder of {file}`buildout.coredev`. @@ -224,6 +236,7 @@ zcml += Use the same naming convention when you branch existing packages. You should always branch packages when working on PLIPs. + ### Working on a PLIP To work on a PLIP, you bootstrap buildout, and then invoke buildout with your PLIP configuration: @@ -250,6 +263,7 @@ installed = .installed.cfg var = ./var ``` + ### Finishing up Before marking your PLIP as ready for review, please add a file to give a set of instructions to the PLIP reviewer. From a79fe1fb975f7576029961ce07bcbc9e3100594d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 22 Jun 2024 05:30:02 -0700 Subject: [PATCH 296/810] Revise and make recommendations in plips.md to remove coaching and focus on how to do things. --- docs/contributing/core/plips.md | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index ed8e9e859..7272c8994 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -9,9 +9,7 @@ myst: # Plone Improvement Proposals (PLIPs) -A {term}`PLIP` is a Plone Improvement Proposal. - -It is a change to a Plone package that would affect everyone. +A Plone Improvement Proposal, or {term}`PLIP`, is a change to a Plone package that would affect everyone. PLIPs go through a different process than bug fixes because of their broad reach. The Plone Framework Team reviews all PLIPs to make sure that it's in the best interest of the broader community, and that it's of high quality. @@ -34,23 +32,25 @@ The key point here is that each change must be documented, allowing it to be tra Anyone who has signed a Plone Contributor Agreement can work on a PLIP. -You do not have to be the most amazing coder in the world to submit a PLIP. +```{todo} +The FWT no longer participates in PLIPs. +Recommend deletion of next two paragraphs. +``` The Framework Team is happy to help you at any point in the process. -Submitting a PLIP can be a great learning process. - When the PLIP is accepted, a Framework Team member will "champion" your PLIP and follow up to its completion. -PLIPs are not just for code experts. -If you have ideas on new interactions or UI your ideas are more than welcome. - -The community will help you pair up with implementers if needed. ### What is a PLIP champion? +```{todo} +This section is no longer in practice. +Recommend deletion. +``` + When you submit your PLIP and it is approved, a Framework Team member will take on the role of champion for that PLIP. -They are there to help you through completion, answer questions and provide guidance. +They are there to help you through completion, answer questions, and provide guidance. A champion fulfills the following tasks: @@ -62,19 +62,15 @@ A champion fulfills the following tasks: Keep in mind that champions are volunteers as well, and have other tasks in life. That means you will have to play an active role in asking for help or guidance. + ### Can I get involved in other ways? If you want to experience the process and how it works, help us review PLIPs as the implementations finish up. -Ask one of the Framework Team members what PLIPs are available for review, or check the status of PLIPs at the [GitHub issues](https://github.com/plone/Products.CMFPlone/issues) page -for [Products.CMFPlone](https://github.com/Plone/Products.CMFPlone) -for [issues tagged with "03 type: feature (plip)"](https://github.com/plone/Products.CMFPlone/labels/03%20type%3A%20feature%20%28plip%29). -Make sure to let the community know you intend to review the PLIP by communicating that to the [Framework Team](https://community.plone.org/c/development/framework-team). +Check the status of PLIPs at https://github.com/search?q=path%3A%2Fplone+label%3A%2203+type%3A+feature+%28plip%29%22++&type=issues&ref=advsearch&state=open. Then, follow the instructions for {doc}`reviewing a PLIP `. -Thank you in advance! - ### When can I submit a PLIP? From ea65b7ce484e727b1b7acad40b1f903023519279 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 22 Jun 2024 16:46:39 -0700 Subject: [PATCH 297/810] Move FAQ to the end to elevate the process overview. Revise process overview without the FWT, as it appears to be an ex-FWT, or possibly just pining for the fjords. --- docs/contributing/core/plips.md | 201 ++++++++++++++++---------------- 1 file changed, 101 insertions(+), 100 deletions(-) diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index 7272c8994..6b880840d 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -9,117 +9,35 @@ myst: # Plone Improvement Proposals (PLIPs) -A Plone Improvement Proposal, or {term}`PLIP`, is a change to a Plone package that would affect everyone. -PLIPs go through a different process than bug fixes because of their broad reach. +A Plone Improvement Proposal, or {term}`PLIP`, is a change to a Plone package that would affect everyone who uses that package. +PLIPs go through a formal process compared to bug fixes because of their broad reach. The Plone Framework Team reviews all PLIPs to make sure that it's in the best interest of the broader community, and that it's of high quality. -## Frequently asked questions about PLIPs - -This section provides detailed answers to common questions about PLIPs. +## Process overview +1. Developer submits a PLIP. +2. [Some indeterminate team?] approves the PLIP for inclusion into Plone core for a given release. +3. Developer implements the PLIP, including code, tests, and documentation. +4. Developer creates a pull request of the PLIP for review by the team. +5. [Some indeterminate team?] reviews the PLIP and gives feedback. +6. Developer addresses concerns from the feedback, and resubmits the PLIP, if necessary. +7. Repeat the two previous steps, until both the [Some indeterminate team?] and developer are happy with the result. +8. [Somebody] approves the PLIP for merge. +9. [Somebody] merges the PLIP. -### PLIP or bugfix? +In rare circumstances, a PLIP may be rejected. +This is usually the result of the developer not responding to feedback or dropping out of the process. -In general, anything that changes the API of Plone in the backend or the user interface (UI) on the front end should be filed as a PLIP. -When in doubt, submit it as a PLIP. -The Framework Team will reclassify it if your proposal falls below the threshold. -If the change you are proposing is not in the scope of a PLIP, a GitHub pull request or issue is the right format. -The key point here is that each change must be documented, allowing it to be tracked and understood. - - -### Who can submit PLIPs? - -Anyone who has signed a Plone Contributor Agreement can work on a PLIP. - -```{todo} -The FWT no longer participates in PLIPs. -Recommend deletion of next two paragraphs. -``` -The Framework Team is happy to help you at any point in the process. - -When the PLIP is accepted, a Framework Team member will "champion" your PLIP and follow up to its completion. +(submit-a-plip)= -### What is a PLIP champion? - -```{todo} -This section is no longer in practice. -Recommend deletion. -``` - -When you submit your PLIP and it is approved, a Framework Team member will take on the role of champion for that PLIP. - -They are there to help you through completion, answer questions, and provide guidance. - -A champion fulfills the following tasks: - -- Answer any questions the PLIP implementor has, technical or otherwise. -- Encourage the PLIP author by constantly giving feedback and encouragement. -- Keep the implementer aware of timelines, and push to get things done on time. -- Assist with finding additional help when needed to complete the implementation in a timely matter. - -Keep in mind that champions are volunteers as well, and have other tasks in life. -That means you will have to play an active role in asking for help or guidance. - - -### Can I get involved in other ways? - -If you want to experience the process and how it works, help us review PLIPs as the implementations finish up. - -Check the status of PLIPs at https://github.com/search?q=path%3A%2Fplone+label%3A%2203+type%3A+feature+%28plip%29%22++&type=issues&ref=advsearch&state=open. - -Then, follow the instructions for {doc}`reviewing a PLIP `. - - -### When can I submit a PLIP? - -Today, tomorrow, any time! - -After the PLIP is accepted, the Framework Team will try to judge complexity and time to completion, and assign it to a milestone. - - -### When is the PLIP due? - -**Summary: As soon as you get it done.** - -Ideally, a PLIP should be completed for the release to which it's assigned. -Sometimes life gets in the way, and a PLIP may have to be re-assigned to the following release. - -In general, PLIPs shouldn't take more than a year, otherwise they should be closed. A new PLIP can follow up if there is more capacity to see it through. - - -### What happens if your PLIP is not accepted? - -If a PLIP isn't accepted in core, it doesn't mean it's a bad idea. -It is often the case that there are competing implementations, and the community wants to see it vetted as an add-on before "blessing" a particular implementation. - - -## Process Overview - -1. Submit a PLIP at any time. -2. PLIP is approved for inclusion into core for a given release. -3. Developer implements PLIP (code, tests, documentation). -4. PLIP is submitted for review by developer. -5. Framework Team reviews the PLIP and gives feedback. -6. Developer addresses concerns in feedback and re-submits the PLIP, if necessary. -7. This may go back and forth a few times, until both the Framework Team and developer are happy with the result. -8. PLIP is approved for merge. - In rare circumstances, a PLIP will be rejected. - This is usually the result of the developer not responding to feedback or dropping out of the process. - Hang in there! -9. After all other PLIPs are merged, a release is cut. - Standby for bugs! - - -(how-to-submit-a-plip)= - -## How to submit a PLIP +## Submit a PLIP Whether you want to update the default theme, or rip out a piece of architecture, major changes should go through the PLIP process. -If you need help at any point in this process, please contact a member of the Framework Team personally or ask for help at the [Framework Team Space](https://community.plone.org/c/development/framework-team). +If you need help at any point in this process, please contact a member of the Framework Team personally or ask for help at the [Framework Team Space](https://community.plone.org/c/development/framework-team/12). -A PLIP is a [GitHub issue](https://github.com/plone/Products.CMFPlone/issues/new) on [`Products.CMFPlone`](https://github.com/Plone/Products.CMFPlone) with a special template and a specific tag. +A PLIP is a [GitHub issue](https://github.com/plone/Products.CMFPlone/issues) on [`Products.CMFPlone`](https://github.com/Plone/Products.CMFPlone) with a special template and a specific tag. To get started, open a new issue. The issue will be prefilled with headings and comments for a bug or a PLIP. @@ -284,3 +202,86 @@ During the merge phase you must be prepared to help out with all the features an If all went as planned, the next Plone release will carry on with your PLIP in it. You'll be expected to help out with that feature after it's been released (within reason). + + +## Frequently asked questions about PLIPs + +This section provides detailed answers to common questions about PLIPs. + + +### PLIP or bug fix? + +In general, anything that changes the API of Plone in the backend or the user interface (UI) on the front end should be filed as a PLIP. +When in doubt, submit it as a PLIP. +The Framework Team will reclassify it if your proposal falls below the threshold. +If the change you are proposing is not in the scope of a PLIP, a GitHub pull request or issue is the right format. +The key point here is that each change must be documented, allowing it to be tracked and understood. + + +### Who can submit PLIPs? + +Anyone who has signed a Plone Contributor Agreement can work on a PLIP. + +```{todo} +The FWT no longer participates in PLIPs. +Recommend deletion of next two paragraphs. +``` +The Framework Team is happy to help you at any point in the process. + +When the PLIP is accepted, a Framework Team member will "champion" your PLIP and follow up to its completion. + + +### What is a PLIP champion? + +```{todo} +This section is no longer in practice. +Recommend deletion. +``` + +When you submit your PLIP and it is approved, a Framework Team member will take on the role of champion for that PLIP. + +They are there to help you through completion, answer questions, and provide guidance. + +A champion fulfills the following tasks: + +- Answer any questions the PLIP implementor has, technical or otherwise. +- Encourage the PLIP author by constantly giving feedback and encouragement. +- Keep the implementer aware of timelines, and push to get things done on time. +- Assist with finding additional help when needed to complete the implementation in a timely matter. + +Keep in mind that champions are volunteers as well, and have other tasks in life. +That means you will have to play an active role in asking for help or guidance. + + +### Can I get involved in other ways? + +If you want to experience the process and how it works, help us review PLIPs as the implementations finish up. + +Check the status of PLIPs at https://github.com/search?q=path%3A%2Fplone+label%3A%2203+type%3A+feature+%28plip%29%22++&type=issues&ref=advsearch&state=open. + +Then, follow the instructions for {doc}`reviewing a PLIP `. + + +### When can I submit a PLIP? + +Today, tomorrow, any time! + +After the PLIP is accepted, the Framework Team will try to judge complexity and time to completion, and assign it to a milestone. + + +### When is the PLIP due? + +**Summary: As soon as you get it done.** + +Ideally, a PLIP should be completed for the release to which it's assigned. +Sometimes life gets in the way, and a PLIP may have to be re-assigned to the following release. + +In general, PLIPs shouldn't take more than a year, otherwise they should be closed. A new PLIP can follow up if there is more capacity to see it through. + + +### What happens if your PLIP is not accepted? + +If a PLIP isn't accepted in core, it doesn't mean it's a bad idea. +It is often the case that there are competing implementations, and the community wants to see it vetted as an add-on before "blessing" a particular implementation. + + From d1b54fc1dd9b3c9c290d1fa41d6646588e9d6916 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 22 Jun 2024 16:46:49 -0700 Subject: [PATCH 298/810] Fix linkcheck redirect --- docs/contributing/core/release.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/core/release.md b/docs/contributing/core/release.md index f9eba0c43..76d5d5297 100644 --- a/docs/contributing/core/release.md +++ b/docs/contributing/core/release.md @@ -121,7 +121,7 @@ These are: 14. For Plone 5.x versions only, create the new release on [Launchpad](https://launchpad.net/plone/). 15. Create a release page on [plone.org](https://plone.org/download/releases) 16. Wait for installers to be uploaded to Launchpad, with a link to the [plone.org](https://plone.org/download/releases) release page. -17. Publish release page on [plone.org](https://plone.org). +17. Publish release page on [plone.org](https://plone.org/). 18. Update plone.org homepage links to point to the new release. 19. Send out announcement to the plone-announce email distribution list. 20. Ask the security team to update the [Hotfixes](https://plone.org/security/hotfixes/) page in the configuration control panel. From aa5a028f8fef927023d294f7ad34828153610be8 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 23 Jun 2024 03:35:15 -0700 Subject: [PATCH 299/810] Revise how to submit a PLIP for today --- docs/contributing/core/plips.md | 120 ++++++++++++++------------------ 1 file changed, 52 insertions(+), 68 deletions(-) diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index 6b880840d..ef1a5cce3 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -9,6 +9,13 @@ myst: # Plone Improvement Proposals (PLIPs) +```{todo} +This page needs extensive review. +It is not clear whether the Framework Team still exists, and PLIPs are now spread over many repositories. + +See https://community.plone.org/t/plips-documentation/19609 +``` + A Plone Improvement Proposal, or {term}`PLIP`, is a change to a Plone package that would affect everyone who uses that package. PLIPs go through a formal process compared to bug fixes because of their broad reach. The Plone Framework Team reviews all PLIPs to make sure that it's in the best interest of the broader community, and that it's of high quality. @@ -17,14 +24,14 @@ The Plone Framework Team reviews all PLIPs to make sure that it's in the best in ## Process overview 1. Developer submits a PLIP. -2. [Some indeterminate team?] approves the PLIP for inclusion into Plone core for a given release. +2. [SOME_INDETERMINATE_TEAM] approves the PLIP for inclusion into Plone core for a given release. 3. Developer implements the PLIP, including code, tests, and documentation. -4. Developer creates a pull request of the PLIP for review by the team. -5. [Some indeterminate team?] reviews the PLIP and gives feedback. +4. Developer creates a pull request of the PLIP for review by the [SOME_INDETERMINATE_TEAM]. +5. [SOME_INDETERMINATE_TEAM] reviews the PLIP and gives feedback. 6. Developer addresses concerns from the feedback, and resubmits the PLIP, if necessary. -7. Repeat the two previous steps, until both the [Some indeterminate team?] and developer are happy with the result. -8. [Somebody] approves the PLIP for merge. -9. [Somebody] merges the PLIP. +7. Repeat the two previous steps, until both the [SOME_INDETERMINATE_TEAM] and developer are happy with the result. +8. [SOMEBODY] approves the PLIP for merge. +9. [SOMEBODY] merges the PLIP. In rare circumstances, a PLIP may be rejected. This is usually the result of the developer not responding to feedback or dropping out of the process. @@ -34,88 +41,65 @@ This is usually the result of the developer not responding to feedback or droppi ## Submit a PLIP -Whether you want to update the default theme, or rip out a piece of architecture, major changes should go through the PLIP process. -If you need help at any point in this process, please contact a member of the Framework Team personally or ask for help at the [Framework Team Space](https://community.plone.org/c/development/framework-team/12). - -A PLIP is a [GitHub issue](https://github.com/plone/Products.CMFPlone/issues) on [`Products.CMFPlone`](https://github.com/Plone/Products.CMFPlone) with a special template and a specific tag. - -To get started, open a new issue. -The issue will be prefilled with headings and comments for a bug or a PLIP. -Remove the bug part. -Fill in all applicable fields. -After submitting, select the tag `03 type: feature (plip)` for the issues. - -When writing a PLIP, be as specific and to-the-point as you can. -Remember your audience. -To get support for your proposal, people will have to be able to read it! +Prepare the following information for your PLIP. -A good PLIP is sufficiently clear for a knowledgeable Plone user to understand the proposed changes, and sufficiently detailed for the release manager and other developers to understand the full impact the proposal would have on the code base. +- Title +- Proposer (you) +- Seconder (another person supporting your PLIP) +- Abstract (a comprehensive overview of the subject) +- Motivation (reason or motivation for creating this proposal) +- Assumptions (preconditions) +- Proposal & Implementation (detailed proposal with implementation details and–if needed—possible variants to be discussed) +- Deliverables (packages and documentation chapters involved, including any third party packages) +- Risks (what will break or affect existing installations of Plone after an upgrade, including the end user point of view, training efforts, and other audiences) +- Participants (list of persons and roles known) -You don't have to list every line of code that needs to be changed, but you should also give an indication that you have some idea of how the change can be feasibly implemented. +Now that you are prepared, submit your PLIP. -After your PLIP is written, solicit feedback on your idea on the [Plone Community Forum](https://community.plone.org/). -In this vetting process, you want to make sure that the change won't adversely affect other people on accident. -Others may be able to point out risks or even offer up better or existing solutions. +1. Visit the package's GitHub issue tracker, and Click {guilabel}`New issue`. -Please note a few things: + If you do not see the option to create a PLIP, then the repository has not been configured with the PLIP GitHub issue template, and you should instead visit the default Plone issue tracker for PLIPs, [`Products.CMFPlone`](https://github.com/plone/Products.CMFPlone/issues). -- It is very rare that the "Risks" section will be empty or none. -- If you find this is the case, and your PLIP is anything more than trivial, maybe some more vetting should be done. -- The seconder field is REQUIRED. +2. For the PLIP option, click {guilabel}`Get started`. -The PLIP will be sent back to you if it is not filled in. -Currently, this is just someone else who thinks your PLIP is a good idea, a +1. +3. Fill in the title and description. + Preserve the headings and comments. + The comments provide guidance for you to follow while composing your PLIP. -In the near future, the seconder should either a coding partner, or someone who is willing and able to finish the PLIP should something happen to the implementer. +4. When done, click {guilabel}`Submit new issue` to submit your PLIP. + +5. If it does not automatically assign the label {guilabel}`03 type: feature (plip)`, then assign that label to the issue to make it easier to find. -### Evaluating PLIPs +## Get feedback -After you submit your PLIP, the Framework Team will meet within a couple weeks, and let you know if the PLIP is accepted. -If the PLIP is not accepted, please don't be discouraged! +After you submit your PLIP, solicit feedback for your idea on the [Plone Community Forum](https://community.plone.org/). -Most PLIPs first start as an add-on, if possible, to make sure it works in practice. +You may revise your PLIP based on feedback. -All communication with you occurs on the PLIP issue itself. -Please keep your eyes and inbox open for changes. +If you need help at any point in this process, please contact a member of the [SOME_INDETERMINATE_TEAM] personally or ask for help at the [Framework Team Space](https://community.plone.org/c/development/framework-team/12). -These are the criteria by which the framework team will review your work: -- What is size and status of the work needed to be done? -- Is it already an add-on and well established? -- Is this idea well baked and expressed clearly? -- Does the work proposed belong in Plone now, or in the future? -- Is this PLIP more appropriate as a qualified add-on? -- Is this PLIP too risky? +## Implement your PLIP -See the {doc}`plip-review` page for more information. +You can start the development at any time, but if you intend to modify Plone core, it is a good idea to wait to see if your idea is approved. -## Implementing your PLIP +### General rules -You can start the development at any time, but if you are going to modify Plone itself, it is a good idea to wait to see if your idea is approved. - - -### General Rules - -- Any new packages must be in a branch in the `plone` namespace in GitHub. - You don't have to develop there, but it must be there when submitted. - Use branches off of the repositories under the Plone GitHub organization, see below. -- Most importantly, the PLIP reviewers must be able run buildout and everything should "just work"™. -- Any new code must: - - - Be {doc}`properly documented `. - - Have clear code. - - Follow current best practices in coding style. The [Plone Meta](https://github.com/plone/meta) project can help you set up your environment. For Volto, follow [this guide](https://6.docs.plone.org/volto/contributing/linting.html). - - [Be tested](https://5.docs.plone.org/develop/testing/index.html). For Volto, follow [this guide](https://6.docs.plone.org/volto/contributing/testing.html) - -```{todo} -Update links from Plone 5 to Plone 6 Documentation, once content is migrated. -See https://github.com/plone/documentation/issues/1330 and other issues. -``` +- Any new packages must be in a branch in the `plone` namespace in GitHub. +- The PLIP reviewers must be able run buildout, and everything should "just work"™. +- New code must: + - Be {doc}`properly documented `. If it ain't documented, it's broken. + - Have clear code. + - Follow current best practices in coding style. + The [Plone Meta](https://github.com/plone/meta) project can help you set up your environment. + For Volto, follow {doc}`/volto/contributing/linting`. + - [Be tested](https://5.docs.plone.org/develop/testing/index.html). + For Volto, follow {doc}`/volto/contributing/testing`. -### Creating a new PLIP branch +### Create a new PLIP branch Create a buildout configuration file for your PLIP in the `plips` folder of {file}`buildout.coredev`. From 21453a6ea6c528bbe8bb0799d688d5dc2a5d1809 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 23 Jun 2024 04:09:36 -0700 Subject: [PATCH 300/810] Fix redirect --- docs/contributing/core/release.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/core/release.md b/docs/contributing/core/release.md index 76d5d5297..707e4eca9 100644 --- a/docs/contributing/core/release.md +++ b/docs/contributing/core/release.md @@ -122,6 +122,6 @@ These are: 15. Create a release page on [plone.org](https://plone.org/download/releases) 16. Wait for installers to be uploaded to Launchpad, with a link to the [plone.org](https://plone.org/download/releases) release page. 17. Publish release page on [plone.org](https://plone.org/). -18. Update plone.org homepage links to point to the new release. +18. Update [plone.org](https://plone.org/) homepage links to point to the new release. 19. Send out announcement to the plone-announce email distribution list. 20. Ask the security team to update the [Hotfixes](https://plone.org/security/hotfixes/) page in the configuration control panel. From ef40380271ffed73f2f45f052203193add919fdf Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 24 Jun 2024 02:22:46 -0700 Subject: [PATCH 301/810] Update pre-requisites of libx* and C compiler --- docs/contributing/core/index.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index cbf2c339c..5cb6fd791 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -36,8 +36,7 @@ However, the following links and sections below may be helpful. - Python {SUPPORTED_PYTHON_VERSIONS} - {term}`GNU make` - {term}`Git` -- [libxml2 and libxslt](https://gitlab.gnome.org/GNOME/libxslt/-/releases), including development headers -- [GNU Compiler Collection (GCC)](https://gcc.gnu.org/) to compile {term}`ZODB`, {term}`Zope`, and {term}`lxml` +- A C compiler ### Python @@ -58,10 +57,13 @@ Plone requires Python version {SUPPORTED_PYTHON_VERSIONS}. ```{include} ../../volto/contributing/install-git.md ``` -### libxml2, libxslt, and GCC +### C compiler -Consult the resources at the links above for installation instructions. -Package managers may facilitate installation. +You need a C compiler on your system to compile {term}`ZODB` and {term}`Zope`. + +On macOS, Developer Tools providers clang for a C compiler. + +On Linux, [GNU Compiler Collection (GCC)](https://gcc.gnu.org/) is a common option. ## Install Plone core for development From cbb149e610f953e3f468ca2a2f844ff51b853fc0 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 24 Jun 2024 02:43:28 -0700 Subject: [PATCH 302/810] Add admonition for non-3.11 Pythons --- docs/contributing/core/index.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 5cb6fd791..6f45d1a41 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -76,6 +76,20 @@ git clone https://github.com/plone/buildout.coredev cd buildout.coredev ``` +````{important} +If you want to use a Python version that is not 3.11, follow these instructions. + +Open the file {file}`bootstrap.sh` at the root of the repository. +Notice that the script expects Python 3.11 to be installed on your system and in your user's `PATH`. + +```shell +#/bin/sh +`which python3.11` -m venv . +``` + +Edit it according to the Python version you want to use, then save and close the file. +```` + Now run the script to install Plone 6. ```shell From 962a4b981213b3b674a6876e19e8d2d9127b01ac Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 24 Jun 2024 02:56:58 -0700 Subject: [PATCH 303/810] Revise and make recommendations in plips.md to remove coaching and focus on how to do things. --- docs/contributing/core/index.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 6f45d1a41..d1a708159 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -108,7 +108,12 @@ Once that's done, you can start an instance of Plone with the following command. To visit your Plone instance, you can open the link http://0.0.0.0:8080 in a web browser. -Click {guilabel}`View your Plone site` to do exactly that. +You will be presented with several options. +Click the button {guilabel}`Create a new Plone site`. + +Enter values in the form, and click the button {guilabel}`Create Plone Site`. + +You will be redirected to your new Plone site. To login, the default credentials are the following. From edee66e4fdb4df1fe47956ea57b8691db2a17887 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 24 Jun 2024 03:37:01 -0700 Subject: [PATCH 304/810] Back off from attempt to use buildout for Volto, and refer to official docs. --- docs/contributing/core/index.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index d1a708159..bf7e714e2 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -12,6 +12,11 @@ myst: This guide describes the process of how to contribute to, and develop in, Plone core. It expands upon {doc}`/contributing/index`. +```{important} +Although Plone core includes Volto—the React based, default frontend for Plone 6—this guide does not apply to Volto and its packages. +To contribute to Volto, see {doc}`../volto`. +``` + This guide assumes that you have basic knowledge of how to use git and GitHub. If you have never contributed to Plone, or you lack basic knowledge of how to use git and GitHub, you should first read {doc}`/contributing/first-time` for more information. @@ -109,11 +114,19 @@ Once that's done, you can start an instance of Plone with the following command. To visit your Plone instance, you can open the link http://0.0.0.0:8080 in a web browser. You will be presented with several options. -Click the button {guilabel}`Create a new Plone site`. +Click the button {guilabel}`Create Classic UI Plone site`. Enter values in the form, and click the button {guilabel}`Create Plone Site`. -You will be redirected to your new Plone site. +You will be redirected to your new Classic UI Plone site. + +```{warning} +Ignore the warning about accessing the Plone backend through its Classic UI frontend. + +Do not follow the instructions to install Volto. +They will not work with buildout. +To contribute to Volto, you will need to start over, and follow {doc}`../volto`. +``` To login, the default credentials are the following. From 7e45ba71e13dd06dddcb0afd355cb28f397ce50d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 24 Jun 2024 03:43:39 -0700 Subject: [PATCH 305/810] Use correct git terms, instead of gitterish --- docs/contributing/core/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index bf7e714e2..b3d6c855b 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -145,9 +145,9 @@ Members of the `plone/contributors` team do not have write access, and instead m The current default and development branch of `buildout.coredev` is `6.1`. Older versions are named according to their `major.minor` version. -Always begin by checking out the git branch on which you want to work, usually called `origin`. -If you have not yet checked out a branch, then you need to track it with the `-t` option and specify the remote branch to track. -The following command will switch and track changes from the remote branch `origin/6.1`. +Always begin by checking out the git branch on which you want to work. +If you have not yet checked out a branch, then you need to track it with the `-t` option and specify the remote to track, usually called `origin`. +The following command will switch and track changes from the remote `origin` and its branch `6.1`. ```shell git checkout -t origin/6.1 From 0897e15754a63afbc4266af801b0c56203f60ef5 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 24 Jun 2024 04:10:54 -0700 Subject: [PATCH 306/810] Give better instructions not to switch between Plone or coredev.buildout branches --- docs/contributing/core/index.md | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index b3d6c855b..d8bbfc85e 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -71,13 +71,25 @@ On macOS, Developer Tools providers clang for a C compiler. On Linux, [GNU Compiler Collection (GCC)](https://gcc.gnu.org/) is a common option. + ## Install Plone core for development +The tool that installs Plone core is `buildout.coredev`. + +The current default and development branch of `buildout.coredev` is `6.1` +Older versions are named according to their `major.minor` version. +Its versions align with Plone's `major.minor` versions. + +Use a separate directory for each version of Plone to which you want to contribute. +This will avoid switching between git branches, then re-running buildout, which can cause dependency conflicts between versions of Plone. + To set up a Plone 6 development environment, change your working directory to wherever you place your projects, and clone https://github.com/plone/buildout.coredev. +You can specify the branch that you want to check out with the `-b` option. ```shell cd [MY_PROJECTS] -git clone https://github.com/plone/buildout.coredev +# clone a specific major.minor version branch +git clone -b 6.1 https://github.com/plone/buildout.coredev cd buildout.coredev ``` @@ -134,7 +146,7 @@ To login, the default credentials are the following. - password: `admin` -## Use the correct branch +## Work with git ```{important} This section applies to members of the GitHub `plone/developers` team, who have write access to repositories under the Plone GitHub organization. @@ -142,9 +154,6 @@ This section applies to members of the GitHub `plone/developers` team, who have Members of the `plone/contributors` team do not have write access, and instead must follow the process to set up their remote upstream and origin branches as described in {ref}`set-up-your-environment-label`. ``` -The current default and development branch of `buildout.coredev` is `6.1`. -Older versions are named according to their `major.minor` version. - Always begin by checking out the git branch on which you want to work. If you have not yet checked out a branch, then you need to track it with the `-t` option and specify the remote to track, usually called `origin`. The following command will switch and track changes from the remote `origin` and its branch `6.1`. @@ -153,7 +162,7 @@ The following command will switch and track changes from the remote `origin` and git checkout -t origin/6.1 ``` -If you check out a different branch, and want to return to the previous branch, you need to specify only the local branch. +Now going forward, you need to specify only the local branch when you want to switch back to it from your development branch. ```shell git checkout 6.1 @@ -165,11 +174,7 @@ Next pull down and merge any recent changes from the remote tracked repository w git pull ``` -```{important} -Make sure to rerun buildout for the current branch to get the correct versions of packages, otherwise you will get some weird behavior. -``` - -Next create a new branch on which you want to work from the current branch, tracking the upstream Plone repository, and check it out. +Next create a new development branch on which you want to work from the current branch, tracking the upstream Plone repository, and check it out. It's a good idea to use a branch name that includes the issue number and is descriptive of what it resolves. ```shell From 1704bbc84217f255ac9716aad06f2c0241588f89 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 24 Jun 2024 04:27:16 -0700 Subject: [PATCH 307/810] Move new development branch under Edit packages, and use what @thet and I walked through, now that it all makes sense (for now) --- docs/contributing/core/index.md | 53 ++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index d8bbfc85e..8f19de2e0 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -174,15 +174,6 @@ Next pull down and merge any recent changes from the remote tracked repository w git pull ``` -Next create a new development branch on which you want to work from the current branch, tracking the upstream Plone repository, and check it out. -It's a good idea to use a branch name that includes the issue number and is descriptive of what it resolves. - -```shell -git switch -c 123-thing-i-fixed -t origin/6.1 -``` - -Now you can edit your code without affecting the original branch. - ## Edit packages @@ -190,33 +181,53 @@ First identify the names of the Plone packages you want to work on. If you do not know, you can ask in the [Plone Community Forum](https://community.plone.org/). Only a few packages are in {file}`src/` by default. -Edit the file {file}`checkouts.cfg` at the root of the repository by adding the package names under the `auto-checkout` list. +Next create a new file {file}`buildout.local.cfg`, and add the names of packages that you want to develop under the `auto-checkout` list. -```{code-block} cfg -:emphasize-lines: 10- +```cfg [buildout] -always-checkout = force -# always-checkout = false +extends = + buildout.cfg + auto-checkout = -# These packages are always checked out: - docs - # -# These packages are manually added, or automatically added by mr.roboto: - # + # Add packages that you want to develop plone.app.event icalendar + # others + ... ``` -Then rerun buildout to install the source packages to edit. +When you make changes in your package, then rerun buildout with the following command, specifying your new buildout configuration file with the `-c` option. ```shell -./bin/buildout +./bin/buildout -c buildout.local.cfg ``` ```{seealso} For tips on working with `mr.developer`, see {doc}`mrdeveloper`. ``` +````{tip} +To avoid conflicts with `buildout.coredev` files, you can configure git for your user. +Either create or edit a file at {file}`~/.gitconfig`. +Then add the following stanza to it. + +```cfg +[core] + excludesfile = ~/.gitignore_global +``` + +Then add any standard `.gitignore` syntax to exclude files from getting committed and pushed to a remote repository. +```` + +Next create a new development branch on which you want to work from the current branch, tracking the upstream Plone repository, and check it out. +It's a good idea to use a branch name that includes the issue number and is descriptive of what it resolves. + +```shell +git switch -c 123-thing-i-fixed -t origin/6.1 +``` + +Now you can edit your code without affecting the original branch. + ## Test locally From 7e604ed4df2c597436d9c1a1e7f8a656fb1ac31f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 24 Jun 2024 04:30:12 -0700 Subject: [PATCH 308/810] Add -N flag option to buildout --- docs/contributing/core/index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 8f19de2e0..49387bfb0 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -197,9 +197,10 @@ auto-checkout = ``` When you make changes in your package, then rerun buildout with the following command, specifying your new buildout configuration file with the `-c` option. +You can add the `-N` flag to save time by not checking PyPI to see if there are updates to packages that were already installed. ```shell -./bin/buildout -c buildout.local.cfg +./bin/buildout -c buildout.local.cfg -N ``` ```{seealso} From fcdd9923dcb60a1007cea70e2ebf9c3bdf73544d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 24 Jun 2024 04:45:17 -0700 Subject: [PATCH 309/810] Reference tests to use PR, CI, and Jenkins first, and locally only if necessary --- docs/contributing/core/index.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 49387bfb0..2b1b73f89 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -237,13 +237,15 @@ If you change the expected behavior of a feature in a package, you should write To run a test for the specific package that you modified, use the `-m` option followed by the package name, as shown in the following example. ```shell -./bin/test -m plone.app.caching +./bin/test -m plone.app.event ``` If any test fails, do not commit and push the changes. Instead write a test that passes. -After the package level tests pass with your change, you can run the full unit test suite to ensure other packages aren't affected by the change. +After the package level tests pass with your change, you can {ref}`contributing-core-create-a-pull-request-label` and let CI run and ask Jenkins to run the full test suite. + +However, if CI or Jenkins report a test failure that you want to troubleshoot locally, you can run the full unit test suite to ensure other packages aren't affected by the change. It takes 5-10 minutes to run the full unit test suite. ```shell @@ -284,6 +286,8 @@ The Plone release manager will check this file to see which packages you have up ``` +(contributing-core-create-a-pull-request-label)= + ## Create a pull request After you have completed all the foregoing steps, push your changes to a remote branch and create a pull request in GitHub. From 7838b17d1b3a529800d30b4cae2d6cfd1c01d87c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 24 Jun 2024 04:46:51 -0700 Subject: [PATCH 310/810] Add note for how to identify towncrier repos --- docs/contributing/core/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 2b1b73f89..013912c14 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -268,6 +268,7 @@ If you can't afford this disruption, you can defer it to Jenkins. All changes require a change log entry. For packages that use [towncrier](https://pypi.org/project/towncrier/) to produce change logs, see {ref}`contributing-change-log-label`. +A package that uses towncrier has a `news` directory at its repository or package root. For packages that don't use towncrier, edit either {file}`CHANGES.rst`, {file}`CHANGES.txt`, or {file}`HISTORY.txt` in each package you have modified, adding a summary of the change. New change log entries should be added at the top of {file}`CHANGES.rst`. From abf5f7b4dadf5556cd1abe8533970eb3c083bcc6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 24 Jun 2024 04:47:49 -0700 Subject: [PATCH 311/810] Remove obsolete section "Update `checkouts.cfg`" --- docs/contributing/core/index.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 013912c14..5a545e36d 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -274,19 +274,6 @@ For packages that don't use towncrier, edit either {file}`CHANGES.rst`, {file}`C New change log entries should be added at the top of {file}`CHANGES.rst`. -## Update `checkouts.cfg` - -If you didn't do so earlier, edit the file {file}`checkouts.cfg` at the root, and add your changed packages only to the `auto-checkout` list. -Remove any packages that you previously added to this file, but did not change. -Leave any pre-existing packages in the original list. - -The Plone release manager will check this file to see which packages you have updated to make a proper release. - -```{seealso} -{doc}`release` -``` - - (contributing-core-create-a-pull-request-label)= ## Create a pull request From bc12737979848953a97e6aa2b9e18d236171b14e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 24 Jun 2024 04:53:33 -0700 Subject: [PATCH 312/810] Copy from first-time-contributors about Fixes #ISSUE-NUMBER --- docs/contributing/core/index.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 5a545e36d..7ddf2b46e 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -279,8 +279,9 @@ New change log entries should be added at the top of {file}`CHANGES.rst`. ## Create a pull request After you have completed all the foregoing steps, push your changes to a remote branch and create a pull request in GitHub. - -If you are working from an issue, return to the original issue, and add a link to the pull request. +If you are working from an issue, include "Fixes #ISSUE-NUMBER" in the description. +This enables automatic closing of the related issue when the pull request is merged. +This also creates a hyperlink to the original issue for easy reference. ## Jenkins and mr.roboto From 6ef5c58872b6b68c76a8563c41a38b506ded8496 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 24 Jun 2024 04:57:07 -0700 Subject: [PATCH 313/810] Purge obsolete explanation about what Jenkins runs --- docs/contributing/core/index.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 7ddf2b46e..fbf4b85be 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -291,8 +291,6 @@ Plone has a continuous integration ({term}`CI`) setup and follows CI rules. When you push a change to a Plone package, there may be GitHub workflows that run automatically. The CI package [mr.roboto](https://github.com/plone/mr.roboto) will perform some checks and suggest that you run Jenkins after all other CI runs. -For each Plone and Python version, Jenkins runs two jobs: one for the package itself (which will give you a fast feedback, within 10 minutes) and one on the full `coredev` build (which can take up to an hour, but makes sure no other packages are affected by your change). - See {doc}`continuous-integration` for more information. From 21e36586b703d0647f55783f9347134d1a857643 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 26 Jun 2024 01:04:56 -0700 Subject: [PATCH 314/810] Update C compiler pre-requisites Co-authored-by: David Glick --- docs/contributing/core/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index fbf4b85be..26fb0aab4 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -64,9 +64,9 @@ Plone requires Python version {SUPPORTED_PYTHON_VERSIONS}. ### C compiler -You need a C compiler on your system to compile {term}`ZODB` and {term}`Zope`. +You need a C compiler on your system to compile some of the Python libraries that Plone uses. -On macOS, Developer Tools providers clang for a C compiler. +On macOS, Developer Tools provides Clang for a C compiler. On Linux, [GNU Compiler Collection (GCC)](https://gcc.gnu.org/) is a common option. From a80c9ccc6fb197b567e6dcc8e62d3be5164d96e0 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 26 Jun 2024 01:48:48 -0700 Subject: [PATCH 315/810] Reword seealso for `mr.developer` --- docs/contributing/core/index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 26fb0aab4..016216316 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -204,7 +204,8 @@ You can add the `-N` flag to save time by not checking PyPI to see if there are ``` ```{seealso} -For tips on working with `mr.developer`, see {doc}`mrdeveloper`. +`mr.developer` checks out additional repositories using the `auto-checkout` option. +For more information, see {doc}`mrdeveloper`. ``` ````{tip} From 26da8cc1d6fed9aa0adb12611384c29546c77e9e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 26 Jun 2024 02:01:08 -0700 Subject: [PATCH 316/810] Rewrite adn simplify git pieces --- docs/contributing/core/index.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 016216316..add4d7a41 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -155,14 +155,9 @@ Members of the `plone/contributors` team do not have write access, and instead m ``` Always begin by checking out the git branch on which you want to work. -If you have not yet checked out a branch, then you need to track it with the `-t` option and specify the remote to track, usually called `origin`. -The following command will switch and track changes from the remote `origin` and its branch `6.1`. +This is the base branch to which you will create a pull request. -```shell -git checkout -t origin/6.1 -``` - -Now going forward, you need to specify only the local branch when you want to switch back to it from your development branch. +If you just cloned `https://github.com/plone/buildout.coredev`, then the `6.1` branch is checked out and current, and you can skip the rest of this section and continue on the next, {ref}`contributing-core-edit-packages-label`. ```shell git checkout 6.1 @@ -175,6 +170,8 @@ git pull ``` +(contributing-core-edit-packages-label)= + ## Edit packages First identify the names of the Plone packages you want to work on. @@ -225,7 +222,7 @@ Next create a new development branch on which you want to work from the current It's a good idea to use a branch name that includes the issue number and is descriptive of what it resolves. ```shell -git switch -c 123-thing-i-fixed -t origin/6.1 +git switch -c 123-thing-i-fixed ``` Now you can edit your code without affecting the original branch. From 6f816aeef2e825a521d45e959fca834d4bae3718 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 26 Jun 2024 03:33:27 -0700 Subject: [PATCH 317/810] Indicate symbol --- docs/contributing/core/mrdeveloper.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/core/mrdeveloper.md b/docs/contributing/core/mrdeveloper.md index db4b0aabf..114bf9379 100644 --- a/docs/contributing/core/mrdeveloper.md +++ b/docs/contributing/core/mrdeveloper.md @@ -27,7 +27,7 @@ From time to time you can check if some old cruft has accumulated. bin/develop status ``` -If this prints any lines with a question mark in front, you can clean the cruft with the following command. +If this prints any lines with a question mark (`?`) in front, you can clean the cruft with the following command. ```shell bin/develop purge From 4a269ca060c982b1bf8935ee04c2775ea3e6e91f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 26 Jun 2024 03:35:46 -0700 Subject: [PATCH 318/810] Fix headings and meta information --- docs/contributing/core/documentation.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/contributing/core/documentation.md b/docs/contributing/core/documentation.md index 70f3b299d..ff06f57cf 100644 --- a/docs/contributing/core/documentation.md +++ b/docs/contributing/core/documentation.md @@ -1,13 +1,13 @@ --- myst: html_meta: - "description": "Writing documentation of Plone" - "property=og:description": "Writing documentation of Plone" - "property=og:title": "Writing documentation of Plone" + "description": "Write documentation of Plone" + "property=og:description": "Write documentation of Plone" + "property=og:title": "Write documentation of Plone" "keywords": "documentation, Plone" --- -# Writing documentation +# Write documentation For general guidance for contributing documentation, see {doc}`/contributing/documentation/index`. @@ -20,7 +20,7 @@ The documentation repository is on [GitHub](https://github.com/plone/documentati Information for how to contribute to documentation can be found at {doc}`/contributing/documentation/index`. -## Documenting a package +## Document a package At the very least, your package should include the following forms of documentation. From c8edc3c0b985434ba009551651ebd477bc8f34fc Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 26 Jun 2024 03:37:05 -0700 Subject: [PATCH 319/810] Remove todo --- docs/contributing/core/plips.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index ef1a5cce3..83da6d27e 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -9,13 +9,6 @@ myst: # Plone Improvement Proposals (PLIPs) -```{todo} -This page needs extensive review. -It is not clear whether the Framework Team still exists, and PLIPs are now spread over many repositories. - -See https://community.plone.org/t/plips-documentation/19609 -``` - A Plone Improvement Proposal, or {term}`PLIP`, is a change to a Plone package that would affect everyone who uses that package. PLIPs go through a formal process compared to bug fixes because of their broad reach. The Plone Framework Team reviews all PLIPs to make sure that it's in the best interest of the broader community, and that it's of high quality. From 86c1fcac807a5c71f1e9990dd00c97d35572159f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 26 Jun 2024 04:00:02 -0700 Subject: [PATCH 320/810] - Align overview with sections of PLIP submittal process - Add designated packages, teams, repos with a default --- docs/contributing/core/plips.md | 48 ++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index 83da6d27e..3b8c13e6d 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -16,21 +16,35 @@ The Plone Framework Team reviews all PLIPs to make sure that it's in the best in ## Process overview -1. Developer submits a PLIP. -2. [SOME_INDETERMINATE_TEAM] approves the PLIP for inclusion into Plone core for a given release. -3. Developer implements the PLIP, including code, tests, and documentation. -4. Developer creates a pull request of the PLIP for review by the [SOME_INDETERMINATE_TEAM]. -5. [SOME_INDETERMINATE_TEAM] reviews the PLIP and gives feedback. -6. Developer addresses concerns from the feedback, and resubmits the PLIP, if necessary. -7. Repeat the two previous steps, until both the [SOME_INDETERMINATE_TEAM] and developer are happy with the result. -8. [SOMEBODY] approves the PLIP for merge. -9. [SOMEBODY] merges the PLIP. +1. Developer submits a PLIP and solicits feedback. +2. Developer addresses concerns from the feedback, and resubmits the PLIP, if necessary. +3. The designated team approves the PLIP for inclusion into Plone core for a given release. +4. Developer implements the PLIP, including code, tests, and documentation. +5. Developer creates a pull request of the PLIP for review by the designated team. +6. The designated team reviews the pull request of the PLIP and gives feedback. +7. Repeat the two previous steps, until both the designated team and developer are happy with the result. +8. A designated team member approves the PLIP for merge. +9. A designated team member merges the PLIP. In rare circumstances, a PLIP may be rejected. This is usually the result of the developer not responding to feedback or dropping out of the process. -(submit-a-plip)= +(designated-teams-label)= + +## Designated teams + +The following packages and repositories have designated teams that you can contact by `@`-ing them in its GitHub issue tracker. +If the repository is not listed, use the default repository for `Products.CMFPlone`. + +| Package | Repository | Team | +|---|---|---| +| `Products.CMFPlone` | https://github.com/plone/Products.CMFPlone | not applicable | +| Classic UI | https://github.com/plone/plone.classicui | `@plone/ClassicUI-Team` | +| Volto | https://github.com/plone/volto | `@plone/volto-team` | + + +(submit-a-plip-label)= ## Submit a PLIP @@ -61,16 +75,22 @@ Now that you are prepared, submit your PLIP. 4. When done, click {guilabel}`Submit new issue` to submit your PLIP. -5. If it does not automatically assign the label {guilabel}`03 type: feature (plip)`, then assign that label to the issue to make it easier to find. +5. If GitHub does not automatically assign the label {guilabel}`03 type: feature (plip)`, then assign that label to the issue to make it easier to find. ## Get feedback -After you submit your PLIP, solicit feedback for your idea on the [Plone Community Forum](https://community.plone.org/). +After you submit your PLIP, solicit feedback for your idea on the [Plone Community Forum](https://community.plone.org/) and through the repository's issue tracker. You may revise your PLIP based on feedback. -If you need help at any point in this process, please contact a member of the [SOME_INDETERMINATE_TEAM] personally or ask for help at the [Framework Team Space](https://community.plone.org/c/development/framework-team/12). +If you need help at any point in this process, you can either `@` the team or personally contact a member of the designated team. + + +## Team approves proposal + +After incorporating feedback to your proposal, you can request a final review and approval for inclusion in Plone. +Every PLIP must be approved by the designated team. ## Implement your PLIP @@ -260,5 +280,3 @@ In general, PLIPs shouldn't take more than a year, otherwise they should be clos If a PLIP isn't accepted in core, it doesn't mean it's a bad idea. It is often the case that there are competing implementations, and the community wants to see it vetted as an add-on before "blessing" a particular implementation. - - From 33156c306ac8ef2c3358c4ad7ca5dde8b9dea7be Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 26 Jun 2024 04:34:45 -0700 Subject: [PATCH 321/810] - Purge FAQ as redundant and unused. No one asks questions about PLIPs anyway, so how can they be frequent? - Purge hand-holding. It's a how-to guide. - Refer to setup of development environment. --- docs/contributing/core/index.md | 6 +- docs/contributing/core/plips.md | 150 ++++++-------------------------- 2 files changed, 32 insertions(+), 124 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index add4d7a41..0041f8229 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -180,7 +180,7 @@ Only a few packages are in {file}`src/` by default. Next create a new file {file}`buildout.local.cfg`, and add the names of packages that you want to develop under the `auto-checkout` list. -```cfg +```ini [buildout] extends = buildout.cfg @@ -228,6 +228,8 @@ git switch -c 123-thing-i-fixed Now you can edit your code without affecting the original branch. +(contributing-core-test-locally-label)= + ## Test locally If you change the expected behavior of a feature in a package, you should write a test to cover the change. @@ -261,6 +263,8 @@ If you can't afford this disruption, you can defer it to Jenkins. ``` +(contributing-core-change-log-label)= + ## Change log All changes require a change log entry. diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index 3b8c13e6d..c369b5329 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -95,6 +95,12 @@ Every PLIP must be approved by the designated team. ## Implement your PLIP +(plip-setup-instructions-label)= + +```{note} +This section assumes you have read and followed the instructions in {doc}`index` to set up your development environment, up until {ref}`contributing-core-edit-packages-label`. +``` + You can start the development at any time, but if you intend to modify Plone core, it is a good idea to wait to see if your idea is approved. @@ -114,15 +120,12 @@ You can start the development at any time, but if you intend to modify Plone cor ### Create a new PLIP branch -Create a buildout configuration file for your PLIP in the `plips` folder of {file}`buildout.coredev`. - -Give it a descriptive name, starting with the PLIP number, for example, {file}`plip-1234-widget-frobbing.cfg`. +Create a buildout configuration file for your PLIP in the `plips` folder of `buildout.coredev`. +Its name should follow the pattern `plip-repository-issue_number-description.cfg`. +For example, {file}`plip-volto-1234-widget-frobbing.cfg`. -The PLIP number is your PLIP's issue number. - -This file will define the branches you're working with in your PLIP, along with other buildout configuration. - -It should look something like the following, such as in a file {file}`plips/plip-1234-widget-frobbing.cfg`. +This file will define the branches for your PLIP, along with other buildout configuration. +The following is example content for the file {file}`plips/plip-volto-1234-widget-frobbing.cfg`. ```ini [buildout] @@ -132,8 +135,8 @@ auto-checkout += plone.app.someotherpackage [sources] -plone.somepackage = git https://github.com/plone/plone.somepackage.git branch=plip-1234-widget-frobbing -plone.app.someotherpackage = git https://github.com/plone/plone.app.somepackage.git branch=plip-1234-widget-frobbing +plone.somepackage = git https://github.com/plone/plone.somepackage.git branch=plip-volto-1234-widget-frobbing +plone.app.someotherpackage = git https://github.com/plone/plone.app.somepackage.git branch=plip-volto-1234-widget-frobbing [instance] eggs += @@ -145,138 +148,39 @@ zcml += ``` Use the same naming convention when you branch existing packages. -You should always branch packages when working on PLIPs. -### Working on a PLIP +### Work on a PLIP -To work on a PLIP, you bootstrap buildout, and then invoke buildout with your PLIP configuration: +To work on a PLIP, assuming you have followed the {ref}`PLIP set up instructions `, you can invoke buildout with your PLIP configuration as follows. ```shell -virtualenv . -./bin/pip install -r requirements.txt -./bin/buildout -c plips/plip-1234-widget-frobbing.cfg +./bin/buildout -c plips/plip-volto-1234-widget-frobbing.cfg ``` -If you are using a {file}`local.cfg` to extend your PLIP file with some changes that you do not want to commit accidentally, be aware that you need to override some settings from {file}`plipbase.cfg` to avoid some files being created in the {file}`plips` directory or in the directory above the buildout directory. -This is done as shown below. - -```ini -[buildout] -extends = plips/plip-1234-widget-frobbing.cfg -develop-eggs-directory = ./develop-eggs -bin-directory = ./bin -parts-directory = ./parts -sources-dir = ./src -installed = .installed.cfg - -[instance] -var = ./var +```{seealso} +See {ref}`contributing-core-test-locally-label`, {ref}`contributing-core-change-log-label`, and {ref}`contributing-core-create-a-pull-request-label`. ``` -### Finishing up +### Finish up -Before marking your PLIP as ready for review, please add a file to give a set of instructions to the PLIP reviewer. -This file should be called {file}`plip__notes.txt`. +Before marking your PLIP as ready for review as a pull request, add a file to give a set of instructions to the PLIP reviewer. +This file should be called {file}`plip___notes.txt`. This should include, but is not limited to: -- URLs pointing to all documentation created and updated -- Any concerns and issues still remaining -- Any weird buildout things +- URLs pointing to all documentation created and updated +- Any concerns and issues still remaining +- Any weird buildout things -Once you have finished, update your PLIP issue to indicate that it is ready for review. -The Framework Team will assign 2-3 people to review your PLIP. +Once you have finished, update your PLIP issue and pull request to indicate that it is ready for review. +The designated team will review your PLIP. They will follow the guidelines listed at {doc}`plip-review`. -After the PLIP has been accepted by the Framework Team and the release managers, you will be asked to merge your work into the main development line. -Merging the PLIP in is not the hardest part, but you must think about it when you develop. - -You'll have to interact with a large number of people to get it all set up. +After the PLIP has been accepted by the designated team and the release managers, you will be asked to merge your work into the main development line. The merge may have unintended interactions with other PLIPs coming in. During the merge phase you must be prepared to help out with all the features and bugs that arise. If all went as planned, the next Plone release will carry on with your PLIP in it. You'll be expected to help out with that feature after it's been released (within reason). - - -## Frequently asked questions about PLIPs - -This section provides detailed answers to common questions about PLIPs. - - -### PLIP or bug fix? - -In general, anything that changes the API of Plone in the backend or the user interface (UI) on the front end should be filed as a PLIP. -When in doubt, submit it as a PLIP. -The Framework Team will reclassify it if your proposal falls below the threshold. -If the change you are proposing is not in the scope of a PLIP, a GitHub pull request or issue is the right format. -The key point here is that each change must be documented, allowing it to be tracked and understood. - - -### Who can submit PLIPs? - -Anyone who has signed a Plone Contributor Agreement can work on a PLIP. - -```{todo} -The FWT no longer participates in PLIPs. -Recommend deletion of next two paragraphs. -``` -The Framework Team is happy to help you at any point in the process. - -When the PLIP is accepted, a Framework Team member will "champion" your PLIP and follow up to its completion. - - -### What is a PLIP champion? - -```{todo} -This section is no longer in practice. -Recommend deletion. -``` - -When you submit your PLIP and it is approved, a Framework Team member will take on the role of champion for that PLIP. - -They are there to help you through completion, answer questions, and provide guidance. - -A champion fulfills the following tasks: - -- Answer any questions the PLIP implementor has, technical or otherwise. -- Encourage the PLIP author by constantly giving feedback and encouragement. -- Keep the implementer aware of timelines, and push to get things done on time. -- Assist with finding additional help when needed to complete the implementation in a timely matter. - -Keep in mind that champions are volunteers as well, and have other tasks in life. -That means you will have to play an active role in asking for help or guidance. - - -### Can I get involved in other ways? - -If you want to experience the process and how it works, help us review PLIPs as the implementations finish up. - -Check the status of PLIPs at https://github.com/search?q=path%3A%2Fplone+label%3A%2203+type%3A+feature+%28plip%29%22++&type=issues&ref=advsearch&state=open. - -Then, follow the instructions for {doc}`reviewing a PLIP `. - - -### When can I submit a PLIP? - -Today, tomorrow, any time! - -After the PLIP is accepted, the Framework Team will try to judge complexity and time to completion, and assign it to a milestone. - - -### When is the PLIP due? - -**Summary: As soon as you get it done.** - -Ideally, a PLIP should be completed for the release to which it's assigned. -Sometimes life gets in the way, and a PLIP may have to be re-assigned to the following release. - -In general, PLIPs shouldn't take more than a year, otherwise they should be closed. A new PLIP can follow up if there is more capacity to see it through. - - -### What happens if your PLIP is not accepted? - -If a PLIP isn't accepted in core, it doesn't mean it's a bad idea. -It is often the case that there are competing implementations, and the community wants to see it vetted as an add-on before "blessing" a particular implementation. From 33159051bccef69bd63ec0bb37fdccc14771d321 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 26 Jun 2024 04:56:29 -0700 Subject: [PATCH 322/810] Volto has its own contributing process, regardless of whether it is a PLIP --- docs/contributing/core/plips.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index c369b5329..091ca2e8d 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -97,6 +97,11 @@ Every PLIP must be approved by the designated team. (plip-setup-instructions-label)= +```{important} +This section does not apply to Volto. +Instead see {doc}`../../volto/contributing/index`. +``` + ```{note} This section assumes you have read and followed the instructions in {doc}`index` to set up your development environment, up until {ref}`contributing-core-edit-packages-label`. ``` @@ -113,9 +118,7 @@ You can start the development at any time, but if you intend to modify Plone cor - Have clear code. - Follow current best practices in coding style. The [Plone Meta](https://github.com/plone/meta) project can help you set up your environment. - For Volto, follow {doc}`/volto/contributing/linting`. - [Be tested](https://5.docs.plone.org/develop/testing/index.html). - For Volto, follow {doc}`/volto/contributing/testing`. ### Create a new PLIP branch From f087267fce5a202a5b27885c41f39c89045a687f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 27 Jun 2024 04:40:38 -0700 Subject: [PATCH 323/810] Add intersphinx configuration for Plone 5 docs --- docs/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/conf.py b/docs/conf.py index a5a763de4..a1f2ff984 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -202,6 +202,7 @@ # the entire Plone Documentation is built. intersphinx_mapping = { "plone": ("https://6.docs.plone.org/", None), # for imported packages + "plone5": ("https://5.docs.plone.org/", None), "python": ("https://docs.python.org/3/", None), "training": ("https://training.plone.org/", None), "training-2022": ("https://2022.training.plone.org/", None), From 2098aa77ec4b83ecd40435b9c3cc09f3e71540fc Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 27 Jun 2024 04:44:32 -0700 Subject: [PATCH 324/810] Finalize PLIP stuff --- docs/contributing/core/plip-review.md | 80 +++++++++++++-------------- docs/contributing/core/plips.md | 2 +- 2 files changed, 38 insertions(+), 44 deletions(-) diff --git a/docs/contributing/core/plip-review.md b/docs/contributing/core/plip-review.md index aa979067d..4ec0c0184 100644 --- a/docs/contributing/core/plip-review.md +++ b/docs/contributing/core/plip-review.md @@ -10,25 +10,19 @@ myst: # PLIP review A Plone Improvement Proposal (PLIP) is a formal process to propose a change to improve Plone. +A review of a PLIP ensures that proposed behavior has been implemented as expected. +Post your PLIP review as a comment in the PLIP pull request. -## Expectations -A good PLIP review takes about four hours. -Please plan accordingly. - -When you are done, if you have access to core, commit the review to the `plips` folder of [`buildout.coredev`](https://github.com/plone/buildout.coredev), and reference the PLIP in your commit message. -If you do not have access, attach your review to the PLIP ticket itself. - - -## Setting up the environment +## Set up the environment Follow the instructions in {doc}`index`. You will need to checkout the branch to which the PLIP is assigned. Instead of running the buildout with the default buildout file, you will run the configuration specific to that PLIP: ```shell -./bin/buildout -c plips/plip-XXXX.cfg +./bin/buildout -c plips/plip---.cfg ``` @@ -36,81 +30,81 @@ Instead of running the buildout with the default buildout file, you will run the This section describes the topics that may be addressed in a PLIP review, depending on the nature of the PLIP itself. +Report bugs or issues you find during the review on GitHub as you would for any Plone bug. +Reference the PLIP in the bug, assign it to its implementer, and add a tag for the PLIP in the form of `plip-xxx`. +This way the implementer can find help if they need it. +Also set a priority for the ticket. +The PLIP will not be merged until all blockers and critical bugs are fixed. + ### General +- Take screenshots or videos as necessary, and post them to the pull request with your comments. - Does the PLIP actually do what the implementers proposed? - Are there incomplete variations? +- Are there incomplete variations? - Were there any errors running buildout? - Did the migration(s) work? +- If there were migrations, did they work? - Do error and status messages make sense? - Are they properly internationalized? +- Are messages properly internationalized? - Are there any performance considerations? - Has the implementer addressed them, if so? ### Bugs - Are there any bugs? - Nothing is too big nor small. -- Do fields handle wacky data? - How about strings in date fields, or nulls in required? -- Is validation up to snuff and sensical? - Is it too restrictive or not restrictive enough? +- Do fields handle unexpected data? +- Is validation function correctly and make sense? +- Is validation too restrictive or not restrictive enough? -### Usability Issues +### Usability issues - Is the implementation usable? -- How will novice end users respond to the change? +- How will end users respond to the change? - Does this PLIP need a usability review? - If you think this PLIP needs a usability review, change the state to "please review" and add a note in the comments. + If you think this PLIP needs a usability review, add GitHub issue labels {guilabel}`99 tag: UX`, or similar, and {guilabel}`32 needs: review`, and add a note in the comments. - Is the PLIP consistent with the rest of Plone? For example, if there is control panel configuration, does the new form fit in with the rest of the panels? -- Does everything flow nicely for novice and advanced users? - Is there any workflow that feels odd? +- Does everything flow nicely for all users? - Are there any new permissions and do they work properly? - Does their role assignment make sense? +- Does permission assignment to roles make sense? -### Documentation Issues +### Documentation issues -- Is the corresponding documentation for the end user, be it developer or Plone user, sufficient? -- Is the change itself properly documented? +- Is the corresponding documentation for the end user, be it developer or Plone user, sufficient? +- Is the change itself properly documented? -Report bugs or issues on GitHub as you would for any Plone bug. -Reference the PLIP in the bug, assign to its implementer, and add a tag for the PLIP in the form of `plip-xxx`. -This way the implementer can find help if they need it. -Also set a priority for the ticket. -The PLIP will not be merged until all blockers and critical bugs are fixed. +## Code review -### Code Review +This section describes considerations of code quality. -#### Python +### Python - Is this code maintainable? - Is the code properly documented? -- Does the code adhere to PEP8 standards (more or less)? -- Are they importing deprecated modules? +- Does the code adhere to formatting and style standards? +- Are there any importied deprecated modules? -#### JavaScript +### JavaScript -- Does the JavaScript meet our set of JavaScript standards? - See our section about [JavaScript](https://5.docs.plone.org/develop/addons/javascript/index.html) and the [JavaScript Style Guide](https://5.docs.plone.org/develop/styleguide/javascript.html). +- Does the JavaScript satisfy the package's JavaScript standards, or if the package has no standard, then Plone's? + See Plone's section about {doc}`plone5:develop/addons/javascript/index` and the {doc}`plone5:develop/styleguide/javascript`. - Does the JavaScript work in all currently supported browsers? - Is it performant? +- Is the JavaScript performant? ```{todo} Update links from Plone 5 Documentation to Plone 6 Documentation, when they exist. See https://github.com/plone/documentation/issues/1330 ``` -#### ME/TAL +### ME/TAL - Does the PLIP use views appropriately, avoiding too much logic? - Is there any code in a loop that could potentially be a performance issue? - Are there any deprecated or old style ME/TAL lines of code, such as using `DateTime`? -- Is the rendered HTML compliant with standards? Are IDs and classes used appropriately? +- Is the rendered HTML compliant with standards? +- Are `id`s and classes used appropriately? diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index 091ca2e8d..6941d6b55 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -118,7 +118,7 @@ You can start the development at any time, but if you intend to modify Plone cor - Have clear code. - Follow current best practices in coding style. The [Plone Meta](https://github.com/plone/meta) project can help you set up your environment. - - [Be tested](https://5.docs.plone.org/develop/testing/index.html). + - Be tested according to Plone core's {doc}`plone5:develop/testing/index`. ### Create a new PLIP branch From 340a0ae4fdff46db8592f2bd2b50d4e0cee218c6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 27 Jun 2024 05:06:58 -0700 Subject: [PATCH 325/810] Clean up release.md and add Community Forum posts --- docs/contributing/core/release.md | 92 ++++++++++++++++--------------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/docs/contributing/core/release.md b/docs/contributing/core/release.md index 707e4eca9..7439d547a 100644 --- a/docs/contributing/core/release.md +++ b/docs/contributing/core/release.md @@ -25,24 +25,25 @@ This command includes the following requirements. All files mentioned in this list may be written in Markdown or reStructuredText and have the appropriate file name suffix. ``` -- All releases must be hosted on PyPI. -- All versions must be tagged in version control. -- Each package must have a {file}`README` file with links to the version control repository and issue tracker. -- {file}`CHANGES` ({file}`docs/HISTORY`) must be always up-to-date and must contain list of functional changes which may affect package users. -- {file}`CHANGES` must contain release dates. -- {file}`README` and {file}`CHANGES` must be visible on PyPI. -- Released eggs must contain generated gettext `.mo` files, but these files must not be committed to the repository. +- All releases must be hosted on PyPI. +- All versions must be tagged in version control. +- Each package must have a {file}`README` file with links to the version control repository and issue tracker. +- {file}`CHANGES` (or {file}`docs/HISTORY`) must be always up-to-date and must contain list of functional changes which may affect package users. +- {file}`CHANGES` must contain release dates. +- {file}`README` and {file}`CHANGES` must be visible on PyPI. +- Released eggs must contain generated gettext `.mo` files, but these files must not be committed to the repository. The `.mo` files can be created with the `zest.pocompile` add-on, which should be installed together with `zest.releaser`. -- `.gitignore` and `MANIFEST.in` must reflect the files going in to the egg (must include page template, po files). +- `.gitignore` and `MANIFEST.in` must reflect the files going in to the egg (must include page template and `.po` files). ```{seealso} [High quality automated package releases for Python with `zest.releaser`](https://opensourcehacker.com/2012/08/14/high-quality-automated-package-releases-for-python-with-zest-releaser/). ``` + ## Special packages The Plone Release Team releases the core Plone packages. -Several others also have the rights to release individual packages on [PyPI](https://pypi.org/). +Several other people also have the rights to release individual packages on [PyPI](https://pypi.org). If you have those rights on your account, you should feel free to make releases. Some packages need special care, or should be done only by specific people, as they know what they are doing. @@ -54,13 +55,14 @@ These are: `plone.app.locales` : Please leave this to the i18n team lead, Vincent Fretin. + ## Plone core release process checklist -1. Check Jenkins status. - Check the latest Plone coredev job on [Jenkins](https://jenkins.plone.org/). +1. Check Jenkins status. + Check the latest Plone coredev job on [Jenkins](https://jenkins.plone.org). It should be green, but if it is not, fix the problem first. -2. Check out `buildout.coredev`. +1. Clone `buildout.coredev`, then check out and build the version to be released. ```shell git clone git@github.com:plone/buildout.coredev.git @@ -70,8 +72,8 @@ These are: bin/buildout -c buildout.cfg ``` -3. Check packages for updates. - Check all packages for updates, add to or remove from `checkouts.cfg` accordingly. +1. Check packages for updates. + Add to or remove from `checkouts.cfg` accordingly. This script may help: ```shell @@ -80,48 +82,50 @@ These are: This step should not be needed, because we do the check for every single commit, but people may still have forgotten to add a package to the `checkouts.cfg` file. -4. Check packages individually. +1. Check packages individually. Use the `bin/fullrelease` script from the core development buildout. This includes extra checks that we have added in `plone.releaser`. It guides you through all the next steps. - 1. Check changelog. + 1. Check changelog. Check if `CHANGES` is up-to-date. All changes since the last release should be included. A "Fixes" or "New" header should be included, with the relevant changes under it. Upgrade notes are best placed here as well. Compare `git log HEAD...` with `CHANGES`, or from `zest.releaser` use the command `lasttaglog `. - 2. Run [pyroma](https://pypi.org/project/pyroma/). - 3. Run [check-manifest](https://pypi.org/project/check-manifest/). - 4. Check package "best practices" (`README`, `CHANGES`, `src` directory). - 5. Check if the version in `setup.py` is correct and follows our versioning best practice. - 6. Make a release (zest.releaser: `bin/fullrelease`) - 7. Remove packages from auto-checkout section in `checkouts.cfg` and update `versions.cfg`. - -5. Make sure `plone.app.upgrade` contains an upgrade step for the future Plone release. -6. Update CMFPlone version in `profiles/default/metadata.xml`. -7. Create an issue in to ask the i18n team lead @vincentfretin to do a `plone.app.locales` release. -8. Create a pending release (directory) on [dist.plone.org](https://dist.plone.org/). - - 1. Copy all core packages there. - 2. Possibly make an alpha or beta release of CMFPlone. - 3. Copy the `versions.cfg` file from coredev to there. - -9. Write an email to the Plone developers list announcing a pending release. -10. Update `plone.app.locales` version. -11. Create a unified changelog. + 1. Run [pyroma](https://pypi.org/project/pyroma/). + 1. Run [check-manifest](https://pypi.org/project/check-manifest/). + 1. Check package "best practices" (`README`, `CHANGES`, `src` directory). + 1. Check if the version in `setup.py` is correct and follows our versioning best practice. + 1. Make a release with `zest.releaser`: `bin/fullrelease`. + 1. Remove packages from the `auto-checkout` section in `checkouts.cfg`, and update `versions.cfg`. + +1. Make sure `plone.app.upgrade` contains an upgrade step for the future Plone release. +1. Update CMFPlone version in `profiles/default/metadata.xml`. +1. Create an issue in https://github.com/collective/plone.app.locales/issues to ask the i18n team lead `@vincentfretin` to do a `plone.app.locales` release. +1. Create a pending release (directory) on [dist.plone.org](https://dist.plone.org/). + + 1. Copy all core packages there. + 1. Possibly make an alpha or beta release of CMFPlone. + 1. Copy the `versions.cfg` file from coredev to there. + +1. Write an email to the Plone developers list announcing a pending release. +1. Create a post on the Plone Community Forum announcing a pending release. +1. Update `plone.app.locales` version. +1. Create a unified changelog. ```shell bin/manage changelog ``` -12. Make the final release on [dist.plone.org](https://dist.plone.org/) (remove "-pending") -13. Update the "-latest" link on [dist.plone.org](https://dist.plone.org/). -14. For Plone 5.x versions only, create the new release on [Launchpad](https://launchpad.net/plone/). -15. Create a release page on [plone.org](https://plone.org/download/releases) -16. Wait for installers to be uploaded to Launchpad, with a link to the [plone.org](https://plone.org/download/releases) release page. -17. Publish release page on [plone.org](https://plone.org/). -18. Update [plone.org](https://plone.org/) homepage links to point to the new release. -19. Send out announcement to the plone-announce email distribution list. -20. Ask the security team to update the [Hotfixes](https://plone.org/security/hotfixes/) page in the configuration control panel. +1. Make the final release on [dist.plone.org](https://dist.plone.org/) (remove "-pending") +1. Update the "-latest" link on [dist.plone.org](https://dist.plone.org/). +1. For Plone 5.x versions only, create the new release on [Launchpad](https://launchpad.net/plone/). +1. Create a release page on [plone.org](https://plone.org/download/releases) +1. Wait for installers to be uploaded to Launchpad, with a link to the [plone.org](https://plone.org/download/releases) release page. +1. Publish release page on [plone.org](https://plone.org/). +1. Update [plone.org](https://plone.org/) homepage links to point to the new release. +1. Send out announcement to the plone-announce email distribution list for the final release. +1. Create a post on the Plone Community Forum announcing the final release. +1. Ask the security team to update the [Hotfixes](https://plone.org/security/hotfixes/) page in the configuration control panel. From 693d0268cb269567b522c1547ff1eaa02674e75a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 27 Jun 2024 05:23:17 -0700 Subject: [PATCH 326/810] Update troubleshooting.md --- docs/contributing/core/troubleshooting.md | 56 +++++++++++------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/contributing/core/troubleshooting.md b/docs/contributing/core/troubleshooting.md index 7a08cfa17..724a77d20 100644 --- a/docs/contributing/core/troubleshooting.md +++ b/docs/contributing/core/troubleshooting.md @@ -1,55 +1,55 @@ --- myst: html_meta: - "description": "Troubleshooting development issues in Plone" - "property=og:description": "Troubleshooting development issues in Plone" - "property=og:title": "Troubleshooting development issues in Plone" - "keywords": "Troubleshooting, development issues, Plone" + "description": "Troubleshoot development issues in Plone" + "property=og:description": "Troubleshoot development issues in Plone" + "property=og:title": "Troubleshoot development issues in Plone" + "keywords": "Troubleshoot, development issues, Plone" --- -# Troubleshooting +# Troubleshoot This chapter describes how to troubleshoot development issues in Plone. + ## Buildout issues -Buildout can be frustrating for those unfamiliar with parsing through error messages. +This section describes issues you might experience with using buildout. -These errors are normally a quick fix. -### Errors running `bootstrap.py` +### `bootstrap.py` errors -You may not even get to running buildout, before you already get an error. -As example: +When attempting to run buildout via the {file}`bootstrap.py`, the script exits with a `VersionConflict` error message. ```shell File "/usr/local/lib/python2.6/site-packages/distribute-0.6.13-py2.6.egg/pkg_resources.py", line 556, in resolve - raise VersionConflict(dist,req) # XXX put more info here + raise VersionConflict(dist,req) pkg_resources.VersionConflict: (zc.buildout 1.5.1 (/usr/local/lib/python2.6/site-packages/zc.buildout-1.5.1-py2.6.egg), Requirement.parse('zc.buildout==1.5.2')) ``` -Buildout has noticed that the version of buildout required by the file `bootstrap.py` you are trying to run does not match the version of buildout in your Python library. +Buildout has noticed that the version of buildout required by the file `bootstrap.py` does not match the version of buildout in your Python path. In the error above, your system has buildout 1.5.1 installed and the `bootstrap.py` file wants to run with 1.5.2. -To fix, you have a couple options. -First, you can force buildout to run with the version you already have installed by invoking the version tag. -This tells your Plone `bootstrap.py` file to play nicely with the version that you already have installed. -In the case of the error pasted above, that would be: +You have two options to resolve the issue. -```shell -python bootstrap.py --version=1.5.1 -``` +1. You can force buildout to run with the version you already have installed by invoking the version tag. + This tells your Plone {file}`bootstrap.py` file to play nicely with the version that you already have installed. + In the case of the error pasted above, that would be: -The other option is to delete your current egg and force the upgrade. -In the case of the error above, delete the egg the system currently has, for example: + ```shell + python bootstrap.py --version=1.5.1 + ``` -```shell -rm -rf /usr/local/lib/python3.10/site-packages/zc.buildout-1.5.1-py3.10.egg -``` +1. The other option is to delete your current egg and force the upgrade. + In the case of the error above, delete the egg the system currently has, for example: + + ```shell + rm -rf /usr/local/lib/python3.10/site-packages/zc.buildout-1.5.1-py3.10.egg + ``` -When you rerun bootstrap, it will look for the buildout of the egg, note that there isn't one, and then go fetch a new egg in the version that it wants for you. + When you rerun {file}`bootstrap.py`, it will look for the buildout of the egg, note that there isn't one, and then go fetch a new egg in the version that it wants for you. -Do one of those and re-run bootstrap. +Do one of those and re-run {file}`bootstrap.py`. -One other thing of note is that running bootstrap effectively ties that Python executable and all of its libraries to your buildout. -If you have several Python installs, and want to switch which Python is tied to your buildout, rerun `bootstrap.py` with the new Python (and then rerun buildout). +When you run {file}`bootstrap.py`, it effectively ties that Python executable and all of its libraries to your buildout. +If you have several Python installs, and want to switch which Python is tied to your buildout, rerun {file}`bootstrap.py` with the new Python, and then rerun buildout. From 2f8630496b01709593e078f0fe793f5cd636c473 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 27 Jun 2024 05:25:00 -0700 Subject: [PATCH 327/810] Reorder navigation --- docs/contributing/core/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 0041f8229..eadada278 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -301,10 +301,10 @@ See {doc}`continuous-integration` for more information. ```{toctree} :maxdepth: 1 +documentation continuous-integration mrdeveloper -documentation -troubleshooting +troubleshoot plips plip-review package-dependencies From 438b8ef9600f2339c00ac4b4de9b1c873f687049 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 27 Jun 2024 05:25:22 -0700 Subject: [PATCH 328/810] Rename troubleshooting.md to troubleshoot.md --- docs/contributing/core/{troubleshooting.md => troubleshoot.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/contributing/core/{troubleshooting.md => troubleshoot.md} (100%) diff --git a/docs/contributing/core/troubleshooting.md b/docs/contributing/core/troubleshoot.md similarity index 100% rename from docs/contributing/core/troubleshooting.md rename to docs/contributing/core/troubleshoot.md From cd238fe82fd6171bdb3a8361e24b31f23bf49871 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 27 Jun 2024 06:00:09 -0700 Subject: [PATCH 329/810] Replace @vincentfretin with @erral --- docs/contributing/core/release.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/contributing/core/release.md b/docs/contributing/core/release.md index 7439d547a..a45f7336a 100644 --- a/docs/contributing/core/release.md +++ b/docs/contributing/core/release.md @@ -53,7 +53,7 @@ These are: : Please leave these to the release managers, Eric Steele and Maurits van Rees. `plone.app.locales` -: Please leave this to the i18n team lead, Vincent Fretin. +: Please leave this to the i18n team lead, Mikel Larreategi, `@erral` on GitHub. ## Plone core release process checklist @@ -103,7 +103,7 @@ These are: 1. Make sure `plone.app.upgrade` contains an upgrade step for the future Plone release. 1. Update CMFPlone version in `profiles/default/metadata.xml`. -1. Create an issue in https://github.com/collective/plone.app.locales/issues to ask the i18n team lead `@vincentfretin` to do a `plone.app.locales` release. +1. Create an issue in https://github.com/collective/plone.app.locales/issues to ask the i18n team lead `@erral` to do a `plone.app.locales` release. 1. Create a pending release (directory) on [dist.plone.org](https://dist.plone.org/). 1. Copy all core packages there. From b5426e8e7da23766ff8bd6cfd89a4f4167bfa863 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 27 Jun 2024 06:21:50 -0700 Subject: [PATCH 330/810] Add link to active PLIPs GitHub project board. --- docs/contributing/core/plips.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index 6941d6b55..9ab7ffd10 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -13,6 +13,8 @@ A Plone Improvement Proposal, or {term}`PLIP`, is a change to a Plone package th PLIPs go through a formal process compared to bug fixes because of their broad reach. The Plone Framework Team reviews all PLIPs to make sure that it's in the best interest of the broader community, and that it's of high quality. +A project board of active PLIPs is located at https://github.com/orgs/plone/projects/47. + ## Process overview From f11f499f2e430d5c17a6ea761adc2efe0e187665 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 27 Jun 2024 14:24:27 -0700 Subject: [PATCH 331/810] Add CommonJS to Plone's Vale spelling accept file. See https://github.com/plone/volto/pull/6130 --- styles/Vocab/Plone/accept.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/styles/Vocab/Plone/accept.txt b/styles/Vocab/Plone/accept.txt index c93207b67..8d79192ed 100644 --- a/styles/Vocab/Plone/accept.txt +++ b/styles/Vocab/Plone/accept.txt @@ -12,6 +12,7 @@ Barceloneta [Bb]oolean buildout cacheable +CommonJS doctest folderish fieldset From 9df10b5e88b75dce67752adbe7df98b2b0683744 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 27 Jun 2024 17:41:44 -0700 Subject: [PATCH 332/810] Update docs/contributing/core/index.md Co-authored-by: Maurits van Rees --- docs/contributing/core/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index eadada278..6252b03b5 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -105,6 +105,7 @@ Notice that the script expects Python 3.11 to be installed on your system and in ``` Edit it according to the Python version you want to use, then save and close the file. +After you have run the script you should undo the change, otherwise you have a local change in git that you might accidentally commit. ```` Now run the script to install Plone 6. From be8c6ad660b7c14108d719ec5ce8d7f2f1512c27 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 27 Jun 2024 17:44:00 -0700 Subject: [PATCH 333/810] Fix doc link, grammar. --- docs/contributing/core/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 6252b03b5..ced8bce21 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -105,7 +105,7 @@ Notice that the script expects Python 3.11 to be installed on your system and in ``` Edit it according to the Python version you want to use, then save and close the file. -After you have run the script you should undo the change, otherwise you have a local change in git that you might accidentally commit. +After you have run the script, you should undo the change, otherwise you have a local change in git that you might accidentally commit. ```` Now run the script to install Plone 6. @@ -114,7 +114,7 @@ Now run the script to install Plone 6. ./bootstrap.sh ``` -If you run into issues in this process, see {doc}`troubleshooting`. +If you run into issues in this process, see {doc}`troubleshoot`. This will run for a long time if it's your first pull (approximately 10-20 minutes, depending on network speed and your hardware). From 62072af5116247aa5d72b555877d92ae2d2794a9 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 27 Jun 2024 17:46:28 -0700 Subject: [PATCH 334/810] Use chromedriver and ROBOT_BROWSER environment variable Co-authored-by: Maurits van Rees --- docs/contributing/core/index.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index ced8bce21..0887d2f8e 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -254,9 +254,12 @@ It takes 5-10 minutes to run the full unit test suite. ./bin/test ``` -If you run acceptance tests with the `--all` option, it will repeatedly launch and close browser windows that gain focus, disrupting you from doing any other work. +If you run acceptance tests with the `--all` option, it will run tests in a real browser. This takes 30-40 minutes to run. -If you can't afford this disruption, you can defer it to Jenkins. +This may repeatedly launch and close browser windows that gain focus, disrupting you from doing any other work. +If this happens, you can install the `chromedriver` OS package. +See https://developer.chrome.com/docs/chromedriver. +Then run `export ROBOT_BROWSER="headlesschrome"` and again run `bin/test --all`. ```shell # Run acceptance tests From a26ee569fca6bd160ade3990b6673c35ca6d00a1 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 27 Jun 2024 17:52:05 -0700 Subject: [PATCH 335/810] =?UTF-8?q?We=20don't=20use=20`bootstrap.py`.=20Bu?= =?UTF-8?q?rn=20it=20with=20=F0=9F=94=A5!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/contributing/core/index.md | 3 -- docs/contributing/core/release.md | 2 +- docs/contributing/core/troubleshoot.md | 55 -------------------------- 3 files changed, 1 insertion(+), 59 deletions(-) delete mode 100644 docs/contributing/core/troubleshoot.md diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 0887d2f8e..664907983 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -114,8 +114,6 @@ Now run the script to install Plone 6. ./bootstrap.sh ``` -If you run into issues in this process, see {doc}`troubleshoot`. - This will run for a long time if it's your first pull (approximately 10-20 minutes, depending on network speed and your hardware). Once that's done, you can start an instance of Plone with the following command. @@ -308,7 +306,6 @@ See {doc}`continuous-integration` for more information. documentation continuous-integration mrdeveloper -troubleshoot plips plip-review package-dependencies diff --git a/docs/contributing/core/release.md b/docs/contributing/core/release.md index a45f7336a..c4082cc89 100644 --- a/docs/contributing/core/release.md +++ b/docs/contributing/core/release.md @@ -68,7 +68,7 @@ These are: git clone git@github.com:plone/buildout.coredev.git cd buildout.coredev git checkout 6.1 - python bootstrap.py + ./bootstrap.sh bin/buildout -c buildout.cfg ``` diff --git a/docs/contributing/core/troubleshoot.md b/docs/contributing/core/troubleshoot.md deleted file mode 100644 index 724a77d20..000000000 --- a/docs/contributing/core/troubleshoot.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -myst: - html_meta: - "description": "Troubleshoot development issues in Plone" - "property=og:description": "Troubleshoot development issues in Plone" - "property=og:title": "Troubleshoot development issues in Plone" - "keywords": "Troubleshoot, development issues, Plone" ---- - -# Troubleshoot - -This chapter describes how to troubleshoot development issues in Plone. - - -## Buildout issues - -This section describes issues you might experience with using buildout. - - -### `bootstrap.py` errors - -When attempting to run buildout via the {file}`bootstrap.py`, the script exits with a `VersionConflict` error message. - -```shell - File "/usr/local/lib/python2.6/site-packages/distribute-0.6.13-py2.6.egg/pkg_resources.py", line 556, in resolve - raise VersionConflict(dist,req) - pkg_resources.VersionConflict: (zc.buildout 1.5.1 (/usr/local/lib/python2.6/site-packages/zc.buildout-1.5.1-py2.6.egg), Requirement.parse('zc.buildout==1.5.2')) -``` - -Buildout has noticed that the version of buildout required by the file `bootstrap.py` does not match the version of buildout in your Python path. -In the error above, your system has buildout 1.5.1 installed and the `bootstrap.py` file wants to run with 1.5.2. - -You have two options to resolve the issue. - -1. You can force buildout to run with the version you already have installed by invoking the version tag. - This tells your Plone {file}`bootstrap.py` file to play nicely with the version that you already have installed. - In the case of the error pasted above, that would be: - - ```shell - python bootstrap.py --version=1.5.1 - ``` - -1. The other option is to delete your current egg and force the upgrade. - In the case of the error above, delete the egg the system currently has, for example: - - ```shell - rm -rf /usr/local/lib/python3.10/site-packages/zc.buildout-1.5.1-py3.10.egg - ``` - - When you rerun {file}`bootstrap.py`, it will look for the buildout of the egg, note that there isn't one, and then go fetch a new egg in the version that it wants for you. - -Do one of those and re-run {file}`bootstrap.py`. - -When you run {file}`bootstrap.py`, it effectively ties that Python executable and all of its libraries to your buildout. -If you have several Python installs, and want to switch which Python is tied to your buildout, rerun {file}`bootstrap.py` with the new Python, and then rerun buildout. From 0d213ac3fdbf366018e1f75f735e65a2f9342b71 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 27 Jun 2024 17:53:31 -0700 Subject: [PATCH 336/810] s/egg/package Co-authored-by: Maurits van Rees --- docs/contributing/core/release.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/core/release.md b/docs/contributing/core/release.md index c4082cc89..c6f1e6861 100644 --- a/docs/contributing/core/release.md +++ b/docs/contributing/core/release.md @@ -33,7 +33,7 @@ All files mentioned in this list may be written in Markdown or reStructuredText - {file}`README` and {file}`CHANGES` must be visible on PyPI. - Released eggs must contain generated gettext `.mo` files, but these files must not be committed to the repository. The `.mo` files can be created with the `zest.pocompile` add-on, which should be installed together with `zest.releaser`. -- `.gitignore` and `MANIFEST.in` must reflect the files going in to the egg (must include page template and `.po` files). +- `.gitignore` and `MANIFEST.in` must reflect the files going in to the package (must include page template and `.po` files). ```{seealso} [High quality automated package releases for Python with `zest.releaser`](https://opensourcehacker.com/2012/08/14/high-quality-automated-package-releases-for-python-with-zest-releaser/). From 7b19bcb25d2b318e3edbc59f0b2c7bbd3e349302 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 27 Jun 2024 17:54:53 -0700 Subject: [PATCH 337/810] Add maintainers Co-authored-by: Maurits van Rees --- docs/contributing/core/release.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/contributing/core/release.md b/docs/contributing/core/release.md index c6f1e6861..8b6ccfce1 100644 --- a/docs/contributing/core/release.md +++ b/docs/contributing/core/release.md @@ -54,7 +54,11 @@ These are: `plone.app.locales` : Please leave this to the i18n team lead, Mikel Larreategi, `@erral` on GitHub. +`plone.staticresources`, `mockup`, `plonetheme.barceloneta`, `plone.classicui`: +: Please leave this to the Classic UI team, especially Peter Mathis, Johannes Raggam and Maik Derstappen. +`plone.restapi` and `plone.volto`: +: Please leave these to Timo Stollenwerk or David Glick. ## Plone core release process checklist From 4c7badf83102d9a816159af73be19faa9e3d03f0 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 27 Jun 2024 17:59:04 -0700 Subject: [PATCH 338/810] Add GitHub handles to humans --- docs/contributing/core/release.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/contributing/core/release.md b/docs/contributing/core/release.md index 8b6ccfce1..723fb9cc4 100644 --- a/docs/contributing/core/release.md +++ b/docs/contributing/core/release.md @@ -53,12 +53,13 @@ These are: : Please leave these to the release managers, Eric Steele and Maurits van Rees. `plone.app.locales` -: Please leave this to the i18n team lead, Mikel Larreategi, `@erral` on GitHub. +: Please leave this to the i18n team lead, Mikel Larreategi `@erral`. `plone.staticresources`, `mockup`, `plonetheme.barceloneta`, `plone.classicui`: -: Please leave this to the Classic UI team, especially Peter Mathis, Johannes Raggam and Maik Derstappen. +: Please leave this to the Classic UI team, especially Peter Mathis `@petschki`, Johannes Raggam `@thet`, and Maik Derstappen `@MrTango`. `plone.restapi` and `plone.volto`: -: Please leave these to Timo Stollenwerk or David Glick. +: Please leave these to Timo Stollenwerk `@tisto` or David Glick `@davisagli`. + ## Plone core release process checklist From 75f782c13fde418ee429ba522429935ed82d982f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 28 Jun 2024 03:50:27 -0700 Subject: [PATCH 339/810] Restore @plone/framework-team GitHub handle --- docs/contributing/core/plips.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index 9ab7ffd10..a2b422bba 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -41,7 +41,7 @@ If the repository is not listed, use the default repository for `Products.CMFPlo | Package | Repository | Team | |---|---|---| -| `Products.CMFPlone` | https://github.com/plone/Products.CMFPlone | not applicable | +| `Products.CMFPlone` | https://github.com/plone/Products.CMFPlone | `@plone/framework-team` | | Classic UI | https://github.com/plone/plone.classicui | `@plone/ClassicUI-Team` | | Volto | https://github.com/plone/volto | `@plone/volto-team` | From 004370b6e7b18932af9cba683cc45072085bf030 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 28 Jun 2024 03:51:25 -0700 Subject: [PATCH 340/810] s/FWT/designated team --- docs/contributing/core/plips.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index a2b422bba..c523fba5f 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -11,7 +11,7 @@ myst: A Plone Improvement Proposal, or {term}`PLIP`, is a change to a Plone package that would affect everyone who uses that package. PLIPs go through a formal process compared to bug fixes because of their broad reach. -The Plone Framework Team reviews all PLIPs to make sure that it's in the best interest of the broader community, and that it's of high quality. +A designated team reviews all PLIPs to make sure that it's in the best interest of the broader community, and that it's of high quality. A project board of active PLIPs is located at https://github.com/orgs/plone/projects/47. From 4c16ff270dc8056e50e72979785648cf87f310df Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 28 Jun 2024 03:57:12 -0700 Subject: [PATCH 341/810] Update tips submodules/plone.api submodules/volto --- submodules/plone.api | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index b114c588c..f29d2a178 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit b114c588c6b3b3984c2d682db4098912e87d0a48 +Subproject commit f29d2a178b51f659171c4f773fced1d9b3005d3e diff --git a/submodules/volto b/submodules/volto index 50bba48a5..ca3c293b2 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 50bba48a5468cd6c102b8e26dd62b55d1bb1e37b +Subproject commit ca3c293b2379dad38b52b0d8fa33e7ed87105f9c From d78a2d3e478783cb6434a9c2763e279b5b4521ee Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 28 Jun 2024 04:33:35 -0700 Subject: [PATCH 342/810] Add a todo for the Steering Circle --- docs/contributing/core/plips.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index c523fba5f..59143c096 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -45,6 +45,7 @@ If the repository is not listed, use the default repository for `Products.CMFPlo | Classic UI | https://github.com/plone/plone.classicui | `@plone/ClassicUI-Team` | | Volto | https://github.com/plone/volto | `@plone/volto-team` | +%TODO: PENDING CONTACT INFORMATION. If any team has issues with another team's PLIP, or if they have some ideas for PLIPs that could potentially impact other teams, then the Steering Circle is the first point of contact for coordination. If further action or coordination is required, then the Plone Foundation Board would be brought in. https://community.plone.org/t/plips-documentation/19609/14?u=stevepiercy (submit-a-plip-label)= From 7e741c889662893c4ee386621698fa3058104051 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 28 Jun 2024 04:33:57 -0700 Subject: [PATCH 343/810] Add the PLIP to the PLIP project board --- docs/contributing/core/plips.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index 59143c096..32cff6959 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -80,6 +80,8 @@ Now that you are prepared, submit your PLIP. 5. If GitHub does not automatically assign the label {guilabel}`03 type: feature (plip)`, then assign that label to the issue to make it easier to find. +6. If GitHub does not automatically add the PLIP to the [PLIP project board](https://github.com/orgs/plone/projects/47), then add it so it can be tracked. + ## Get feedback From ad7dce19a7d0aeb131c860a81f33878a5f54bfb0 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 29 Jun 2024 03:12:20 -0700 Subject: [PATCH 344/810] Remove TODO for Steering Circle, as it is not a relevant body to review PLIPs in a timely and effective manner, given it only meets monthly as a stand-up meeting --- docs/contributing/core/plips.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index 32cff6959..c7b8b17eb 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -45,7 +45,6 @@ If the repository is not listed, use the default repository for `Products.CMFPlo | Classic UI | https://github.com/plone/plone.classicui | `@plone/ClassicUI-Team` | | Volto | https://github.com/plone/volto | `@plone/volto-team` | -%TODO: PENDING CONTACT INFORMATION. If any team has issues with another team's PLIP, or if they have some ideas for PLIPs that could potentially impact other teams, then the Steering Circle is the first point of contact for coordination. If further action or coordination is required, then the Plone Foundation Board would be brought in. https://community.plone.org/t/plips-documentation/19609/14?u=stevepiercy (submit-a-plip-label)= From f42e0b700997e0fc2a4c7cb9385053c16b15bb0c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 29 Jun 2024 03:23:33 -0700 Subject: [PATCH 345/810] Update tips submodules/plone.api submodules/plone.restapi submodules/volto --- submodules/plone.api | 2 +- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index b114c588c..f29d2a178 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit b114c588c6b3b3984c2d682db4098912e87d0a48 +Subproject commit f29d2a178b51f659171c4f773fced1d9b3005d3e diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 9d11653fe..86e62411c 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 9d11653fe2da0c50ee4d74bef1d8a416879c4168 +Subproject commit 86e62411cb9910c907facd428219690fc8a1307c diff --git a/submodules/volto b/submodules/volto index 50bba48a5..51bdfa0bd 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 50bba48a5468cd6c102b8e26dd62b55d1bb1e37b +Subproject commit 51bdfa0bd4d1b3b726855da0a0e6ad2880271b29 From add1c99653b4d6fcd2a5b3f10accba7f7b5478cf Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 28 Jun 2024 04:33:35 -0700 Subject: [PATCH 346/810] Add a todo for the Steering Circle --- docs/contributing/core/plips.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index c523fba5f..59143c096 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -45,6 +45,7 @@ If the repository is not listed, use the default repository for `Products.CMFPlo | Classic UI | https://github.com/plone/plone.classicui | `@plone/ClassicUI-Team` | | Volto | https://github.com/plone/volto | `@plone/volto-team` | +%TODO: PENDING CONTACT INFORMATION. If any team has issues with another team's PLIP, or if they have some ideas for PLIPs that could potentially impact other teams, then the Steering Circle is the first point of contact for coordination. If further action or coordination is required, then the Plone Foundation Board would be brought in. https://community.plone.org/t/plips-documentation/19609/14?u=stevepiercy (submit-a-plip-label)= From ca03c8727a67bf9c53fde9aafb1fc44d18908579 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 28 Jun 2024 04:33:57 -0700 Subject: [PATCH 347/810] Add the PLIP to the PLIP project board --- docs/contributing/core/plips.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index 59143c096..32cff6959 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -80,6 +80,8 @@ Now that you are prepared, submit your PLIP. 5. If GitHub does not automatically assign the label {guilabel}`03 type: feature (plip)`, then assign that label to the issue to make it easier to find. +6. If GitHub does not automatically add the PLIP to the [PLIP project board](https://github.com/orgs/plone/projects/47), then add it so it can be tracked. + ## Get feedback From e5dae084c1d465c0e555655a85578e5fa76a14b6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 29 Jun 2024 03:12:20 -0700 Subject: [PATCH 348/810] Remove TODO for Steering Circle, as it is not a relevant body to review PLIPs in a timely and effective manner, given it only meets monthly as a stand-up meeting --- docs/contributing/core/plips.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/contributing/core/plips.md b/docs/contributing/core/plips.md index 32cff6959..c7b8b17eb 100644 --- a/docs/contributing/core/plips.md +++ b/docs/contributing/core/plips.md @@ -45,7 +45,6 @@ If the repository is not listed, use the default repository for `Products.CMFPlo | Classic UI | https://github.com/plone/plone.classicui | `@plone/ClassicUI-Team` | | Volto | https://github.com/plone/volto | `@plone/volto-team` | -%TODO: PENDING CONTACT INFORMATION. If any team has issues with another team's PLIP, or if they have some ideas for PLIPs that could potentially impact other teams, then the Steering Circle is the first point of contact for coordination. If further action or coordination is required, then the Plone Foundation Board would be brought in. https://community.plone.org/t/plips-documentation/19609/14?u=stevepiercy (submit-a-plip-label)= From 113d9b36ed0fc8a2ac2c72876081780aca86971c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 29 Jun 2024 03:32:48 -0700 Subject: [PATCH 349/810] Revert "Update tips submodules/plone.api submodules/volto" This reverts commit 4c16ff270dc8056e50e72979785648cf87f310df. --- submodules/plone.api | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index f29d2a178..b114c588c 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit f29d2a178b51f659171c4f773fced1d9b3005d3e +Subproject commit b114c588c6b3b3984c2d682db4098912e87d0a48 diff --git a/submodules/volto b/submodules/volto index ca3c293b2..50bba48a5 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit ca3c293b2379dad38b52b0d8fa33e7ed87105f9c +Subproject commit 50bba48a5468cd6c102b8e26dd62b55d1bb1e37b From 3f38b6b61d2ad5908de99a5ac7e9a52c325d28ae Mon Sep 17 00:00:00 2001 From: Peter Mathis Date: Mon, 1 Jul 2024 08:51:35 +0200 Subject: [PATCH 350/810] Add link to Patternslib dependencies --- docs/classic-ui/module-federation.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index b46bf9aa0..ced3cd7b5 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -47,7 +47,8 @@ const mf_config = require("@patternslib/dev/webpack/webpack.mf"); ``` Import all the dependencies you want to share. -Potentially these are the ones from Patternslib, Mockup, and your own dependencies. +Potentially these are the ones from [Patternslib](https://github.com/Patternslib/Patterns/blob/master/package.json), +Mockup, and your own dependencies. You can add the Patternslib and Mockup dependencies, even if you are not using them. ```js From 51842fd16694f2b5d3a7cabd131f82a0bb091350 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 1 Jul 2024 02:45:35 -0700 Subject: [PATCH 351/810] One sentence per line --- docs/classic-ui/module-federation.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index ced3cd7b5..83c180253 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -47,8 +47,7 @@ const mf_config = require("@patternslib/dev/webpack/webpack.mf"); ``` Import all the dependencies you want to share. -Potentially these are the ones from [Patternslib](https://github.com/Patternslib/Patterns/blob/master/package.json), -Mockup, and your own dependencies. +Potentially these are the ones from [Patternslib](https://github.com/Patternslib/Patterns/blob/master/package.json), Mockup, and your own dependencies. You can add the Patternslib and Mockup dependencies, even if you are not using them. ```js From 98267c79e063e42ca186ca0a4238038c51aea417 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 1 Jul 2024 02:49:58 -0700 Subject: [PATCH 352/810] Proper casing of module, federation, and Mockup --- docs/classic-ui/module-federation.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index 83c180253..9cb184106 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -1,16 +1,16 @@ --- html_meta: - "description": "How to use Module Federation in Mockup and add-on bundles." - "property=og:description": "How to use Module Federation in Mockup and add-on bundles." - "property=og:title": "Module Federation in Mockup" - "keywords": "Plone, Classic UI, classic-ui, Mockup, mockup, module federation, webpack, JavaScript" + "description": "How to use module federation in Mockup and add-on bundles." + "property=og:description": "How to use module federation in Mockup and add-on bundles." + "property=og:title": "Module federation in Mockup" + "keywords": "Plone, Classic UI, classic-ui, Mockup, module federation, webpack, JavaScript" --- (classic-ui-module-federation-in-mockup-label)= # Module federation in Mockup -Module Federation allows sharing of dependencies between bundles. +Module federation allows sharing of dependencies between bundles. Each bundle includes the whole set of dependencies. However, if multiple bundles have the same dependencies, then they are loaded only once. @@ -18,11 +18,11 @@ For example, if bundle A and B both depend on jQuery and bundle A has already lo But if only bundle B is loaded, it uses its own bundled version of the jQuery library. There is a host bundle, as in the fictional example above, our bundle A. -In Plone the host bundle is the main mockup bundle. +In Plone the host bundle is the main Mockup bundle. Add-ons can add bundles called "remotes" which are initialized for module federation by the host bundle. ```{seealso} -Webpack's documentation on [Module Federation](https://webpack.js.org/concepts/module-federation/). +Webpack's documentation on [module federation](https://webpack.js.org/concepts/module-federation/). ``` From 9a80b1b3f4eef2ee0d4560cd3f6bb3b10ee01428 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 1 Jul 2024 03:03:19 -0700 Subject: [PATCH 353/810] Revert to `Module Federation` because webpack breaks the rules of English --- docs/classic-ui/module-federation.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index 9cb184106..eb380dc84 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -1,16 +1,16 @@ --- html_meta: - "description": "How to use module federation in Mockup and add-on bundles." - "property=og:description": "How to use module federation in Mockup and add-on bundles." - "property=og:title": "Module federation in Mockup" - "keywords": "Plone, Classic UI, classic-ui, Mockup, module federation, webpack, JavaScript" + "description": "How to use Module Federation in Mockup and add-on bundles." + "property=og:description": "How to use Module Federation in Mockup and add-on bundles." + "property=og:title": "Module Federation in Mockup" + "keywords": "Plone, Classic UI, classic-ui, Mockup, Module Federation, webpack, JavaScript" --- (classic-ui-module-federation-in-mockup-label)= -# Module federation in Mockup +# Module Federation in Mockup -Module federation allows sharing of dependencies between bundles. +Module Federation allows sharing of dependencies between bundles. Each bundle includes the whole set of dependencies. However, if multiple bundles have the same dependencies, then they are loaded only once. @@ -19,14 +19,14 @@ But if only bundle B is loaded, it uses its own bundled version of the jQuery li There is a host bundle, as in the fictional example above, our bundle A. In Plone the host bundle is the main Mockup bundle. -Add-ons can add bundles called "remotes" which are initialized for module federation by the host bundle. +Add-ons can add bundles called "remotes" which are initialized for Module Federation by the host bundle. ```{seealso} -Webpack's documentation on [module federation](https://webpack.js.org/concepts/module-federation/). +Webpack's documentation on [Module Federation](https://webpack.js.org/concepts/module-federation/). ``` -## Use module federation +## Use Module Federation If you created an add-on with a Mockup pattern, and you want to include the respective JavaScript code in your theme code, then the following instructions are for you. @@ -38,7 +38,7 @@ Create a new entry point {file}`index.js` which only imports the normal entry po import("./patterns"); ``` -Next add the module federation plugin in {file}`webpack.config.js`. +Next add the Module Federation plugin in {file}`webpack.config.js`. There is a configuration factory `mf_config` which you can use for that. Add the following line near the top of the file. From 50f8fe16108a15aa9fdadc4655d0037aee3c2599 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 7 Jul 2024 07:58:59 -0700 Subject: [PATCH 354/810] Use `-s` for a package Co-authored-by: Gil Forcada Codinachs --- docs/contributing/core/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 664907983..19f156d3d 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -233,10 +233,10 @@ Now you can edit your code without affecting the original branch. If you change the expected behavior of a feature in a package, you should write a test to cover the change. -To run a test for the specific package that you modified, use the `-m` option followed by the package name, as shown in the following example. +To run a test for the specific package that you modified, use the `-s` option followed by the package name, as shown in the following example. ```shell -./bin/test -m plone.app.event +./bin/test -s plone.app.event ``` If any test fails, do not commit and push the changes. From 53e678bfe1a6ba9fca1ed8eeba7d3992466997c4 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 7 Jul 2024 08:19:01 -0700 Subject: [PATCH 355/810] Fix typo Co-authored-by: Gil Forcada Codinachs --- docs/contributing/core/plip-review.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/core/plip-review.md b/docs/contributing/core/plip-review.md index 4ec0c0184..13d06d1ee 100644 --- a/docs/contributing/core/plip-review.md +++ b/docs/contributing/core/plip-review.md @@ -86,7 +86,7 @@ This section describes considerations of code quality. - Is this code maintainable? - Is the code properly documented? - Does the code adhere to formatting and style standards? -- Are there any importied deprecated modules? +- Are there any imported deprecated modules? ### JavaScript From 9012f30bae46b53e904501130cbee7e973809412 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 7 Jul 2024 20:22:59 -0700 Subject: [PATCH 356/810] Add labels for refs --- docs/classic-ui/theming/from-scratch.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/classic-ui/theming/from-scratch.md b/docs/classic-ui/theming/from-scratch.md index 688431e6c..78e22c28f 100644 --- a/docs/classic-ui/theming/from-scratch.md +++ b/docs/classic-ui/theming/from-scratch.md @@ -25,6 +25,8 @@ Theming based on a filesystem package without any dependency. - No Diazo needed +(classic-ui-theming-from-scratch-package-label)= + ## Theme package - Create a theme package as explained here. @@ -33,6 +35,8 @@ Theming based on a filesystem package without any dependency. - Static files +(classic-ui-theming-from-scratch-static-files-label)= + ## Static files Register directory to keep static files @@ -49,6 +53,9 @@ Directory: `src/plonetheme/munich/browser/static` /> ``` + +(classic-ui-theming-from-scratch-theme-label)= + ## Theme ### Manifest @@ -161,7 +168,7 @@ To do so, follow this guide. - Add a script in {file}`package.json` to compile the CSS. ```json - "css-compile-main": "sass --load-path=node_modules --style expanded --source-map --embed-sources --no-error-css plone.scss:../static/plone.css" + "css-compile-main": "sass --load-path=node_modules --style expanded --source-map --embed-sources --no-error-css plone.scss:../static/plone.css" ``` ```{tip} From 31803308a7fcbf6b9fad51d5b1affc87741e43e6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 7 Jul 2024 20:33:01 -0700 Subject: [PATCH 357/810] Change page title to reflect content --- docs/classic-ui/mockup.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/classic-ui/mockup.md b/docs/classic-ui/mockup.md index e053303e8..b2fcc43e8 100644 --- a/docs/classic-ui/mockup.md +++ b/docs/classic-ui/mockup.md @@ -3,13 +3,13 @@ myst: html_meta: "description": "Mockup together with Patternslib are used to build the UI toolkit for Classic UI, a frontend for Plone." "property=og:description": "Mockup together with Patternslib are used to build the UI toolkit for Classic UI, a frontend for Plone." - "property=og:title": "Mockup" + "property=og:title": "Mockup and Patternslib" "keywords": "Mockup, Patternslib, Classic UI, frontend, Plone" --- -(mockup-label)= +(mockup-and-patternslib-label)= -# Mockup +# Mockup and Patternslib {term}`Mockup` together with {term}`Patternslib` are used to build the UI toolkit for {term}`Classic UI`, a frontend for Plone. From e6de265434240cb97d03c8b7f2200925abd2bad2 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 7 Jul 2024 20:33:30 -0700 Subject: [PATCH 358/810] Pull reference from PR 1275 and place in proper context. --- docs/classic-ui/static-resources.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/classic-ui/static-resources.md b/docs/classic-ui/static-resources.md index 0594a42a6..84a8aec56 100644 --- a/docs/classic-ui/static-resources.md +++ b/docs/classic-ui/static-resources.md @@ -14,6 +14,10 @@ myst: We often want to ship a website with a static resource, such as an image, icon, CSS, or JavaScript file. For this, we need to register static resources. +```{seealso} +For some additional implementation information, see {ref}`classic-ui-theming-from-scratch-theme-label`. +``` + (classic-ui-static-resources-registering-label)= @@ -96,4 +100,4 @@ The following attributes are available for registering a static resource: ## Loading order of resources -`depends` is used to define the loading order of resources, by specifying the name of the depending bundle. +`depends` is used to define the loading order of resources by specifying the name of the depending bundle. From 6ddacc63e49b841508b970f6f32b26c0025c7914 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 7 Jul 2024 20:34:43 -0700 Subject: [PATCH 359/810] Trim whitespace --- docs/classic-ui/module-federation.md | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index eb380dc84..fab33a89b 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -59,24 +59,24 @@ const package_json_patternslib = require("@patternslib/patternslib/package.json" Then find the following line. ```js - config = patternslib_config(env, argv, config, ["@plone/mockup"]); +config = patternslib_config(env, argv, config, ["@plone/mockup"]); ``` Below this line add the following. ```js - config.plugins.push( - mf_config({ - name: "myaddon", - filename: "myaddon-remote.min.js", - remote_entry: config.entry["myaddon.min"], - dependencies: { - ...package_json_patternslib.dependencies, - ...package_json_mockup.dependencies, - ...package_json.dependencies, - }, - }) - ); +config.plugins.push( + mf_config({ + name: "myaddon", + filename: "myaddon-remote.min.js", + remote_entry: config.entry["myaddon.min"], + dependencies: { + ...package_json_patternslib.dependencies, + ...package_json_mockup.dependencies, + ...package_json.dependencies, + }, + }) +); ``` Replace the name `myaddon` with your add-on bundle's unique name. @@ -93,7 +93,7 @@ To preserve compatibility with older add-ons and JavaScript implementations, the Constructs like the following still work: ```js - (function($) { - // JS code which uses $ - })(jQuery); +(function($) { + // JS code which uses $ +})(jQuery); ``` From 5e3c3bc9518c899ccfa461bc3be24124d1475916 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 7 Jul 2024 20:48:45 -0700 Subject: [PATCH 360/810] Port content from #1275 --- docs/classic-ui/mockup.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/docs/classic-ui/mockup.md b/docs/classic-ui/mockup.md index b2fcc43e8..15a5fbe4e 100644 --- a/docs/classic-ui/mockup.md +++ b/docs/classic-ui/mockup.md @@ -4,7 +4,7 @@ myst: "description": "Mockup together with Patternslib are used to build the UI toolkit for Classic UI, a frontend for Plone." "property=og:description": "Mockup together with Patternslib are used to build the UI toolkit for Classic UI, a frontend for Plone." "property=og:title": "Mockup and Patternslib" - "keywords": "Mockup, Patternslib, Classic UI, frontend, Plone" + "keywords": "Mockup, Patternslib, Classic UI, plonecli, bobtemplates.plone, mr.bob, frontend, Plone" --- (mockup-and-patternslib-label)= @@ -15,4 +15,27 @@ myst: View the [interactive documentation of Mockup](https://plone.github.io/mockup/). -For more information, visit the [Mockup repository on GitHub](https://github.com/plone/mockup). + +## Get started + +[bobtemplates.plone](https://github.com/plone/bobtemplates.plone) provides [mr.bob](https://mrbob.readthedocs.io/en/latest/) templates to generate packages for Plone projects. +[plonecli](https://github.com/plone/plonecli) provides a command line client for bobtemplates.plone. + +Install plonecli into your Python user packages to make it available to all your projects. + +```shell +pip install plonecli --user +``` + +Create a theme package add-on with {term}`plonecli`. + +```shell +plonecli add mockup_pattern +``` + + +## References + +- {ref}`v60-mockup-resource-registry-label` in Plone 6.0 +- [Mockup repository on GitHub](https://github.com/plone/mockup) +- [Patternslib](https://patternslib.com/) From e29ace948bee9c7b4d76776c8fa94883570d8c3e Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Mon, 8 Jul 2024 14:15:34 +0200 Subject: [PATCH 361/810] chore(classic-ui/images): add a code snippet That showcases how to generate a responsive image with it `srcset`. --- docs/classic-ui/images.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/classic-ui/images.md b/docs/classic-ui/images.md index 6bfd771c1..5025797ff 100644 --- a/docs/classic-ui/images.md +++ b/docs/classic-ui/images.md @@ -291,6 +291,14 @@ Additionally, you can define [media queries](https://developer.mozilla.org/en-US The configuration allows you to define different picture variants, such as `Large`, `Medium`, or `Small`. Users can choose from them in editors, such as TinyMCE, and developers can use them in templates. +To generate a `picture` tag, use: + +```python +from plone import api + +scale_util = api.content.get_view("images", context, request) +tag = scale_util.picture("image", scale='larger', picture_variant='large') +``` (classic-ui-images-responsive-image-support-picture-variants)= @@ -533,4 +541,4 @@ This information shows we have everything we need to generate our image URLs, wi width="${python: preview['width']}" height="${python: preview['height']}" /> -``` \ No newline at end of file +``` From 558ea1070b08cf4cc4d4f03895fe18e1de3ebf37 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 8 Jul 2024 06:35:28 -0700 Subject: [PATCH 362/810] `picture` is an inline literal --- docs/classic-ui/images.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/classic-ui/images.md b/docs/classic-ui/images.md index 5025797ff..4105cb9a1 100644 --- a/docs/classic-ui/images.md +++ b/docs/classic-ui/images.md @@ -285,10 +285,10 @@ To access image scales, which are normally not accessible to the current user, o ## Responsive image support -Plone supports the generation of picture tags with `srcset`s for image optimization. +Plone supports the generation of `picture` tags with `srcset`s for image optimization. Additionally, you can define [media queries](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries/Using_media_queries) for [art direction](classic-ui-images-responsive-image-support-art-direction) and further optimization. -The configuration allows you to define different picture variants, such as `Large`, `Medium`, or `Small`. +The configuration allows you to define different `picture` variants, such as `Large`, `Medium`, or `Small`. Users can choose from them in editors, such as TinyMCE, and developers can use them in templates. To generate a `picture` tag, use: @@ -302,9 +302,9 @@ tag = scale_util.picture("image", scale='larger', picture_variant='large') (classic-ui-images-responsive-image-support-picture-variants)= -### Picture variants +### `picture` variants -In `/@@imaging-controlpanel` Plone allows you to define picture variants with a list of available image scales. +In `/@@imaging-controlpanel` Plone allows you to define `picture` variants with a list of available image scales. These are used for HTML {term}`srcset` attributes. A `srcset` attribute can help the browser to serve the best fitting image size for the current user's display. @@ -404,10 +404,10 @@ This means the generated `srcset` will contain the scales from `preview` up to ` (classic-ui-images-responsive-image-support-picture-variant-in-editor)= -#### Hiding a picture variant in editors +#### Hiding a `picture` variant in editors -It is possible to hide a picture variant in editors. -This is useful when you want to define a picture variant to be used in templates only. +It is possible to hide a `picture` variant in editors. +This is useful when you want to define a `picture` variant to be used in templates only. ```json "leadimage": { From 397eaba4731674c30c16f0e3df4a71fae590ef93 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 8 Jul 2024 06:36:14 -0700 Subject: [PATCH 363/810] Add reference to MDN picture tag --- docs/classic-ui/images.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/classic-ui/images.md b/docs/classic-ui/images.md index 4105cb9a1..e13e3b85a 100644 --- a/docs/classic-ui/images.md +++ b/docs/classic-ui/images.md @@ -285,7 +285,7 @@ To access image scales, which are normally not accessible to the current user, o ## Responsive image support -Plone supports the generation of `picture` tags with `srcset`s for image optimization. +Plone supports the generation of [`picture`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture) tags with `srcset`s for image optimization. Additionally, you can define [media queries](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries/Using_media_queries) for [art direction](classic-ui-images-responsive-image-support-art-direction) and further optimization. The configuration allows you to define different `picture` variants, such as `Large`, `Medium`, or `Small`. From 4251ba6723694fbc9296bab125a7c4fcedba723e Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Mon, 8 Jul 2024 18:02:25 +0200 Subject: [PATCH 364/810] Apply suggestions from code review Co-authored-by: Steve Piercy --- docs/classic-ui/images.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/classic-ui/images.md b/docs/classic-ui/images.md index e13e3b85a..2883ec49a 100644 --- a/docs/classic-ui/images.md +++ b/docs/classic-ui/images.md @@ -291,13 +291,13 @@ Additionally, you can define [media queries](https://developer.mozilla.org/en-US The configuration allows you to define different `picture` variants, such as `Large`, `Medium`, or `Small`. Users can choose from them in editors, such as TinyMCE, and developers can use them in templates. -To generate a `picture` tag, use: +To generate a `picture` tag, use the following code. ```python from plone import api scale_util = api.content.get_view("images", context, request) -tag = scale_util.picture("image", scale='larger', picture_variant='large') +tag = scale_util.picture("image", scale="larger", picture_variant="large") ``` (classic-ui-images-responsive-image-support-picture-variants)= From af3bed1481dd9d308b9176e901a38e7db2ce9eba Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Thu, 11 Jul 2024 09:59:17 +0200 Subject: [PATCH 365/810] Add template example --- docs/classic-ui/images.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/classic-ui/images.md b/docs/classic-ui/images.md index 2883ec49a..ba8f0961c 100644 --- a/docs/classic-ui/images.md +++ b/docs/classic-ui/images.md @@ -300,6 +300,14 @@ scale_util = api.content.get_view("images", context, request) tag = scale_util.picture("image", scale="larger", picture_variant="large") ``` +The same can be done from a template; + +```xml +
+ +
+``` + (classic-ui-images-responsive-image-support-picture-variants)= ### `picture` variants From 200e0b1ece203a097b156ea18cd08f84cfc9f08f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 11 Jul 2024 03:48:58 -0700 Subject: [PATCH 366/810] Update docs/classic-ui/images.md --- docs/classic-ui/images.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/classic-ui/images.md b/docs/classic-ui/images.md index ba8f0961c..fe7b2c568 100644 --- a/docs/classic-ui/images.md +++ b/docs/classic-ui/images.md @@ -300,7 +300,7 @@ scale_util = api.content.get_view("images", context, request) tag = scale_util.picture("image", scale="larger", picture_variant="large") ``` -The same can be done from a template; +The same can be done from a template. ```xml
From a68f9ad92e29e7aa7f5d5f28e1d9c867706bccda Mon Sep 17 00:00:00 2001 From: David Ichim Date: Sun, 14 Jul 2024 11:13:44 +0300 Subject: [PATCH 367/810] Modified link to docker docs for persistent data and updated the Arbitrary user title --- docs/install/containers/images/backend.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/install/containers/images/backend.md b/docs/install/containers/images/backend.md index 20f2f2027..789ce3be7 100644 --- a/docs/install/containers/images/backend.md +++ b/docs/install/containers/images/backend.md @@ -31,7 +31,7 @@ There are several ways to store data used by applications that run in Docker con We encourage users of the `Plone` images to familiarize themselves with the options available. -[The Docker documentation](https://docs.docker.com/) is a good starting point for understanding the different storage options and variations. +[The Docker documentation](https://docs.docker.com/guides/docker-concepts/running-containers/persisting-container-data) is a good starting point for understanding the different storage options and variations. ## Configuration Variables @@ -375,7 +375,7 @@ when Plone starts. ## Advanced usage -### Arbitrary `--user` +### Arbitrary `--user` and persisting data using `docker volumes` This image supports running as a (mostly) arbitrary user via `--user` on `docker run`, as long as the owner of `/data` matches: From face787e544ae5b8f4772b26854f57513d8f6b21 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 17 Jul 2024 12:37:21 +0200 Subject: [PATCH 368/810] Expand upon @ichim-david's original addition --- docs/install/containers/images/backend.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/install/containers/images/backend.md b/docs/install/containers/images/backend.md index 789ce3be7..a2c629fb8 100644 --- a/docs/install/containers/images/backend.md +++ b/docs/install/containers/images/backend.md @@ -374,22 +374,30 @@ when Plone starts. ## Advanced usage +This section describes advanced usage of the Plone backend Docker image. -### Arbitrary `--user` and persisting data using `docker volumes` -This image supports running as a (mostly) arbitrary user via `--user` on `docker run`, as long as the owner of `/data` matches: +### Arbitrary user and persistent data + +You can run Docker as an arbitrary user with the `--user` option. + +To persist backend data between restarts of Docker, use both options of `--user` and `-v`. + +The following command will run the Plone backend container as an arbitrary user, and persist the backend data in a volume, provided that the owner of the directory `/data` is the same as the `--user` option. ```shell docker run --user="$(id -u)" -v $(pwd)/data:/data plone/plone-backend ``` -The main caveat to note is that some environment variables, such as `ADDONS` and `DEVELOP`, will not work: +````{note} +Some environment variables, such as `ADDONS` and `DEVELOP`, will not work. ```console $ docker run --user="$(id -u)" -v $(pwd)/data:/data -e ADDONS="eea.facetednavigation" plone/plone-backend ... error: [Errno 13] Permission denied: '/app/lib/python3.9/site-packages/eea' ``` +```` ### Multiple containers with ZEO From 7bbffc1083adbc4a21833c229e69a60ab00b0e0f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 18 Jul 2024 03:16:54 +0200 Subject: [PATCH 369/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 51bdfa0bd..6c4442415 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 51bdfa0bd4d1b3b726855da0a0e6ad2880271b29 +Subproject commit 6c4442415ac16293e48ce6e0a18c4ab7d9352abd From 95f74be808a0cb03a2fc688f78830402ba5245c8 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 18 Jul 2024 03:50:50 +0200 Subject: [PATCH 370/810] Synch with latest dist reqs. Closes #1680 --- requirements-initial.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements-initial.txt b/requirements-initial.txt index eb8815a12..454722d5b 100644 --- a/requirements-initial.txt +++ b/requirements-initial.txt @@ -1,4 +1,4 @@ # From https://dist.plone.org/release/6-latest/constraints.txt -pip==23.2 -setuptools==68.0.0 -wheel==0.40.0 +pip==24.0 +setuptools==71.0.0 +wheel==0.43.0 From f41d1229ca97cade1be8d5882a17b04ee328d200 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 20 Jul 2024 13:20:45 +0200 Subject: [PATCH 371/810] Use relative links to ensure static files get copied during documentation build --- docs/contributing/documentation/myst-reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/documentation/myst-reference.md b/docs/contributing/documentation/myst-reference.md index 7c922d74a..e9d48224e 100644 --- a/docs/contributing/documentation/myst-reference.md +++ b/docs/contributing/documentation/myst-reference.md @@ -222,7 +222,7 @@ Example MyST syntax is shown below. `````{example} ````{only} not text -```{video} /_static/user-manual/blocks/block-copy-cut.mp4 +```{video} ../../volto/_static/user-manual/blocks/block-copy-cut.mp4 ``` ```` ````` From b791e72ee4cbfbb79765df8f9614c2783133a878 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 20 Jul 2024 13:55:05 +0200 Subject: [PATCH 372/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 6c4442415..f7adcdc08 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 6c4442415ac16293e48ce6e0a18c4ab7d9352abd +Subproject commit f7adcdc08491449a90fa546e3fded078dfc1eaf0 From b4f87faafea09f340d68b0b8d12389bb44e0c080 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 20 Jul 2024 14:13:50 +0200 Subject: [PATCH 373/810] Comment out continuous-integration and silence Sphinx warning --- docs/conf.py | 1 + docs/contributing/core/index.md | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index a1f2ff984..13a8ca8af 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -125,6 +125,7 @@ "**/CONTRIBUTORS.rst", "**/LICENSE.rst", "**/README.rst", + "contributing/core/continuous-integration.md", "plone.restapi/.*", "plone.restapi/bin", "plone.restapi/docs/source/glossary.md", # There can be only one Glossary. diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 19f156d3d..0a02f6691 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -295,7 +295,7 @@ Plone has a continuous integration ({term}`CI`) setup and follows CI rules. When you push a change to a Plone package, there may be GitHub workflows that run automatically. The CI package [mr.roboto](https://github.com/plone/mr.roboto) will perform some checks and suggest that you run Jenkins after all other CI runs. -See {doc}`continuous-integration` for more information. +%% See {doc}`continuous-integration` for more information. ## Additional material @@ -304,7 +304,7 @@ See {doc}`continuous-integration` for more information. :maxdepth: 1 documentation -continuous-integration +%% continuous-integration mrdeveloper plips plip-review From 73524a49289be792c51ff029cc21a95ed2e260b4 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 20 Jul 2024 14:24:07 +0200 Subject: [PATCH 374/810] Purge coredev directory of now obsolete files --- coredev/agreement.md | 67 -- coredev/continous-integration.md | 109 ---- coredev/contributors_agreement_explained.md | 100 --- coredev/culture.md | 30 - coredev/documentation.md | 113 ---- coredev/getting-started-with-development.md | 391 ------------ coredev/git.md | 640 -------------------- coredev/guidelines.md | 57 -- coredev/index.md | 67 -- coredev/mrdeveloper.md | 40 -- coredev/packages-dependencies.md | 372 ------------ coredev/plip-review.md | 119 ---- coredev/plips.md | 299 --------- coredev/release.md | 136 ----- coredev/roboto.md | 63 -- coredev/troubleshooting.md | 186 ------ 16 files changed, 2789 deletions(-) delete mode 100644 coredev/agreement.md delete mode 100644 coredev/continous-integration.md delete mode 100644 coredev/contributors_agreement_explained.md delete mode 100644 coredev/culture.md delete mode 100644 coredev/documentation.md delete mode 100644 coredev/getting-started-with-development.md delete mode 100644 coredev/git.md delete mode 100644 coredev/guidelines.md delete mode 100644 coredev/index.md delete mode 100644 coredev/mrdeveloper.md delete mode 100644 coredev/packages-dependencies.md delete mode 100644 coredev/plip-review.md delete mode 100644 coredev/plips.md delete mode 100644 coredev/release.md delete mode 100644 coredev/roboto.md delete mode 100644 coredev/troubleshooting.md diff --git a/coredev/agreement.md b/coredev/agreement.md deleted file mode 100644 index a95b9a8cf..000000000 --- a/coredev/agreement.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -myst: - html_meta: - "description": "Contributing to Plone" - "property=og:description": "Contributing to Plone" - "property=og:title": "Contributing to Plone" - "keywords": "Contributing, Plone" ---- - -```{todo} -All this can go, it's redundant -``` - -(contributing-to-plone-label)= - -# Contributing to Plone - -There are many people and companies who rely on Plone on a day-to-day basis, so we must enforce some level of code quality control. - -Plone's source code is hosted in git repositories at , but only members of the developer team have commit rights. - -Sending in a contributors agreement does not guarantee your commit access to the repositories, but once you send it in we will always have it on file for when you are ready to contribute. - -We ask that before requesting core access you familiarize yourself a little with the community since they will help you get ramped up: - -- Ask and (especially) answer questions on [the Plone forum](https://community.plone.org/) and in {doc}`Plone chat ` with a focus on getting to know the active developers a bit. - -- Attend a [conference](https://plone.org/news-and-events/events/plone-conferences), [symposium](https://plone.org/news-and-events/events/regional), or participate in a [sprint](https://plone.org/news-and-events/events/sprints). - - There are plenty of opportunities to meet the community and start contributing through various coding sessions, either in person or on the web. - - You may even be able to get immediate core access at a conference if you are flexing your mad coding skills and the right people are attending. - -- Get your feet wet by contributing to the [collective](https://collective.github.io/). - Don't worry about getting it perfect or asking for help. - This way you get to know us and we improve our code together as a community. - -- **Patches:** Historically we encouraged people to submit patches to the ticket collector. - These tickets are usually ignored forever. - Technically, for us to accept your patch, you must sign the contributors agreement. - If you want to contribute fixes, please just sign the agreement and go through the standard GitHub pull request process described below until you feel comfortable to bypass review. - If the ticket is trivial, you do not need to sign a contributor's agreement. - -Once you have familiarized yourself with the community and you are excited to contribute to the core: - -- Sign the contributor agreement at , then either send by postal mail to the address provided, or scan and email it to . - This offers both copyright protection and ensures that the Plone Foundation is able to exercise some control over the codebase, ensuring it is not appropriated for someone's unethical purposes. - For questions about why the agreement is required, please see [About the Plone Contributor Agreement -](https://plone.org/foundation/contributors-agreement). - -If you aren't sure where to start or just want more direction, feel free to get in the forum or in chat, and ask for help. -While there is no official mentoring process, there are plenty of people willing to act in that role and guide you through the steps of getting involved in the community. -A common way to start contributing is to participate in a [Plone sprint](https://plone.org/news-and-events/events/sprints). - -**Welcome to the Plone community!** - - -## Dealing with pull requests on GitHub - -Before we can merge a pull request, we must ensure that the author has signed the Plone Contributor Agreement. - -If they're listed in either the [Developers](https://github.com/orgs/plone/teams/developers/members) or [Contributors](https://github.com/orgs/plone/teams/contributors/members) team, the author has signed the Plone Contributor Agreement, so we can go ahead and merge. - -If they aren't listed there, they may have signed and returned the Plone Contributor Agreement, but they were not yet added to a team. -You can ask agreements@plone.org to verify. - -Pull requests without a signed Plone Contributor Agreement can only be merged in trivial cases, and only by the release manager. diff --git a/coredev/continous-integration.md b/coredev/continous-integration.md deleted file mode 100644 index 49eb23d35..000000000 --- a/coredev/continous-integration.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -myst: - html_meta: - "description": "Essential continuous integration practices" - "property=og:description": "Essential continuous integration practices" - "property=og:title": "Essential continuous integration practices" - "keywords": "Plone, continuous integration, best practices" ---- - -```{todo} -needs redaction and upgrade -``` - -# Essential continuous integration practices - -The CI system at [jenkins.plone.org](https://jenkins.plone.org) is a shared resource for Plone core developers to notify them of regressions in Plone core code. - -Build breakages are a normal and expected part of the development process. -Our aim is to find errors and eliminate them as quickly as possible, without expecting perfection and zero errors. -Though, there are some essential rules that needs to be followed in order to achieve a stable build. - - -## 1) Don't check in on a broken build - -Do not make things more complicated for the developer who is responsible for breaking the build. - -If the build breaks, the developer has to identify the cause of the breakage as soon as possible and should fix it. -If we adopt this strategy, we will always be in the best position to find out what caused the breakage and fix it immediately. -If one of the developers has made a check-in and broken the build as a result, we have the best chance of fixing the build if we have a clear look at the problem. -Checking in further changes and triggering new builds will just lead to more problems. - -If the build is broken over a longer period of time (more than a couple of hours) you should either notify the developer who is responsible for the breakage, fix the problem yourself, or just revert the commit in order to be able to continue to work. - -```note -There is one exception to this rule. -Sometimes there are changes or tests that depend on changes in other packages. -If this is the case, there is no way around breaking a single build for a certain period of time. -In this case run the all tests locally with all the changes and commit them within a time frame of ten minutes. -``` - - -## 2) Always run all commit tests locally before committing - -Following this practice ensures the build stays green, and other developers can continue to work without breaking the first rule. - -There might be changes that have been checked in before your last update from the version control that might lead to a build failure in Jenkins in combination with your changes. -Therefore it is essential that you check out ({command}`git pull`) and run the tests again before you push your changes to GitHub. - -Furthermore, a common source of errors on check-in is to forget to add some files to the repository. - -If you follow this rule and your local build passes, you can be sure that this is because someone else checked in in the meantime, or because you forgot to add a new class or configuration file that you have been working on into the version control system. - - -## 3) Wait for commit tests to pass before moving on - -Always monitor the build's progress, and fix the problem right away if it fails. -You have a far better chance of fixing the build, if you just introduced a regression than later. -Also another developer might have committed in the meantime (by breaking rule 1), making things more complicated for yours. - - -## 4) Never go home on a broken build - -Taking into account the first rule of CI ("Don't check in on a broken build"), breaking the build essentially stops all other developers from working on it. -Therefore going home on a broken build (or even on a build that has not finished yet) is **not** acceptable. -It will prevent all the other developers to stop working on the build or fixing the errors that you introduced. - - -## 5) Always be prepared to revert to the previous revision - -In order for the other developers to be able to work on the build, you should always be prepared to revert to the previous (passing) revision. - - -## 6) Time-box fixing before reverting - -When the build breaks on check-in, try to fix it for ten minutes. -If, after ten minutes, you aren't finished with the solution, revert to the previous version from your version control system. -This way you will allow other developers to continue to work. - - -## 7) Don't comment out failing tests - -Once you begin to enforce the previous rule, the result is often that developers start commenting out failing tests in order to get the build passing again as quick as possible. -While this impulse is understandable, it is **wrong**. - -The tests have been passing for a while and then start to fail. -This means that we either caused a regression, made assumptions that are no longer valid, or the application has changed the functionality being tested for a valid reason. - -You should always either fix the code (if a regression has been found), modify the test (if one of the assumptions has changed), or delete it (if the functionality under test no longer exists). - - -## 8) Take responsibility for all breakages that result from your changes - -If you commit a change and all the tests you wrote pass, but others break, the build is still broken. -This also applies to tests that fail in `buildout.coredev` and don't belong directly to the package you worked on. -This means that you have introduced a regression bug into the application. - -It is **your responsibility**—because you made the change—to fix all tests that are not passing as a result of your changes. - -There are some tests in Plone that fail randomly, we are always working on fixing those. -If you think you hit such a test, try to fix it (better) or re-run the Jenkins job to see if it passes again. - -In any case the developer who made the commit is responsible to make it pass. - - -## Further Reading - -Those rules were taken from the excellent book "Continuous Delivery" by Jez Humble and David Farley (Addison Wesley), and have been adopted and rewritten for the Plone community. - -If you want to learn more about continuous integration and continuous delivery, I'd recommend that you buy this book. diff --git a/coredev/contributors_agreement_explained.md b/coredev/contributors_agreement_explained.md deleted file mode 100644 index ef04222b0..000000000 --- a/coredev/contributors_agreement_explained.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -myst: - html_meta: - "description": "Contributor's Agreement for Plone explained" - "property=og:description": "Contributor's Agreement for Plone explained" - "property=og:title": "Contributor's Agreement for Plone explained" - "keywords": "Contributor, Agreement, Plone" ---- - -```{todo} -All this can go, it's redundant -``` - -# Contributor's Agreement for Plone explained - -Prospective contributors to the Plone code base are required to sign a contributor's agreement, which assigns copyright in the code to the Plone Foundation, the non-profit organization which stewards the Plone code base. - -This document explains the purposes of this, along with questions and answers about what this means. - -The Plone Contributor's Agreement can be found at https://plone.org/foundation/contributors-agreement. - - -## About the Plone Contributor Agreement - -The Foundation feels that it benefits the community for a single organization to hold the rights to Plone. -Prior to the Foundation, the intellectual property of Plone was jointly held by individual developers and by Alan Runyan and Alexander Limi. - -The community members who formed the Foundation felt that having the Foundation hold these rights provides several benefits: - -1. **Minimizing confusion / maximizing business compatibility** -- Organizations considering adopting Plone have a simple answer for "Who owns this?", rather than a more complicated answer that might scare away the legally-cautious. -2. **Trademark protection** -- By having the Foundation hold the trademarks and rights to the Plone branding assets, it can effectively protect these from unfair use. -3. **Guarantee of future Open Source versions** -- The Foundation's contributor agreement ensures that there will **always** be an OSI-approved version of Plone. - - -## Questions and answers - -What does the Contributor's Agreement cover? - -> This agreement is for the Plone core codebase only. -> The Plone core codebase is that code which lives in the Plone core version repositories, currently located at [https://github.com/plone]. -> Contributions to the "Collective", currently located at [https://github.com/collective] are not assigned to the Plone Foundation, and are made available under whatever license the project developers wish to use, although add-on products that import from GPLed Plone code are of course subject to the terms of the GPL, which requires derived works to be GPL licensed. - -What rights will I continue to have for my contributions? - -> Contributors are asked to transfer their intellectual property rights to the Foundation. -> In return, they will be given back irrevocable rights to use and distribute their contributions. -> They can even give their contributions to other Open Source projects (as long as those projects are compatible with the license Plone itself is issued under) or use them in non-Open Source commercial applications (if that is compatible with the license Plone is under). - -Do I have to sign the contributor's agreement to make changes to the Plone core codebase? - -> Yes. - -Do I have to sign the contributor's agreement to submit a patch to the Plone core codebase? - -> We enthusiastically welcome patches, but we can't merge them until you sign and return a contributor's agreement. -> (Unless, in the judgement of the Plone Release Manager, the patch is so tiny as not to constitute a "creative work". -> See the [Policy for Contributor Agreements and Patches] for more detail on this policy.) - -Can I grant the Plone foundation a non-exclusive license to my contributions rather than an exclusive license, so that I can contribute the same code to other projects under different terms or use the contribution for other commercial endeavors? - -> Not under the current version of the contributors agreement. - -Does the Foundation control use of the Plone trademark? - -> Yes. -> In order to keep the trademark, the Foundation (or any trademark owner) must demonstrate that they have acted to protect it. - -Will Plone always be available under an OSI-approved/Open Source license? -Couldn't the Board change its mind about this? - -> Plone will always be available under an OSI-approved license; this is written into the language of the contributor agreement each developer and the foundation sign. - -Will Plone ever be available under a non-GPL license? - -> The current Plone approach states that companies can negotiate a non-GPL license. -> Thus, the Foundation might pursue a dual-licensing (GPL and non-GPL) scheme - -> but, at this time, the Board has not yet created any policies on this. -> This is an important question for the community, of course, and the Foundation intends to have this conversation in a transparent way. - -Why would anyone want a non-GPL Plone? - -> Two possible reasons: some companies are reluctant to do in-house modifications of framework-like systems (such as Plone) that are under the GPL, fearing that a clause in the GPL might force them to disclose their internal work - thus wanting to license it under (for example) a BSD-style license. -> Second, companies may wish to offer a commercial version of Plone, under a conventional shrink-wrap license, without the obligation to reveal source code or share changes. - -How much would a non-GPL version of Plone cost? - -> Would a small company be able to afford one? -> Neither the Foundation nor the Board have made any decisions about a non-GPL version, let alone about pricing. -> However, one of the Foundation's stated goals is to maintain a level playing field for Plone while trying to benefit all of the Plone commons. -> If a non-GPL version was available, and a large company bought it, -> added features to it, and sold it, wouldn't they be using our work without an obligation to give back? -> It's helpful to remember the core value open source provides: distributed development, maintenance, security checking, and support. -> Companies that build large features for Plone are **already** having to make decisions of whether to release their products under an open source license or not (since they could always release them as a Product, not as a modification to the Plone core). -> Despite this, though, many large and excellent contributions—such as Archetypes—have been made, and the Foundation hopes that companies will continue to do so. -> In any event, a company that purchases a non-GPL license (should such ever become available) is contributing financial resources to our community, which can be used to further develop, market, and protect the GPL version of Plone. - -- https://plone.org/foundation/contributors-agreement/agreement.pdf -- https://github.com/collective -- https://github.com/plone -- [Policy for Contributor Agreements and patches](https://plone.org/foundation/materials/foundation-resolutions/patch-policy-052011) diff --git a/coredev/culture.md b/coredev/culture.md deleted file mode 100644 index ff30aa2d8..000000000 --- a/coredev/culture.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -myst: - html_meta: - "description": "Plone developer culture" - "property=og:description": "Plone developer culture" - "property=og:title": "Plone developer culture" - "keywords": "Plone, developer, culture" ---- - -```{todo} -All this can go, it's redundant -``` - -# Plone developer culture - -If you are going to contribute to Plone, we ask a couple things. -First, please join the [Plone forum](https://community.plone.org) and at minimum lurk around. -You will quickly see how people work and what kind of things are best suited for group discussion. -Second, please ask for help setting up your environment, in the forum. - -Most of our developers work there and you will get the best advice there. - -If you are actively committing code, always keep an eye on our [Jenkins CI](https://jenkins.plone.org/) to know if your recent commits have broken (or fixed!) the build. - -If you are in a timezone when things are not very active, please post to the forum or grab a drink and wait for people to wake up. - -**When in doubt, please ask** - -The code base is very complicated and everyone is vested in the right thing happening. -Despite the occasional grouch here and there, most Plone developers will go out of their way to get you on the right path. diff --git a/coredev/documentation.md b/coredev/documentation.md deleted file mode 100644 index bebf84e09..000000000 --- a/coredev/documentation.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -myst: - html_meta: - "description": "Writing documentation of Plone" - "property=og:description": "Writing documentation of Plone" - "property=og:title": "Writing documentation of Plone" - "keywords": "documentation, Plone" ---- -```{todo} -shorten & update -``` - -# Writing documentation - -For general guidance for contributing documentation, see {doc}`contributing/index`. - -For documentation authors, see {doc}`contributing/authors`. - - -## Documentation of Plone - -The comprehensive resource for Plone documentation is https://6.docs.plone.org/. -The documentation repository is on [GitHub](https://github.com/plone/documentation). -Information for how to contribute to documentation can be found at {doc}`contributing/index`. - - -## Documenting a package - -At the very least, your package should include the following forms of documentation. - -### `README.md` - -The `README.md` is the first entry point for most people to your package. -It will be included on the PyPI page for your package, and on the front page of its GitHub repository. -It should be formatted using [GitHub flavored Markdown](https://github.github.com/gfm/) to get formatted properly by those systems. - -`README.md` should include: - -- A brief description of the package's purpose. -- Installation information (How do I get it working?) -- Compatibility information (what versions of Plone does it work with?) -- Links to other sources of documentation. -- Links to issue trackers, mailing lists, and other ways to get help. - - -### The manual (narrative documentation) - -The manual goes into further depth for people who want to know all about how to use the package. - -It includes topics like: - -- What are its features -- How to use them (in English—not doctests!) -- Information about architecture -- Common gotchas - -The manual should consider various audiences who may need different types of information: - -- End users who use Plone for content editing, but don't manage the site. -- Site administrators who install and configure the package. -- Integrators who need to extend the functionality of the package in code. -- System administrators who need to maintain the server running the software. - -Simple packages with limited functionality can get by with a single page of narrative documentation. -In this case, it's simplest to include it in an extended `README.md`. -Some excellent examples of a single-page README are https://pypi.org/project/plone.outputfilters/ and https://github.com/plone/plone.app.caching. - -If your project is moderately complex, you may want to set up your documentation with multiple pages. -The preferred way to do this is to add Sphinx to your project, and host your docs on readthedocs.org, so that it rebuilds the documentation whenever you push to GitHub. -If you do this, your `README.md` must link off site to the documentation. - - -### Reference or API documentation - -An API reference provides information about the package's public API (that is, the code that the package exposes for use from external code). -It is meant for random access to remind the reader of how a particular class or method works, rather than for reading in its entirety. - -If the codebase is written with docstrings, API documentation can be automatically generated using Sphinx. - - -### Changes or history - -```{todo} -Update for towncrier. -Probably purge all this content. -``` - -The changelog is a record of all the changes made to the package and who made them, with the most recent changes at the top. -This is maintained separately from the git commit history to give a chance for more user-friendly messages and to and record when releases were made. - -A changelog looks something like: - -```text -Changelog -========= - -1.0 (2012-03-25) ----------------- - -* Documented changelogs. - [davisagli] -``` - -See for a full example. - -If a change was related to a bug in the issue tracker, the changelog entry should include a link to that issue. - - -### Licenses - -Information about the open source license used for the package should be placed within the `docs` directory. - -For Plone core packages, this includes `LICENSE.md` and {file}`LICENSE.GPL`. diff --git a/coredev/getting-started-with-development.md b/coredev/getting-started-with-development.md deleted file mode 100644 index 003e6a7f2..000000000 --- a/coredev/getting-started-with-development.md +++ /dev/null @@ -1,391 +0,0 @@ ---- -myst: - html_meta: - "description": "Getting started with Plone development" - "property=og:description": "Getting started with Plone development" - "property=og:title": "Getting started with Plone development" - "keywords": "Plone, development" ---- - -```{todo} -Needs updating to Plone6, but contains useful info -``` - -# Getting started with development - -This document assumes you want to run the current latest Plone source, fix a bug in Plone, or test an add-on in the context of the latest code, and will detail the full process. -For how to write Plone Improvement Proposals (PLIPs), read {doc}`plips`. - - -## Version support policy - -If you are triaging or fixing bugs, keep in mind that Plone has a [version support policy](https://plone.org/download/release-schedule#91815aec-0513-40e0-a804-55ea787a8c68). - - -## Dependencies - -- git. See [Set up Git](https://docs.github.com/en/get-started/quickstart/set-up-git). -- [Python](https://python.org/). See the [current supported versions of Python](https://plone.org/download/release-schedule). -- If you are on macOS, you will need to install [XCode](https://developer.apple.com/xcode/). - You can do this through the App Store or registering through the Apple Developer Program. -- [Pillow](https://pypi.org/project/Pillow/). -- [GCC](https://gcc.gnu.org/) in order to compile ZODB, Zope and lxml. -- [libxml2 and libxslt](https://gitlab.gnome.org/GNOME/libxslt/-/releases), including development headers. - - -(setup-development-environment)= - -## Set up your development environment - -The first step in fixing a bug is getting this [buildout](https://github.com/plone/buildout.coredev) running. -We recommend fixing the bug on the latest branch, and then [backporting](https://en.wikipedia.org/wiki/Backporting) as necessary. -Dependent on the current development cycle, there may exist a future branch. -For example, `6.0` is the actively maintained stable branch. -[Some other branch] is the future, currently unstable, active development branch. -More information on switching release branches is described below. - -To set up a plone 6 development environment. - -```shell -cd ~/projects # or wherever you want to put things -git clone -b 6.0 https://github.com/plone/buildout.coredev ./plone6devel -cd ./plone6devel -./bootstrap.sh -``` - -If you run into issues in this process, please see {doc}`troubleshooting`. - -This will run for a long time if it is your first pull (approximately 20 minutes). -Once that is done pulling down eggs, you can start your new instance with: - -```shell -./bin/instance fg -``` - -or as a WSGI service with: - -```shell -./bin/wsgi -``` - -To login, the defaults are: - -- username: admin -- password: admin - - -## Switching branches - -If your bug is specific to one branch, or you think it should be backported, you can switch branches. -The first time you get a branch, you must do: - -```shell -git checkout -t origin/6.0 -``` - -This should set up a local 6.0 branch tracking the one on GitHub. -From then on you can just do: - -```shell -git checkout 6.0 -``` - -To see what branch you are currently on: - -```shell -git branch -``` - -The line with a `*` by it will indicate the branch on which you are currently working. - -```{important} -Make sure to rerun buildout if you were in a different branch earlier to get the correct versions of packages, otherwise you will get some weird behavior. -``` - - -## Jenkins and mr.roboto - -Plone has a continuous integration (CI) setup and follows CI rules. - -When you push a change to any Plone package, our testing/CI middleware `mr.roboto` starts running all the tests that are needed to make sure that you don't break anything. -For each Plone and Python version we run two jobs, one for the package itself (which will give you a fast feedback, within 10 minutes) and one on the full `coredev` build (which can take up to an hour, but makes sure no other packages are effected by your change. - -For more information you can read {doc}`Mr. Roboto workflow ` or our [Jenkins machine](https://jenkins.plone.org/). - -The CI system at `jenkins.plone.org` is a shared resource for Plone developers to notify them of regressions in Plone code. -Build breakages are a normal and expected part of the development process. -Our aim is to find errors and eliminate them as quickly as possible, without expecting perfection and zero errors. -Though, there are some essential practices that need to be followed in order to achieve a stable build: - -1. Don't check in on a broken build. Check Jenkins first. -2. Always run all commit tests locally before committing. -3. Wait for commit tests to pass before moving on. -4. Never go home on a broken build. -5. Always be prepared to revert to the previous revision. -6. Time-box fixing before reverting. -7. Don't comment out failing tests. -8. Take responsibility for all breakages that result from your changes. - -See {doc}`continous-integration` for more information. - -Since it can be burdensome to check this manually, install the tools locally to always see the current state of the Plone CI Server: - -- For Linux and X11 environments, there is [BuildNotify](https://pypi.org/project/BuildNotify/). -- For macOS there is [CCMenu](http://ccmenu.org/). -- For windows there is [CCTray](https://cruisecontrolnet.org/cctray_download_plugin-2/). -- For Firefox there is [CruiseControl Monitor](https://addons.thunderbird.net/EN-US/firefox/addon/cruisecontrol-monitor/?src=cb-dl-name) (no longer supported), and many other [Jenkins plugins](https://addons.mozilla.org/en-US/firefox/search/?q=jenkins). - -These tools were built to parse a specific file that CruiseControl, another CI tool, generated. -Jenkins generates this file too. -You can configure your notifier of choice with this url: `https://jenkins.plone.org/cc.xml` [which is a 404, LOL!] - - -## Check out packages to fix - -Most packages are not in {file}`src/` by default, so you can use `mr.developer` to get the latest and make sure you are always up to date. -It can be a little daunting at first to find out which packages cause the bug in question, but just ask in https://community.plone.org/ if you need some help. -Once you know which packages you want, pull their source. - -You can get the source of the package with `mr.developer` and the checkout command, or you can go directly to editing {file}`checkouts.cfg`. -We recommend the latter but will describe both. -In the end, {file}`checkouts.cfg` must be configured, so you might as well start there. - -At the base of your buildout, open {file}`checkouts.cfg` and add your package if it's not already there: - -```cfg -auto-checkout = - # my modified packages - plone.app.caching - plone.caching - # others - ... -``` - -Then rerun buildout to get the source packages: - -```shell -./bin/buildout -``` - -Alternatively, we can manage checkouts from the command line, by using `mr.developer`'s `bin/develop` command to get the latest source. -For example, if the issue is in `plone.app.caching` and `plone.caching`: - -```shell -./bin/develop co plone.app.caching -./bin/develop co plone.caching -./bin/buildout -``` - -Don't forget to rerun buildout! -In both methods, `mr.developer` will download the source from GitHub (or otherwise) and put the package in the {file}`src/` directory. -You can repeat this process with as many or as few packages as you need. -For some more tips on working with `mr.developer`, please read {doc}`mrdeveloper`. - - -## Testing Locally - -To run a test for the specific module you modify: - -```shell -./bin/test -m plone.app.caching -``` - -These should all run without error. -Please don't check in anything that doesn't succeed! -Now write a test case for the bug you are fixing, and make sure everything is running as it should. - -After the module level tests run with your change, please make sure other modules aren't affected by the change by running the full suite, including robot-tests (remove the `--all` to run without robot tests): - -```shell -./bin/test --all -``` - -```{note} -Tests take a long time to run. -Once you become a master of bugfixes, -you may just let jenkins do this part for you. -More on that below. -``` - - -## Updating `CHANGES.rst` and `checkouts.cfg` - -Once all the tests are running locally on your machine, you are **ALMOST** ready to commit the changes. -You must perform a couple housekeeping chores before moving on. - -First, edit {file}`CHANGES.rst` (or {file}`CHANGES.txt`, or {file}`HISTORY.txt`) in each package you have modified and add a summary of the change. -This change note will be collated for the next Plone release and is important for integrators and developers to be able to see what they will get if they upgrade. -New changelog entries should be added at the very top of {file}`CHANGES.rst`. -Some packages already switched to use [towncrier](https://pypi.org/project/towncrier/). -If this is the case you'll find a note at the top of the `CHANGES.rst` file. - -Most importantly, if you didn't do it earlier, edit the file {file}`checkouts.cfg` in the buildout directory, and add your changes package to the `auto-checkout` list. -This lets the release manager know that the package has been updated, so that when the next release of Plone is cut, a new egg will be released, and Plone will need to pin to the next version of that package. -In other words, this is how your fix becomes an egg! - -Note that there is a section separator called "# Test Fixes Only". -Make sure your egg is above that line, else your egg probably won't get made very quickly. -This just tells the release manager that any eggs below this line have tests that are updated, but no code changes. - -Modifying the file {file}`checkouts.cfg` also triggers the buildbot, [jenkins](https://jenkins.plone.org/), to pull in the egg and run all the tests against the changes you just made. -Not that you would ever skip running all tests. - -If your bug is in more than one release, for example 5.2 and 6.0, please checkout both branches, and add it to the file {file}`checkouts.cfg`. - - -## Commits and pull requests - -Review the following checklist: - -- Did you fix the original bug? -- Is your code consistent with our [Style Guides](https://5.docs.plone.org/develop/styleguide/index.html)? -- Did you remove any extra code and lingering pdbs? -- Did you write a test case for that bug? -- DO all test cases for the modules and Plone pass? -- Did you update {file}`CHANGES.rst` in each packages you touched? -- Did you add your changed packages to {file}`checkouts.cfg`? - -If you answered *YES* to all of these questions, then you are ready to push your changes! -A couple quick reminders: - -- Only commit directly to the development branch if you're confident that your code won't break anything badly and the changes are small and fairly trivial. - Otherwise, please create a `pull request` (more on that below). -- Please try to make one change per commit. - If you are fixing three bugs, make three commits. - That way, it is easier to see what was done when, and easier to roll back any changes if necessary. - If you want to make large changes cleaning up whitespace or renaming variables, it is especially important to do so in a separate commit for this reason. -- We have a few angels that follow the changes and each commit to see what happens to their favourite CMS! - If you commit something REALLY sketchy, they will politely contact you, most likely after immediately reverting changes. - There are no official people assigned to this so if you are especially nervous, ask in https://community.plone.org/. - - -## Commit to `Products.CMFPlone` - -If you are working a bug fix on `Products.CMFPlone`, there are a couple other things to take notice of. -First and foremost, you'll see that there are several branches. -At the time of writing this document, there are branches for 4.2.x, 4.3.x and master, which is the implied 5.0. -This may change faster than this documentation, so check the branch dropdown on GitHub. - -If the fix is only for one version, make sure to get that branch. -However, chances are the bug is in multiple branches. - -Let's say the bug starts in 4.1. -Pull the 4.1 branch and fix and commit there with tests. - -If your fix only involved a single commit, you can use git's `cherry-pick` command to apply the same commit to a different branch. - -First check out the branch: - -```shell -git checkout 4.2 -``` - -And then cherry-pick the commit (you can get the SHA hash from git log): - -```shell -git cherry-pick b6ff4309 -``` - -There may be conflicts. -If so, resolve them, then follow the directions git gives you to complete the cherry-pick. - -If your fix involved multiple commits, cherry-picking them one by one can get tedious. -In this case, things are easiest if you did your fix in a separate feature branch. - -In that scenario, you first merge the feature branch to the 4.1 branch: - -```shell -git checkout 4.1 -git merge my-awesome-feature -``` - -Then return to the feature branch, and make a branch for rebasing it onto the 4.2 branch: - -```shell -git checkout my-awesome-feature -git checkout -b my-awesome-feature-4.2 -git rebase ef978a --onto 4.2 -``` - -(`ef978a` happens to be the last commit in the feature branch's history before it was branched off of 4.1. -You can look at `git log` to find this.) - -At this point, the feature branch's history has been updated, but it hasn't actually been merged to 4.2 yet. -This lets you deal with resolving conflicts before you actually merge it to the 4.2 release branch. -Let's do that now: - -```shell -git checkout 4.2 -git merge my-awesome-feature-4.2 -``` - -### Branches and forks and direct commits - oh my! - -```{note} -This section needs a rewrite. -Meanwhile we do not allow direct commits, except in very rare cases. -``` - -Plone used to be in an svn repository, so everyone is familiar and accustomed to committing directly to the branches. -After the migration to GitHub, the community decided to maintain this spirit. -If you have signed the [contributor agreement](https://plone.org/foundation/contributors-agreement), you can commit directly to the branch. -For Plone, this would be the version branch, whereas for most other packages this would be `main`. - -HOWEVER, there are a few situations where a branch is appropriate. -If you: - -- are just getting started -- are not sure about your changes -- want feedback or code review -- are implementing a non-trivial change - -then you should create a branch of whatever packages you are using, and then use the [pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) feature of GitHub to get review. -Everything about this process would be the same except you need to work on a branch. -Take the `plone.app.caching` example. -After checking it out with `mr.developer`, create your own branch with: - -```shell -cd src/plone.app.caching -git checkout -b my_descriptive_branch_name -``` - -```{note} -Branching or forking is your choice. -I prefer branching, and I'm writing the docs so this uses the branch method. -If you branch, it helps us because we *know* that you have committer rights. -Either way it's your call. -``` - -Proceed as normal. -When you are ready to push your fix, push to a remote branch with: - -```shell -git push origin my_descriptive_branch_name -``` - -This will make a remote branch in GitHub. -Navigate to this branch in the GitHub user interface, and on the top right, there will be a button that says {guilabel}`Pull Request`. -This will turn your request into a pull request on the main branch. -There are people who look once a week or more for pending pull requests and will confirm whether or not it's a good fix, and give you feedback where necessary. -The reviewers are informal and very nice, so don't worry. -They are there to help! -If you want immediate feedback, visit https://community.plone.org/ with the pull request link and ask for a review. - -```{note} -You still need to update the file {file}`checkouts.cfg` in the correct branches of `buildout.coredev`! -``` - - -## Finalize issues - -If you are working from an issue, please don't forget to go back to the issue, and add a link to the change set. -We don't have integration with GitHub yet so it's a nice way to track changes. -It also lets the reporter know that you care. -If the bug is really bad, consider pinging the release manager and asking them to make a release. - - -## FAQ - -How do I know when my package got made? -: You can follow the project on GitHub, and watch its [timeline](https://github.com/orgs/plone/dashboard). - You can also check the {file}`CHANGES.rst` of every plone release for a comprehensive list of all changes, and validate that yours is present. diff --git a/coredev/git.md b/coredev/git.md deleted file mode 100644 index 10696f8d3..000000000 --- a/coredev/git.md +++ /dev/null @@ -1,640 +0,0 @@ ---- -myst: - html_meta: - "description": "" - "property=og:description": "" - "property=og:title": "" - "keywords": "" ---- - -```{todo} -All this can go, it's redundant -``` - -# Working with Git and GitHub - -## The Plone Git workflow and branching model - -Our repository on GitHub has the following layout: - -- **feature branches**: - All development for new features must be done in dedicated branches, normally one branch per feature. -- **main** or **master** **branch**: - when features get completed they are merged into the master branch; bugfixes are commited directly on the master branch, -- **tags**: - whenever we create a new release, we tag the repository so we can later retrace our steps, or rerelease versions. - - -## Git basics - -Some introductory definitions and concepts, if you are already familiar enough with Git, head to next section: {ref}`general-guidelines-label`. - - -### Mental working model - -With Git (as well as all modern [DVCS](http://en.wikipedia.org/wiki/Distributed_revision_control)), distributing changes to others is a two steps process (contrary to traditional VCS like `svn`). - -This way what on svn is a single `svn ci` in Git is two commands: `git commit` and `git push`. - -This may seem to be a drawback, but instead it's a feature. - -**You are working locally until you decide to push your changes.** - -Not a single commit anymore, but a series of them, meaning that all those fears, concerns, doubts are taken away! - -You can freely fix/change/remove/rework/update/... your commits afterwards. - -Push your changes whenever you are sure they are what you, and others, expect them to be. - - -### Concepts - -In Git there are: - -commits - -: A patch made out of changes (additions, removals) on files tracked by Git. - -branches - -: Series of commits that have a name. - -tags - -: A name attached to a single commit. - -`HEAD` - -: A pointer that always tells you where you are (extremely useful when doing some operations). - -The index - -: A temporal staging storage with changes on files that are pending to be added to a commit. - If your Git output is colored, green filenames are those in the index. - -Working tree - -: Your current modified files. - This is the only place where you can loose your changes. - If your Git output is colored, red filenames are those in the working tree. - -Stash - -: Temporal storage for changes, again, extremely useful in some scenarios, see further below for examples. - -### Branches - -Another great feature of DVCS is cheap branching, i.e. branching in Git is effortless and really useful. -As it's no longer too much effort to branch, there is no need to always work on the master branch. - -A developer can branch easily for each fix/feature. - -Branches allow you to tinker with your changes while keeping the master branch clean. - -Not only that, it also allows you to keep modifying your changes until you and your peers are fine with them. - -Further documentation: -[Introduction to branching](http://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell). - -### Commands - -Some of the most useful/common commands (note that most of them have switches that enhance/*completely twist* their functionality): - -Just append `--help` on all of them to get their full definitions and options, -i.e. `git add --help`. - -clone - -: Download a repository from a given remote URL. - -add - -: Add the given files to the index. - - ```{note} - **pro tip**: once a file is add via `git add` your changes will never be lost! - As long as you don't remove the `.git` folder, even if you remove the file you just added, the changes you made before doing `git add` are still there ready to be recovered at any time! - ``` - -status - -: Get an overview of the repository status. - - If there are files on the index, or files not tracked by Git, or the status of your local branch with regards to the remote, etc. - -diff - -: See the current changes made to the files already tracked by Git. - - ```note} - Fear not, if you used `git add SOME_FILE` and then `git diff` doesn't output anything you haven't lost your changes! - - Just try `git diff --cached`. - Now you know how to see the working tree changes (`git diff`) and index changes (`git diff --cached`). - ``` - -commit - -: Create/record changes to the repository (locally only, nothing is sent over the wire). - -push - -: Send your changes, - either commits or a complete new branch, - to the configured remote repository. - -show - -: Display the given commit(s) details. - -log - -: Shows the repository history. - Sorted by date (last commit at the top), - and like all other commands, - extremely versatile with all its switches. - - See further below for an example of a powerful combination of switches. - -branch - -: Create a branch. - -fetch - -: Download changes from the remote repository. - - **Without** changing the current `HEAD` (see rebase and pull commands). - -pull - -: Fetch and integrate changes from remote repository. - - Internally that means to do a `git fetch` plus either `git merge` or `git rebase`. - - :::{note} - Used careless most probably adds extra superfluous commits. - See further down. - ::: - -merge - -: Join two, - or more, - branches together. - -rebase - -: Forward-port your current local commits (or branch) to be based on top of another commit. - - An image is worth 1000 words: - -checkout - -: Change to the given branch or get the given file to its latest committed version. - - :::{note} - If Git is criticized for being complex, - this command is one of the main sources of complains. - - You can compare it with `svn switch` if you happen to know it. - - Fear not though, - two main use cases are: - change branches and reset a file to its last committed version. - Still, - the syntax for both cases is really simple. - ::: - -cherry-pick - -: Apply a commit(s) to the current working branch. - -stash - -: Use a temporal storage to save/restore current changes still not meant to be used on a commit. - - :::{note} - Seems a bit not so useful on a first look, - but it is indeed. - - Think about this scenario: - you are working on your branch coding away. - All of the sudden you notice a small fix that should be done directly on master. - Thanks to `git stash` you can save your changes quickly and safely, - move to master branch, - do the quick fix, - commit and push it, - move back to your branch and `git stash pop` to recover your changes and continue hacking away. - ::: - -reflog - -: When things go bad you will **love** this command. - - It effectively shows you a histogram of what happened on the repository, - allowing you to rollback you repository to a previous stage. - - Extremely useful once a bad interactive rebase has happened. - -(general-guidelines-label)= - -## General guidelines - -### Pulling code - -Let's compare this two histories: - -``` -* 3333333 (HEAD, master) Merge branch 'feature-branch' into master -|\ -| * 2222222 (feature-branch) Last changes on feature-branch -| * 1111111 Merge branch 'master' into feature-branch -| |\ -| * | 0000000 More changes on feature branch -| * | fffffff Merge branch 'master' into feature-branch -| |\ \ -* | | | eeeeeee master keeps rocking -| |_|/ -|/| | -* | | ddddddd master goes and goes -| |/ -|/| -* | ccccccc master evolves -| * bbbbbbb First commit on feature-branch -|/ -* aaaaaaa commit on master # this is where feature-branch was created -``` - -With: - -``` -* 3333333 (HEAD, master) Merge branch 'feature-branch' into master -|\ -| * 2222221 (feature-branch) Last changes on feature-branch -| * 0000001 More changes on feature branch -| * bbbbbb1 First commit on feature-branch -|/ -* eeeeeee master keeps rocking -* ddddddd master goes and goes -* ccccccc master evolves -* aaaaaaa commit on master -``` - -What do we see above? Actually and contrary to what it seems, -exactly the same **result** -(as how the files and its content look like on commit `333333`). - -The second version is far more easy to understand what happened and removes two superfluous commits -(the two partial merges with master (`fffffff` and `1111111`). - -This happens if you have not properly configured `git pull`. -By default it does a `merge` meaning that an extra commit is always added, -tangling the history and making this more complex when looking back for what happened there. - -#### How to solve it? - -*ALWAYS* do a {command}`git pull --rebase` when fetching new code, -configure Git to do always so with: - -``` -git config branch.autosetuprebase always # add the --global switch to make it default everywhere -``` - -This way you do not introduce new extra commits and the Git history is kept as simple as possible. - -This is especially important when trying to understand why some changes were made, -or who did actually change that line, -etc. - -A couple of further explanations: - - - - -Search for `git merge vs rebase`, you will find plenty of literature. - -### Reviewing your changes - -After hacking for some minutes/hours/days you are finished and about to commit your changes, -great! - -*BUT*, -please, -do so with {command}`git add --patch`. - -The `--patch` (also `-p`) switch allows you to select which hunks you want to add on a commit. - -This is not only great to split changes into different commits, -but is also the time when you actually **review** your code before anyone else sees it. - -This is the time when you spot typos, pep8 errors, misaligned code, lack of docstrings in methods, -that a permission is not defined on Generic Setup, that an upgrade should be needed... - -Remember that the first code review is the one you do on your own. -Some inspiration/better phrasing: - - -And please, do remember the gold metric about reviewing code: - - -#### One commit does one thing - -Repeat with me: *One commit does one thing*. Period. - -When someone else needs to review your code, most probably she will give up or just skim over your code -if there are too many (unrelated) changes. - -Reviewing commits with +20 files doing all sorts of changes on them (maybe even unrelated) -is no fun and adds complexity and [cognitive load](http://en.wikipedia.org/wiki/Cognitive_load). - -Something that should mostly be a verification of a checklist like: - -- the browser view is registered on ZCML? - -- is there an interface for that form? - -- the pt and py are there? - -- ... - -Turns instead into a list of questions: - -- why is this interface renamed here if it has nothing to do with this adapter? -- all this removal of deprecated code while adding new features just mixes the diff, - am I missing something? -- *others* - -If you can not express what has been changed within 50 characters (suggested length of a commit message subject), -or you say it like "it does XXX and YYY", you most probably need to split that commit into, at least, -two or more commits. - -That doesn't mean that a +20 files or +100 lines of code changes are bad per se, you may be doing -a simple refactoring across lots of files, that's fine and good actually. - -As long as a commit is just and only about a specific purpose, and not a mixed selection of the following: - -- refactoring code -- moving things around -- fixing some bugs while at it -- adding some docs -- a new cool feature -- fixing typos on documentation -- pep8 fixes - -It is absolutely fine to refactor. - -And this is actually to help both your present self and your +5 years from now that will have to refactor that code of yours, -and maybe is struggling to understand what was going on there. - -Following this advice will: - -- keep things simple where there's no gain in adding complexity -- make your changes easy to be reviewed -- make later on lookups on those changes easy to follow - -### Making commits - -For commit messages see: {ref}`git_commit_message_style_guide`. - -#### Adding references to issues - -Always add the full URL to the issue/pull request you are fixing/referring to. - -Maybe within the Git repository it makes sense, but as soon as you are outside of it, it will not. - -Take into account mr.roboto automatic commits to buildout.coredev for example, if your commit message goes like *Fix for #33*, -which issue/pull request is that fixing? - -The one in buildout.coredev itself? On another issue tracker? Somewhere else? - -It would be far better if the commit goes instead like: - -``` -Brief description - -Further explanation. - -Fixes: https://github.com/plone/plone.app.discussion/issue/999 -``` - -#### Bad examples - -Some bad examples of commit messages: - - -Commit messages goes like *"Make note about how this interface is now for BBB only"*. - -Question: if it's BBB only, where is the new place to look for that interface now? - -The problem is that, in this case Martin, wrote that in 2009, so most probably once a refactor of that package -is done later on 2015, Martin is no longer around, and if he was, most probably he would not remember something from +6 years ago. - -Ask yourself a question: - -If someone comes to you asking details about a random commit done by you +5 years ago, what will you reply? - -Try that, get one project that you worked 5 years ago, get a random commit and: - -See if, just by reading the commit message, you are given enough information of what changes have been made, -when comparing the commit message and the actual code. -Does the commit message match the code changed? - -### Before pushing commits - -Code is reviewed, spread into nice isolated commits, descriptive enough commit messages are written, *what's left?* - -A final overview of what you are about to push. - -To do so, you can get an idea with the following Git alias (to be added on your `~/.gitconfig`): - -``` -[alias] - fulllog = log --graph --decorate --pretty=oneline --abbrev-commit --all -``` - -Now run {command}`git fulllog` on your Git repository, you will see a nice graph showing you the current situation. - -Maybe it makes you realize that commits need to be reordered, commit messages could get some improvements, -that you forgot to add a reference to an issue, ... - -## Pull requests - -Some specific tips and best practices for pull requests. - -### Always rebase - -Always rebase on top of the branch you want your changes to be merged before sending a pull request, -and as your pull request is still pending to be merged and the master branch evolves, keep rebasing it. - -To do so: - -``` -git checkout -git rebase master # or the branch you are targeting to integrate your changes to -# done! -# or if there are conflicts, -# fix them and follow instructions from git itself -``` - -The principle is, if you do merges with master, you are actually spreading your pull request into more commits, -and at the end making it more difficult to track what was changed. - -On top of that, the commit history is more complex to follow. - -See the history example above: {ref}`general-guidelines-label`. - -Unfortunately the flat view from GitHub prevents us from seeing that, -which is a shame. - -### One line one commit - -On a series of commits make sure the same code line is not changed twice, -the worst thing you can do to the one reviewing your changes, -is to make him/her spend time reviewing some code changes that one the next commit are changed again to do something else. - -It will not only make your commits smaller, but it will also make it easy to do atomic commits. - -### No cleanup commits please - -*On the context of a pull request* - -Ask yourself: What relation does a cleanup commit, say pep8 fixes or other code analysis fixes, -have with your pull request? - -Couldn't that pep8 fixes commit or small refactoring go straight into master branch? - -Or even if you send a pull request for it, chances are that it will be merged right away. -As long as it is a cleanup commit, there's not much to argue with it. - -The same goes with commits that improve or actually fix previous commits (within the same pull request). -A series of commits like this: - -``` -* 11ba28c Last fix, finally -* 11ba28c Fix tests, again -* 11ba28c Fix tests -* 11ba28c Do something fancy -* 11ba28c Failing test, we are doing TDD right? -``` - -Only tells you that the author did not take care at all about the one who will review it, -and specially about the person that in +5 years will try to understand that test. -Specially because now the test is not only spread between 4 commits, but most probably during those 5 years -it has already been refactored, maybe a {command}`git blame` will report that within that test method, -there are +5 related current commits to check, not nice right? - -#### Squashing commits - -To fix the previous example, run the following command: - -``` -git rebase ---interactive # which mostly is usually master -``` - -This allows you to rewrite the story of your branch. -See a more [elaborate description with examples](https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase-i/). - -:::{note} -Be careful on not to run that on master itself! -Please take your time to really understand it. - -It's a really powerful tool, -and as [Stan Lee says](http://en.wikiquote.org/wiki/Stan_Lee), -it comes with great responsibility. -::: - -To actually make it easier you can do commits like this: - -``` -git commit --fixup HASH -``` - -Where `HASH` is the commit hash you want the changes you are about to commit be merged with. - -This way, when running {command}`git rebase --interactive`, Git will already reorder the commits as you already want. - -### No side changes - -That's an extension to the previous point. - -Keeping pull requests simple and to the point, without changes not related to the pull request itself, -will make your changes easier to understand and easier to follow. - -Again this applies: - - -### The review-change-push-review cycle - -After you have made a pull request, -you should ask for a review via the GitHub interface. - -After the review you will frequently have to do some changes of your PR, -perhaps add a missing changelog entry, and so on. - -When the changes are done, rebase your branch again -and squash any fixup-commits, all as described above. - -Finally you should force push your feature branch to GitHub. -Only force push on your own feature branches! -Never on branches shared with other people. - -After the update of your branch, -the GitHub PR interface will pick up the changes, -ready for returning to the reviewer, -and hopefully get a final go for the merge. - -## Recipes - -Assorted list of tips and tricks. - -### Change branches with uncommitted changes - -**Situation:** you are working on a pull request and while working on it founds that some cleanups are needed, -how to proceed forward? - -**Solution:** `git stash` or `git commit --amend -m"TMP"`. - -The basic idea here is: store your current changes safely (either on a Git stash commit or directly on a commit on the branch, -whichever you prefer), move to the canonical branch (`master` usually), do the fixes/cleanups/refactorings there, -commit those changes, rebase your branch on top of the changes you made, hack away. - -Command line version: - -``` -git stash # or git commit --amend -m"TMP" -git checkout master # or whatever happens to be the canonical branch name (i.e. 5.0 on buildout.coredev) -# do the cleanups && push them -git checkout your-branch # get back to your branch -git rebase master # again the canonical branch where you made the changes -git stash pop # or git reset HEAD^ if you did a git commit --amend -m"TMP" -# if needed, fix the conflicts, with patience and practise that's a piece of cake once you are used to -``` - -### Git visual applications - -Not everyone is a fan of the command line, for them there is a list of GUI clients on the official Git website: - - - -### Enhanced Git prompt - -Do one (or more) of the following: - -- -- -- - -### Git dotfiles - -Plone developers have dotfiles similar to these: -. - -## Learn more - -What's here is just the tip of the iceberg, there's plenty of Git knowledge on the web. - -A few good further resources are listed here (contributions welcome): - -- official online Git book: [Pro Git](http://git-scm.com/book/en/v2) -- PyCon 2015 talk: [Advanced Git by David Baumgold](https://www.youtube.com/watch?v=4EOZvow1mk4) diff --git a/coredev/guidelines.md b/coredev/guidelines.md deleted file mode 100644 index 331c25e34..000000000 --- a/coredev/guidelines.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -myst: - html_meta: - "description": "" - "property=og:description": "" - "property=og:title": "" - "keywords": "" ---- - -```{todo} -All this can go, it's redundant. -IMPORTANT: it does need a rewrite on 6.docs.plone.org as there are many packages in the wild that link to it. -``` - -% Note: this page is linked to from CONTRIBUTING.rst in all packages. Keep it short! - -# Guidelines for contributing to Plone Core - -You probably came here by clicking one of the 'guidelines for contributing' links on GitHub. -You probably have an issue to report or you want to create a pull request. -Thanks a lot! -Let's bring you up to speed with the minimum you need to know to start contributing. - -## Create an issue - -- If you know the issue is for a specific package, you can add an issue there. - When in doubt, create one in the [CMFPlone issue tracker](https://github.com/plone/Products.CMFPlone/issues). - -- Please specify a few things: - - - What steps reproduce the problem? - - What do you expect when you do that? - - What happens instead? - - Which Plone version are you using? - -- If it is a visual issue, can you add a screen shot? - -- If there is an error in the Site Setup error log, please include it. - Especially a traceback is helpful. - Click on the 'Display traceback as text' link if you see it in the error log. - - -## Create a pull request - -- Legally, you can NOT contribute code unless you have signed the {doc}`contributor agreement `. - This means that we can NOT accept pull requests from you unless this is done, so please don't put the code reviewers at risk and do it anyways. -- Add a changelog entry as file in the news directory. - For helpful instructions, please see: -- For new features, an addition to README.rst is probably needed. - A package may include other documentation that needs updating. -- All text that can be shown in a browser must be translatable. - Please mark all such strings as translatable. -- Be nice and use code quality checkers like flake8 and jshint. -- See if you can use git to squash multiple commits into one where this makes sense. - If you are not comfortable with git, never mind. -- If after reading this you become hesitant: don't worry. - You can always create a pull request, mark it as WIP (work in progress), and improve the above points later. diff --git a/coredev/index.md b/coredev/index.md deleted file mode 100644 index 41192a357..000000000 --- a/coredev/index.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -myst: - html_meta: - "description": "Development in Plone" - "property=og:description": "Development in Plone" - "property=og:title": "Development in Plone" - "keywords": "Developing, Plone, Contributing" ---- - -```{todo} -Most of this can go -``` - -# Development in Plone - -This part describes the process of development in Plone. -It is primarily a technical resource for setting up your development environment, fixing bugs, and writing Plone Improvement Proposals (PLIPs). - - -## Plone Contributor Agreement - -You must sign the [Plone Contributor Agreement](https://plone.org/foundation/contributors-agreement). - -We can **NOT** accept pull requests from you until you have signed and returned the Contributor Agreement, and been approved. -Please don't put the code reviewers at risk by ignoring this requirement. - - -## Contents - -```{toctree} -:maxdepth: 2 - -guidelines -agreement -culture -getting-started-with-development -documentation -plips -issues -release -git -package-dependencies -``` - - -## Additional material - -These are some documents used as reference for this documentation. - -```{toctree} -:maxdepth: 1 - -contributors-agreement-explained -continous-integration -roboto -mrdeveloper -plip-review -``` - -```{todo} -The style guides are ancient and need to be overhauled. -``` - -Documenation's style is guided by Vale and the Microsoft Style Guide. -See [Contributing to Documentation](https://6.docs.plone.org/contributing/index.html). - -Our coding style guides are located at the [Plone Style Guide](https://5.docs.plone.org/develop/styleguide/index.html section. diff --git a/coredev/mrdeveloper.md b/coredev/mrdeveloper.md deleted file mode 100644 index f0480b0c1..000000000 --- a/coredev/mrdeveloper.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -myst: - html_meta: - "description": "mr.developer" - "property=og:description": "mr.developer" - "property=og:title": "mr.developer" - "keywords": "mr.developer" ---- - -```{todo} -Review, but keep -``` - -# `mr.developer` - -This buildout uses `mr.developer` to manage package development. -See https://pypi.org/project/mr.developer/ for more information, or run `bin/develop help` for a list of available commands. - -The most common workflow to get all the latest updates is: - -```shell -git pull -bin/develop rb -``` - -This will get you the latest `coredev` configuration, checkout and update all packages via git and Subversion in src, and run buildout to configure the whole thing. - -From time to time you can check if some old cruft has accumulated: - -```shell -bin/develop st -``` - -If this prints any lines with a question mark in front, you can cleanup by: - -```shell -bin/develop purge -``` - -This will remove packages from {file}`src/` which are no longer needed, as they have been replaced by proper egg releases of these packages. diff --git a/coredev/packages-dependencies.md b/coredev/packages-dependencies.md deleted file mode 100644 index 8f95a4f70..000000000 --- a/coredev/packages-dependencies.md +++ /dev/null @@ -1,372 +0,0 @@ ---- -myst: - html_meta: - "description": "This chapter describes the architecture of Plone's packages and dependencies." - "property=og:description": "This chapter describes the architecture of Plone's packages and dependencies." - "property=og:title": "Architecture: packages and dependecies" - "keywords": "Architecture, packages, dependecies, Plone" ---- - -```{todo} -Needs grammar/style check, and re-do the ASCII art as Mermaid diagram for added clarity and visuals -``` - -# Architecture: packages and dependecies - -This chapter describes the architecture of Plone's packages and dependencies. - - -## Motivation - -In the past, lots of indirections were introduced in Plone's packages and dependecies. -Our goal in the long run is to untangle them and get a direct dependency graph. -This document shows the current state as an orientation. - - -## Overview - -There are multiple level of dependencies: - -- package level (`setup.py`/`setup.cfg`/`pyproject.toml`) -- Python level (imports) -- ZCML level (includes) -- testing (need for layers, such as functional testing) - -We do not have any circular dependencies at the package level anymore. -This was solved already. - -Nevertheless we have indirection on all other levels. -Since Plone consists of a lot of packages, it is complex to untangle those. - - -## Mental model - -A base mental model for how Plone is organized in Plone 6 since alpha 4 is shown in the following diagram: - -``` -┌────────────────────────────┐ -│ "Plone" | -| The Integration of both | -| distributions in one | -| Release | -├────────────────────────────┤ -| Distributions: | -| - plone.volto | -| - plone.classicui | -├────────────────────────────┤ -│ Core-Addons │ -│ - plone.distribution │ -│ - plone.app.exportimport │ -│ - plone.app.discussion │ -│ - plone.app.multilingual │ -│ - plone.app.caching │ -│ - plone.app.iterate │ -│ - plone.app.update │ -│ │ -├────────────────────────────┤ -│ Core-APIs │ -│ - plone.restapi │ -│ - plone.api │ -├────────────────────────────┤ -│ │ -│ Products.CMFPlone │ -│ │ -├────────────────────────────┤ -│ │ -│ The space between (core ) │ -│ │ -│ - most of plone.app.* │ -│ - but also some other │ -│ │ -├────────────────────────────┤ -│ │ -│ plone.base │ -│ │ -├────────────────────────────┤ -│ │ -│ The Foundations │ -│ │ -│ - Zope │ -│ - CMFCore │ -│ - PAS/PlonePAS │ -│ - plone.registry │ -│ - plone.dexterity │ -│ - plone.behavior │ -│ - plone.rest │ -│ - .... │ -│ │ -└────────────────────────────┘ -``` - -As a rough model we have two packages as dividing lines: - -1. `Products.CMFPlone` -2. `plone.base` - - -## Packages in detail - -If we look deeper into those, we have more sub-dividers, but first group all into the three groups: - -Then, based on the 6.0.0.a4 release, these are the packages: - - -### Above `Products.CMFPlone` - -- Plone -- plone.api -- plone.app.iterate -- plone.app.upgrade -- plone.restapi -- plone.volto -- Products.CMFPlacefulWorkflow - - -### Between `Products.CMFPlone` and `plone.base` - -- collective.monkeypatcher -- plone.app.caching -- plone.app.content -- plone.app.contentlisting -- plone.app.contentmenu -- plone.app.contentrules -- plone.app.contenttypes -- plone.app.customerize -- plone.app.dexterity -- plone.app.discussion -- plone.app.event -- plone.app.i18n -- plone.app.intid -- plone.app.layout -- plone.app.linkintegrity -- plone.app.locales -- plone.app.lockingbehavior -- plone.app.multilingual -- plone.app.portlets -- plone.app.querystring -- plone.app.redirector -- plone.app.registry -- plone.app.relationfield -- plone.app.textfield -- plone.app.theming -- plone.app.users -- plone.app.uuid -- plone.app.versioningbehavior -- plone.app.viewletmanager -- plone.app.vocabularies -- plone.app.widgets -- plone.app.workflow -- plone.app.z3cform -- plone.browserlayer -- plone.cachepurging -- plone.contentrules -- plone.formwidget.namedfile -- plone.formwidget.recurrence -- plone.i18n -- plone.namedfile -- plone.outputfilters -- plone.portlet.collection -- plone.portlet.static -- plone.portlets -- plone.protect -- plone.resourceeditor -- plone.rfc822 -- plone.schemaeditor -- plone.session -- plone.staticresources -- plone.stringinterp -- plone.theme -- plonetheme.barceloneta -- Products.isurlinportal - - -### The foundation below `plone.base` - - -#### Plone world - -- borg.localrole -- plone.alterego -- plone.autoform -- plone.autoinclude -- plone.batching -- plone.behavior -- plone.caching -- plone.dexterity -- plone.event -- plone.folder -- plone.indexer -- plone.intelligenttext -- plone.keyring -- plone.locking -- plone.memoize -- plone.registry -- plone.resource -- plone.rest -- plone.scale -- plone.schema -- plone.subrequest -- plone.supermodel -- plone.transformchain -- plone.uuid -- plone.z3cform -- Products.DateRecurringIndex -- Products.ExtendedPathIndex -- Products.MimetypesRegistry -- Products.PlonePAS -- Products.PortalTransforms -- Products.statusmessages - - -#### Zope ecosystem - -- Chameleon -- diazo -- five.customerize -- five.intid -- five.localsitemanager -- icalendar -- Products.CMFCore -- Products.CMFDiffTool -- Products.CMFDynamicViewFTI -- Products.CMFEditions -- Products.CMFUid -- Products.DCWorkflow -- Products.ExternalMethod -- Products.GenericSetup -- Products.MailHost -- Products.PluggableAuthService -- Products.PluginRegistry -- Products.PythonScripts -- Products.Sessions -- Products.SiteErrorLog -- Products.StandardCacheManagers -- Products.ZopeVersionControl -- repoze.xmliter -- webresource -- z3c.caching -- z3c.form -- z3c.formwidget.query -- z3c.objpath -- z3c.pt -- z3c.relationfield -- z3c.zcmlhook -- zc.recipe.egg -- zc.relation -- zodbverify -- zope.copy -- zope.intid -- zope.keyreference - - -#### Zope core - -- AccessControl -- Acquisition -- AuthEncoding -- beautifulsoup4 -- BTrees -- DateTime -- DocumentTemplate -- ExtensionClass -- Missing -- MultiMapping -- Persistence -- persistent -- Products.BTreeFolder2 -- Products.ZCatalog -- Record -- RestrictedPython -- transaction -- zc.lockfile -- ZConfig -- zdaemon -- ZEO -- zExceptions -- ZODB -- ZODB3 -- zodbpickle -- Zope -- zope.annotation -- zope.app.locales -- zope.browser -- zope.browsermenu -- zope.browserpage -- zope.browserresource -- zope.cachedescriptors -- zope.component -- zope.componentvocabulary -- zope.configuration -- zope.container -- zope.contentprovider -- zope.contenttype -- zope.datetime -- zope.deferredimport -- zope.deprecation -- zope.dottedname -- zope.event -- zope.exceptions -- zope.filerepresentation -- zope.globalrequest -- zope.hookable -- zope.i18n -- zope.i18nmessageid -- zope.interface -- zope.lifecycleevent -- zope.location -- zope.pagetemplate -- zope.processlifetime -- zope.proxy -- zope.ptresource -- zope.publisher -- zope.ramcache -- zope.schema -- zope.security -- zope.sendmail -- zope.sequencesort -- zope.site -- zope.size -- zope.structuredtext -- zope.tal -- zope.tales -- zope.testbrowser -- zope.testing -- zope.traversing -- zope.viewlet -- Zope2 - - -#### Libraries - -- attrs -- cffi -- cssselect -- decorator -- docutils -- feedparser -- future -- importlib_metadata -- jsonschema -- Markdown -- multipart -- Paste -- PasteDeploy -- piexif -- Pillow -- pycparser -- PyJWT -- pyrsistent -- python_dotenv -- python_gettext -- requests -- roman -- sgmllib3k -- simplejson -- soupsieve -- Unidecode -- urllib3 -- waitress -- WebOb -- WebTest -- WSGIProxy2 -- zipp diff --git a/coredev/plip-review.md b/coredev/plip-review.md deleted file mode 100644 index 267b55902..000000000 --- a/coredev/plip-review.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -myst: - html_meta: - "description": "PLIP review" - "property=og:description": "PLIP review" - "property=og:title": "PLIP review" - "keywords": "PLIP, review, Plone Improvement Proposal, Plone" ---- - -```{todo} -Combine with PLIP page, remove obsolete technologies, go over language -``` - -# PLIP review - -A Plone Improvement Proposal (PLIP) is a formal process to propose a change to improve Plone. - - -## Expectations - -A good PLIP review takes about four hours. -Please plan accordingly. -When you are done, if you have access to core, commit the review to the `plips` folder, and reference the PLIP in your commit message. -If you do not have access, attach your review to the PLIP ticket itself. - - -## Setting up the environment - -Follow the instructions in {doc}`getting-started-with-development`. -You will need to checkout the branch to which the PLIP is assigned. -Instead of running the buildout with the default buildout file, you will run the configuration specific to that PLIP: - -```shell -./bin/buildout -c plips/plipXXXX.cfg -``` - - -## Functionality review - -This section describes the topics that may be addressed in a PLIP review, depending on the nature of the PLIP itself. - - -### General - -- Does the PLIP actually do what the implementers proposed? - Are there incomplete variations? -- Were there any errors running buildout? - Did the migration(s) work? -- Do error and status messages make sense? - Are they properly internationalized? -- Are there any performance considerations? - Has the implementer addressed them, if so? - - -### Bugs - -- Are there any bugs? - Nothing is too big nor small. -- Do fields handle wacky data? - How about strings in date fields, or nulls in required? -- Is validation up to snuff and sensical? - Is it too restrictive or not restrictive enough? - - -### Usability Issues - -- Is the implementation usable? -- How will novice end users respond to the change? -- Does this PLIP need a usability review? - If you think this PLIP needs a usability review, change the state to "please review" and add a note in the comments. -- Is the PLIP consistent with the rest of Plone? - For example, if there is control panel configuration, does the new form fit in with the rest of the panels? -- Does everything flow nicely for novice and advanced users? - Is there any workflow that feels odd? -- Are there any new permissions and do they work properly? - Does their role assignment make sense? - - -### Documentation Issues - -- Is the corresponding documentation for the end user, be it developer or Plone user, sufficient? -- Is the change itself properly documented? - -Report bugs or issues on GitHub as you would for any Plone bug. -Reference the PLIP in the bug, assign to its implementer, and add a tag for the PLIP in the form of `plip-xxx`. -This way the implementer can find help if they need it. -Also set a priority for the ticket. -The PLIP will not be merged until all blockers and critical bugs are fixed. - - -### Code Review - - -#### Python - -- Is this code maintainable? -- Is the code properly documented? -- Does the code adhere to PEP8 standards (more or less)? -- Are they importing deprecated modules? - - -#### JavaScript - -- Does the JavaScript meet our set of JavaScript standards? - See our section about [JavaScript](https://5.docs.plone.org/develop/addons/javascript/index.html) and the [JavaScript Style Guide](https://5.docs.plone.org/develop/styleguide/javascript.html). -- Does the JavaScript work in all currently supported browsers? - Is it performant? - -```{todo} -Update links from Plone 5 Documentation to Plone 6 Documentation, when they exist. -See https://github.com/plone/documentation/issues/1330 -``` - -#### ME/TAL - -- Does the PLIP use views appropriately, avoiding too much logic? -- Is there any code in a loop that could potentially be a performance issue? -- Are there any deprecated or old style ME/TAL lines of code, such as using `DateTime`? -- Is the rendered HTML compliant with standards? Are IDs and classes used appropriately? diff --git a/coredev/plips.md b/coredev/plips.md deleted file mode 100644 index 90b071eac..000000000 --- a/coredev/plips.md +++ /dev/null @@ -1,299 +0,0 @@ ---- -myst: - html_meta: - "description": "Plone Improvement Proposals (PLIPs)" - "property=og:description": "Plone Improvement Proposals (PLIPs)" - "property=og:title": "Plone Improvement Proposals (PLIPs)" - "keywords": "Plone Improvement Proposal, PLIP)" ---- - -```{todo} -Needs language review -``` - -# Plone Improvement Proposals (PLIPs) - -A PLIP is a Plone Improvement Proposal. -It is a change to a Plone package that would affect everyone. -PLIPs go through a different process than bug fixes because of their broad reaching effect. -The Plone Framework Team reviews all PLIPs to be sure that it's in the best interest of the broader community to be implemented and that it is of high quality. - - -## Frequently asked questions about PLIPs - -This section provides detailed answers to common questions about PLIPs. - - -### PLIP or bugfix? - -In general, anything that changes the API of Plone in the backend or the user interface (UI) on the front end should be filed as a PLIP. -When in doubt, submit it as a PLIP. -The Framework Team is eager to reduce its own workload and will reclassify it for you. -If the change you are proposing is not in the scope of a PLIP, a GitHub pull request or issue is the right format. -The key point here is that each change must be documented, allowing it to be tracked and understood. - - -### Who can submit PLIPs? - -Anyone who has signed a Plone Contributor Agreement can work on a PLIP. -Don't let the wording freak you out: signing the agreement is easy and you will get access almost immediately. - -You do not have to be the most amazing coder in the entire world to submit a PLIP. -The Framework Team is happy to help you at any point in the process. - -Submitting a PLIP can be a great learning process. -We encourage people of all backgrounds to submit a PLIP. -When the PLIP is accepted, a Framework Team member will "champion" your PLIP and be dedicated to its completion. - -PLIPs are not just for code monkeys. -If you have ideas on new interactions or UI your ideas are more than welcome. - -We will help you pair up with implementers if needed. - - -### What is a PLIP champion? - -When you submit your PLIP and it is approved, a Framework Team member who is especially excited about seeing the PLIP completed will be assigned to your PLIP as a champion. - -They are there to push you through completion, as well as answer any questions and provide guidance. - -A champion fulfill the following tasks. - -- Answer any questions the PLIP implementor has, technical or otherwise. -- Encourage the PLIP author by constantly giving feedback and encouragement. -- Keep the implementer aware of timelines, and push to get things done on time. -- Assist with finding additional help when needed to complete the implementation in a timely matter. - -Keep in mind that champions are in passive mode by default. -If you need help or guidance, please reach out to them as soon as possible to activate help mode. - - -### Can I get involved in other ways? - -If you want to experience the process and how it works, help us review PLIPs as the implementations finish up. -Ask one of the Framework Team members what PLIPs are available for review, or check the status of PLIPs at the [GitHub issues](https://github.com/plone/Products.CMFPlone/issues) page -for [Products.CMFPlone](https://github.com/Plone/Products.CMFPlone) -for [issues tagged with "03 type: feature (plip)"](https://github.com/plone/Products.CMFPlone/labels/03%20type%3A%20feature%20%28plip%29). - -Make sure to let us know you intend to review the PLIP by communicating that to the [Framework Team](https://community.plone.org/c/development/framework-team). - -Then, follow the instructions for {doc}`reviewing a PLIP `. - -Thank you in advance! - - -### When can I submit a PLIP? - -Today, tomorrow, any time! - -After the PLIP is accepted, the Framework Team will try to judge complexity and time to completion, and assign it to a milestone. - -You can begin work immediately, and we encourage submitting fast and furious. - - -### When is the PLIP due? - -**Summary: As soon as you get it done.** - -Technically, we want to see it completed for the release to which it's assigned. -We know that things get busy, and new problems may make PLIPs more complicated, and we will push it to the next release. - -In general, we don't want to track a PLIP for more than a year. - -If your PLIP is accepted and we haven't seen activity in over a year, we will probably ask you to restart the whole process. - - -### What happens if your PLIP is not accepted? - -If a PLIP isn't accepted in core, it doesn't mean it's a bad idea. -It is often the case that there are competing implementations, and we want to see it vetted as an add-on before "blessing" a preferred implementation. - - -## Process Overview - -1. Submit a PLIP at any time. -2. PLIP is approved for inclusion into core for a given release. -3. Developer implements PLIP (code, tests, documentation). -4. PLIP is submitted for review by developer. -5. Framework Team reviews the PLIP and gives feedback. -6. Developer addresses concerns in feedback and re-submits the PLIP, if necessary. -7. This may go back and forth a few times, until both the Framework Team and developer are happy with the result. -8. PLIP is approved for merge. - In rare circumstances, a PLIP will be rejected. - This is usually the result of the developer not responding to feedback or dropping out of the process. - Hang in there! -9. After all other PLIPs are merged, a release is cut. - Standby for bugs! - - -(how-to-submit-a-plip)= - -## How to submit a PLIP - -Whether you want to update the default theme, or rip out a piece of architecture, everyone should go through the PLIP process. -If you need help at any point in this process, please contact a member of the Framework Team personally or ask for help at the [Framework Team Space](https://community.plone.org/c/development/framework-team). - -A PLIP is a [GitHub issue](https://github.com/plone/Products.CMFPlone/issues/new) on [`Products.CMFPlone`](https://github.com/Plone/Products.CMFPlone) with a special template and a specific tag. - -To get started, open a new issue. -The issue will be prefilled with headings and comments for a bug or a PLIP. -Remove the bug part. -Fill in all applicable fields. -After submitting, select the tag `03 type: feature (plip)` for the issues. - -When writing a PLIP, be as specific and to-the-point as you can. -Remember your audience. -To get support for your proposal, people will have to be able to read it! - -A good PLIP is sufficiently clear for a knowledgeable Plone user to understand the proposed changes, and sufficiently detailed for the release manager and other developers to understand the full impact the proposal would have on the code base. - -You don't have to list every line of code that needs to be changed, but you should also give an indication that you have some idea of how the change can be feasibly implemented. - -After your PLIP is written, solicit feedback on your idea on the [Plone Community Forum](https://community.plone.org/). -In this vetting process, you want to make sure that the change won't adversely affect other people on accident. -Others may be able to point out risks or even offer up better or existing solutions. - -Please note a few things: - -- It is very rare that the "Risks" section will be empty or none. -- If you find this is the case, and your PLIP is anything more than trivial, maybe some more vetting should be done. -- The seconder field is REQUIRED. - -We will send the PLIP back to you if it is not filled in. -Currently, this is just someone else who thinks your PLIP is a good idea, a +1. - -In the near future, we will start asking that the seconder is either a coding partner, or someone who is willing and able to finish the PLIP should something happen to the implementer. - - -### Evaluating PLIPs - -After you submit your PLIP, the Framework Team will meet within a couple weeks, and let you know if the PLIP is accepted. -If the PLIP is not accepted, please don't be sad! - -We encourage most PLIPs to go through the add-on process at first, if at all possible, to make sure the majority of the community uses it. - -All communication with you occurs on the PLIP issue itself. -Please keep your eyes and inbox open for changes. - -These are the criteria by which the framework team will review your work: - -- What is size and status of the work needed to be done? -- Is it already an add-on and well established? -- Is this idea well baked and expressed clearly? -- Does the work proposed belong in Plone now, or in the future? -- Is this PLIP more appropriate as a qualified add-on? -- Is this PLIP too risky? - -See the {doc}`plip-review` page for more information. - - -## Implementing your PLIP - -You can start the development at any time, but if you are going to modify Plone itself, it is a good idea to wait to see if your idea is approved. - - -### General Rules - -- Any new packages must be in a branch in the `plone` namespace in GitHub. - You don't have to develop there, but it must be there when submitted. - We recommend using branches off of the repositories under the Plone GitHub organization, and will detail that below. -- Most importantly, the PLIP reviewers must be able run buildout and everything should "just work"™. -- Any new code must: - - - Be {doc}`properly documented `. - - Have clear code. - - [Follow our style guides](https://5.docs.plone.org/develop/styleguide/index.html). - For convenience and better code quality use Python, JavaScript, and other code linting plugins in your editor. - - [Be tested](https://5.docs.plone.org/develop/testing/index.html). - -```{todo} -Update links from Plone 5 to Plone 6 Documentation, once content is migrated. -See https://github.com/plone/documentation/issues/1330 and other issues. -``` - - -### Creating a new PLIP branch - -Create a buildout configuration file for your PLIP in the `plips` folder. -Give it a descriptive name, starting with the PLIP number, for example, {file}`plip-1234-widget-frobbing.cfg`. - -The PLIP number is your PLIP's issue number. - -This file will define the branches you're working with in your PLIP, along with other buildout configuration. - -It should look something like the following, such as in a file {file}`plips/plip-1234-widget-frobbing.cfg`. - -```ini -[buildout] -extends = plipbase.cfg -auto-checkout += - plone.somepackage - plone.app.someotherpackage - -[sources] -plone.somepackage = git https://github.com/plone/plone.somepackage.git branch=plip-1234-widget-frobbing -plone.app.someotherpackage = git https://github.com/plone/plone.app.somepackage.git branch=plip-1234-widget-frobbing - -[instance] -eggs += - plone.somepackage - plone.app.someotherpackage -zcml += - plone.somepackage - plone.app.someotherpackage -``` - -Use the same naming convention when you branch existing packages. -You should always branch packages when working on PLIPs. - - -### Working on a PLIP - -To work on a PLIP, you bootstrap buildout, and then invoke buildout with your PLIP configuration: - -```shell -virtualenv . -./bin/pip install -r requirements.txt -./bin/buildout -c plips/plip-1234-widget-frobbing.cfg -``` - -If you are using a {file}`local.cfg` to extend your PLIP file with some changes that you do not want to commit accidentally, be aware that you need to override some settings from {file}`plipbase.cfg` to avoid some files being created in the {file}`plips` directory or in the directory above the buildout directory. -This is done as shown below. - -```ini -[buildout] -extends = plips/plip-1234-widget-frobbing.cfg -develop-eggs-directory = ./develop-eggs -bin-directory = ./bin -parts-directory = ./parts -sources-dir = ./src -installed = .installed.cfg - -[instance] -var = ./var -``` - - -### Finishing up - -Before marking your PLIP as ready for review, please add a file to give a set of instructions to the PLIP reviewer. -This file should be called {file}`plip__notes.txt`. -This should include, but is not limited to: - -- URLs pointing to all documentation created and updated -- Any concerns and issues still remaining -- Any weird buildout things - -Once you have finished, update your PLIP issue to indicate that it is ready for review. -The Framework Team will assign 2-3 people to review your PLIP. -They will follow the guidelines listed at {doc}`plip-review`. - -After the PLIP has been accepted by the Framework Team and the release manager, you will be asked to merge your work into the main development line. -Merging the PLIP in is not the hardest part, but you must think about it when you develop. - -You'll have to interact with a large number of people to get it all set up. -The merge may cause problems with other PLIPs coming in. -During the merge phase you must be prepared to help out with all the features and bugs that arise. - -If all went as planned, the next Plone release will carry on with your PLIP in it. -You'll be expected to help out with that feature after it's been released (within reason). diff --git a/coredev/release.md b/coredev/release.md deleted file mode 100644 index 3d4ff8ac8..000000000 --- a/coredev/release.md +++ /dev/null @@ -1,136 +0,0 @@ ---- -myst: - html_meta: - "description": "Plone release process" - "property=og:description": "Plone release process" - "property=og:title": "Plone release process" - "keywords": "Plone, release, process" ---- - -```{todo} -Can stay, as it needs a place to live. Check in with Release Managers to update content, if needed -``` - -# Plone release process - -This chapter describes the process to release Plone and its packages. - - -## Release process for Plone packages - -To keep the Plone software stack maintainable, the Python egg release process must be automated to a high degree. -This happens by enforcing Python packaging best practices, and then making automated releases using [`zest.releaser`](https://github.com/zestsoftware/zest.releaser/). - -This is extended with Plone coredev specific features by [`plone.releaser`](https://github.com/plone/plone.releaser). - -Anyone with necessary PyPI permissions must be able to make a new release by running the `fullrelease` command. -This command includes the following requirements. - -```{note} -All files mentioned in this list may be written in Markdown or reStructuredText and have the appropriate file name suffix. -``` - -- All releases must be hosted on PyPI. -- All versions must be tagged in version control. -- Each package must have a {file}`README` file with links to the version control repository and issue tracker. -- {file}`CHANGES` ({file}`docs/HISTORY`) must be always up-to-date and must contain list of functional changes which may affect package users. -- {file}`CHANGES` must contain release dates. -- {file}`README` and {file}`CHANGES` must be visible on PyPI. -- Released eggs must contain generated gettext `.mo` files, but these files must not be committed to the repository. - The `.mo` files can be created with the `zest.pocompile` add-on, which should be installed together with `zest.releaser`. -- `.gitignore` and `MANIFEST.in` must reflect the files going in to the egg (must include page template, po files). - -```{seealso} -[High quality automated package releases for Python with `zest.releaser`](https://opensourcehacker.com/2012/08/14/high-quality-automated-package-releases-for-python-with-zest-releaser/). -``` - - -## Special packages - -The Plone Release Team releases the core Plone packages. -Several others also have the rights to release individual packages on [PyPI](https://pypi.org/). -If you have those rights on your account, you should feel free to make releases. - -Some packages need special care, or should be done only by specific people, as they know what they are doing. -These are: - -`Products.CMFPlone`, `Plone`, and `plone.app.upgrade` -: Please leave these to the release manager, Eric Steele. - -`plone.app.locales` -: Please leave this to the i18n team lead, Vincent Fretin. - - -## Plone core release process checklist - -1. Check Jenkins status. - Check the latest Plone coredev job on [Jenkins](https://jenkins.plone.org/). - It should be green, but if it is not, fix the problem first. - -2. Check out `buildout.coredev`. - - ```shell - git clone git@github.com:plone/buildout.coredev.git - cd buildout.coredev - git checkout 5.1 - python bootstrap.py - bin/buildout -c buildout.cfg - ``` - -3. Check packages for updates. - Check all packages for updates, add to or remove from `checkouts.cfg` accordingly. - This script may help: - - ```shell - bin/manage report --interactive - ``` - - This step should not be needed, because we do the check for every single commit, but people may still have forgotten to add a package to the `checkouts.cfg` file. - -4. Check packages individually. - - Use the `bin/fullrelease` script from the core development buildout. - This includes extra checks that we have added in `plone.releaser`. - It guides you through all the next steps. - - 1. Check changelog. - Check if `CHANGES` is up-to-date. - All changes since the last release should be included. - A "Fixes" or "New" header should be included, with the relevant changes under it. - Upgrade notes are best placed here as well. - Compare `git log HEAD...` with `CHANGES`, or from `zest.releaser` use the command `lasttaglog `. - 2. Run [pyroma](https://pypi.org/project/pyroma/). - 3. Run [check-manifest](https://pypi.org/project/check-manifest/). - 4. Check package "best practices" (`README`, `CHANGES`, `src` directory). - 5. Check if the version in `setup.py` is correct and follows our versioning best practice. - 6. Make a release (zest.releaser: `bin/fullrelease`) - 7. Remove packages from auto-checkout section in `checkouts.cfg` and update `versions.cfg`. - -5. Make sure `plone.app.upgrade` contains an upgrade step for the future Plone release. -6. Update CMFPlone version in `profiles/default/metadata.xml`. -7. Create an issue in to ask the i18n team lead @vincentfretin to do a `plone.app.locales` release. -8. Create a pending release (directory) on [dist.plone.org](https://dist.plone.org/). - - 1. Copy all core packages there. - 2. Possibly make an alpha or beta release of CMFPlone. - 3. Copy the `versions.cfg` file from coredev to there. - -9. Write an email to the Plone developers list announcing a pending release. -10. Update `plone.app.locales` version. -11. Create a unified changelog. - - ```shell - bin/manage changelog - ``` - -12. Make the final release on dist.plone.org (remove "-pending") -13. Update the "-latest" link on [dist.plone.org](https://dist.plone.org/). -14. For Plone 5.x versions only, create the new release on [Launchpad](https://launchpad.net/plone/). -15. Create a release page on [plone.org](https://plone.org/download/releases) -16. Send links to the installers list at plone-installers@lists.sourceforge.net. -17. Wait for installers to be uploaded to Launchpad, with a link to the plone.org release page. -18. Publish release page on plone.org. -19. Update plone.org homepage links to point to the new release. -20. Send out announcement to the plone-announce email distribution list. -21. Update #plone topic (obsolete? maybe announce to Discord?) -22. Ask the security team to update the [Hotfixes](https://plone.org/security/hotfixes/) page in the configuration control panel. diff --git a/coredev/roboto.md b/coredev/roboto.md deleted file mode 100644 index ef2e7a109..000000000 --- a/coredev/roboto.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -myst: - html_meta: - "description": "Mr. Roboto" - "property=og:description": "Mr. Roboto" - "property=og:title": "Mr. Roboto" - "keywords": "Mr. Roboto, mr.roboto, Plone" ---- - -```{todo} -Needs content review, it looks highly outdated with references to CVS, kgs and other obsolete tech -``` - -# Mr. Roboto - -```{todo} -Add brief description of what is Mr. Roboto and what it does. -``` - -## GitHub push - -When a push happens on GitHub, `mr.roboto` is triggered and it starts to analyze the push. - -- If it's on `buildout-coredev`, it starts the job of the branch that has been pushed. - In this case, we send to `plone-cvs` the commit to keep track of the commits on that list. -- If it's on a package that's on the {file}`sources.cfg` of a `buildout-coredev`, it starts the coredev jobs that are linked to that package and a kgs job with that package. - This kgs job is a snapshot of the last working version of the `buildout.coredev` with the newest version of the package that is involved on the push. - These jobs are really fast, as we only test the package applied to the kgs Plone and Python version `coredev` buildout. -- If it's on a PLIP specification, it runs the job that is configured Through The Web on the `mr.roboto` interface at http://jenkins.plone.org/roboto/plips. - -```{todo} -`http://jenkins.plone.org/roboto/plips` is obsolete, and returns a 404 not found. -``` - - -## Job finishes - -When Jenkins finishes a job, it makes a callback to `mr.roboto`, which in turn does the following: - -- If it comes from a `coredev` job, when all the `coredev` jobs related to that push are finished, it writes a comment on the GitHub commit with all the information. - It does this one time only, with all the information, so no more empty mails from the GitHub notification system. -- If it comes from a kgs job and all the kgs jobs are finished, (that may take max 10 min) and some have failed, we send an email to the testbot mailing list saying that a commit failed on the kgs job. - We also send an email to [plone-cvs](https://sourceforge.net/projects/plone/lists/plone-cvs) with the information to keep track of all the commits. -- If it comes from a kgs job and all the kgs jobs are finished, and all are working, we send an email to [plone-cvs](https://sourceforge.net/projects/plone/lists/plone-cvs) with the information to keep track of all the commits. - -For all kgs jobs jenkins sends an email to the author with the results when is finished. - -All the notifications have an URL similar to http://jenkins.plone.org/roboto/get_info?push=9a183de85b3f48abb363fa8286928a10. - -```{todo} -http://jenkins.plone.org/roboto/get_info?push=9a183de85b3f48abb363fa8286928a10 is obsolete, and returns a 404 not found. -``` - -On this URL, there is the commit hash, who committed it, the diff, the files, and the result for each Jenkins job. - -- [plone-testbot](https://lists.plone.org/mailman/listinfo/plone-testbot) mailing list receives messages only when a test fails on the kgs environment, and may take up to ten minutes from the push. -- [plone-cvs](https://sourceforge.net/projects/plone/lists/plone-cvs) always has the commit, diff, and the information, and it may take ten minutes to get there after the push. -- The author receives the results of tests failing against kgs after ten minutes after the push. - -```{note} -In case of integration errors with other packages that may fail because of the push, kgs will not be aware of that. -It's important that at the end (and after the fifty minutes that takes the `coredev` jobs to complete), that you also check the latest version of `coredev` with your push. -``` diff --git a/coredev/troubleshooting.md b/coredev/troubleshooting.md deleted file mode 100644 index 61a94d3f3..000000000 --- a/coredev/troubleshooting.md +++ /dev/null @@ -1,186 +0,0 @@ ---- -myst: - html_meta: - "description": "Troubleshooting development issues in Plone" - "property=og:description": "Troubleshooting development issues in Plone" - "property=og:title": "Troubleshooting development issues in Plone" - "keywords": "Troubleshooting, development issues, Plone" ---- - -```{todo} -Needs review. In general, a 'troubleshooting' page is nice, but this looks outdated -``` - -# Troubleshooting - -This chapter describes how to troubleshoot development issues in Plone. - - -## Buildout issues - -Buildout can be frustrating for those unfamiliar with parsing through autistic robot language. -These errors are almost always a quick fix, and a little bit of understanding goes a long way. - - -### Errors running `bootstrap.py` - -You may not even get to running buildout, and then you will already have an error. -Let's take this one for example: - -```console - File "/usr/local/lib/python2.6/site-packages/distribute-0.6.13-py2.6.egg/pkg_resources.py", line 556, in resolve - raise VersionConflict(dist,req) # XXX put more info here - pkg_resources.VersionConflict: (zc.buildout 1.5.1 (/usr/local/lib/python2.6/site-packages/zc.buildout-1.5.1-py2.6.egg), Requirement.parse('zc.buildout==1.5.2')) -``` - -Buildout has simply noticed that the version of buildout required by the file `bootstrap.py` you are trying to run does not match the version of buildout in your Python library. -In the error above, your system has buildout 1.5.1 installed and the `bootstrap.py` file wants to run with 1.5.2. - -To fix, you have a couple options. -First, you can force buildout to run with the version you already have installed by invoking the version tag. -This tells your Plone `bootstrap.py` file to play nicely with the version that you already have installed. -In the case of the error pasted above, that would be: - -```shell -python bootstrap.py --version=1.5.1 -``` - -I personally know that versions 1.4.4, 1.5.1, and 1.5.2 all work this way. - -The other option is to delete your current egg and force the upgrade. -In the case of the error above, delete the egg the system currently has, for example: - -```shell -rm -rf /usr/local/lib/python2.6/site-packages/zc.buildout-1.5.1-py2.6.egg -``` - -When you rerun bootstrap, it will look for the buildout of the egg, note that there isn't one, and then go fetch a new egg in the version that it wants for you. - -Do one of those and re-run bootstrap. - -One other thing of note is that running bootstrap effectively ties that Python executable and all of its libraries to your buildout. -If you have several Python installs, and want to switch which Python is tied to your buildout, simply rerun `bootstrap.py` with the new Python (and then rerun buildout). -You may get the same error above again, but now that you know how to fix it, you can spend that time drinking beer instead of smashing your keyboard. - -Hooray! - - -### When `mr.developer` is unhappy - -`mr.developer` is never unhappy, except when it is. -Although this technically isn't a buildout issue, it happens when running buildout, so I'm putting it under buildout issues. - -When working with the dev instance, especially with all the moving back and forth between GitHub and Subversion, you may have an old copy of a `src` package. -The error looks like: - -```console -mr.developer: Can't update package 'Products.CMFPlone' because its URL doesn't match. -``` - -As long as you don't have any pending commits, you just need to remove the package from {file}`src/` and it will recheck it out for you when it updates. - -You can also get such fun errors as: - -```console -Link to http://sphinx.pocoo.org/ ***BLOCKED*** by --allow-hosts -``` - -These are OK to ignore if and only if the lines following it say: - -```console -Getting distribution for 'Sphinx==1.0.7'. -Got Sphinx 1.0.7. -``` - -If buildout ends with warning you that some packages could not be downloaded, then chances are that package wasn't downloaded. -This is bad and could cause all sorts of whack out errors when you start or try to run things because it never actually downloaded the package. - -There are two ways to get this error to go away. - -The first is to delete all instances of host filtering. -Go through all the files and delete any lines which say `allow-hosts =` and `allow-hosts +=`. -In theory, by restricting which hosts you download from, buildout will go faster. -The point is that they are safely deletable. - -The second option is to allow the host that it is pointing to by adding something like this to your `.cfg`: - -```cfg -allow-hosts += sphinx.pocoo.org -``` - -Again, this is only necessary if the package wasn't found in the end. - - -### `mr.developer` path errors - -```console -ERROR: You are not in a path which has mr.developer installed (:file:`.mr.developer.cfg` not found). -``` - -When running any {command}`./bin/develop` command. - -To fix, do: - -```shell -ln -s plips/.mr.developer.cfg -``` - - -## Other random issues - -```{TODO} -These need to be revalidated -``` - - -### Dirty packages - -```console -ERROR: Can't update package 'Some package', because it's dirty. -``` - - -#### Fix - -`mr.developer` is complaining because a file has been changed or added, but not committed. - -Use `bin/develop update --force`. -Adding `*.pyc *~.nib *.egg-info .installed.cfg *.pt.py *.cpt.py *.zpt.py *.html.py *.egg` to your subversion configuration's `global-ignores` has been suggested as a more permanent solution. - - -### No module named zope 2 - -```console -ImportError: No module named Zope2" when building using a PLIP cfg file. -``` - -Appears to not actually be the case. -Delete {file}`mkzopeinstance.py` from {file}`bin/`, and rerun buildout to correct this if you're finding it irksome. - - -### Can't open file '/Startup/run.py' - -Two possible fixes. - -If you use Python 2.4 by mistake, use 2.6 instead. - -Or you may need to make sure you run `bin/buildout …` after `bin/develop …`. -Try removing {file}`parts/*`, {file}`bin/*`, {file}`.installed.cfg`, then re-bootstrap and re-run buildout, develop, buildout. - - -### Missing PIL - -{file}`pil.cfg` is included within this buildout to aid in PIL installation. -Run {command}`bin/buildout -c pil.cfg` to install. -This method does not work on Windows. -We're unable to run it by default. - - -### Modified egg issues - -{command}`bin/develop status` is showing that the `Products.CMFActionIcons` egg has been modified, but I haven't touched it. -And this is preventing `bin/develop up` from updating all the eggs. - -#### Fix - -Edit {file}`~/.subversion/config` and add `eggtest\*.egg` to the list of `global-ignores`. From 89add234ed2783481a78f2218f0a142d4514bc35 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 20 Jul 2024 15:05:09 +0200 Subject: [PATCH 375/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index f7adcdc08..b958cb251 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit f7adcdc08491449a90fa546e3fded078dfc1eaf0 +Subproject commit b958cb25149ffd8e8a6112fe6c9c310ddbba89ab From fbe51197ff6844239994698122aba04b87ac7179 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 20 Jul 2024 15:49:01 +0200 Subject: [PATCH 376/810] Add label for pre-requisites --- docs/contributing/core/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 0a02f6691..304d094ef 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -30,6 +30,8 @@ You must {ref}`contributing-sign-and-return-the-plone-contributor-agreement-labe Before you contribute to Plone core, check the [version support policy](https://plone.org/download/release-schedule) to see which versions of Plone are currently supported. +(plone-pre-requisites-label)= + ## Pre-requisites It is beyond the scope of this documentation to provide installation instructions for all pre-requisites for your operating system. From d2cf5c5f3dca0013a556d0840df5daa42b364ed3 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 20 Jul 2024 16:05:57 +0200 Subject: [PATCH 377/810] Add label for working with git --- docs/contributing/core/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 304d094ef..a748f8386 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -147,6 +147,8 @@ To login, the default credentials are the following. - password: `admin` +(contributing-core-work-with-git-label) + ## Work with git ```{important} From 95bbcc7183024fba0a8b9f876ad588eeb0d647e9 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 20 Jul 2024 20:59:10 +0200 Subject: [PATCH 378/810] syntax fix --- docs/contributing/core/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index a748f8386..4b7773c0b 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -147,7 +147,7 @@ To login, the default credentials are the following. - password: `admin` -(contributing-core-work-with-git-label) +(contributing-core-work-with-git-label)= ## Work with git From f0ca74e327b066c99540a24bfa805592fa93b379 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 21 Jul 2024 00:13:27 +0200 Subject: [PATCH 379/810] Update `plone.api` contributing link, fix myst html_meta syntax --- docs/classic-ui/module-federation.md | 11 ++++++----- docs/contributing/index.md | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/classic-ui/module-federation.md b/docs/classic-ui/module-federation.md index fab33a89b..06b73ad7a 100644 --- a/docs/classic-ui/module-federation.md +++ b/docs/classic-ui/module-federation.md @@ -1,9 +1,10 @@ --- -html_meta: - "description": "How to use Module Federation in Mockup and add-on bundles." - "property=og:description": "How to use Module Federation in Mockup and add-on bundles." - "property=og:title": "Module Federation in Mockup" - "keywords": "Plone, Classic UI, classic-ui, Mockup, Module Federation, webpack, JavaScript" +myst: + html_meta: + "description": "How to use Module Federation in Mockup and add-on bundles." + "property=og:description": "How to use Module Federation in Mockup and add-on bundles." + "property=og:title": "Module Federation in Mockup" + "keywords": "Plone, Classic UI, classic-ui, Mockup, Module Federation, webpack, JavaScript" --- (classic-ui-module-federation-in-mockup-label)= diff --git a/docs/contributing/index.md b/docs/contributing/index.md index 54735e7e7..5214b687e 100644 --- a/docs/contributing/index.md +++ b/docs/contributing/index.md @@ -154,7 +154,7 @@ Documentation Plone API : API methods for Plone functionality. - See {doc}`../plone.api/contribute/index`. + See {doc}`../plone.api/contribute`. Plone REST API : A RESTful API for Plone. From 8c976c93f2341e51844c68e604b75dae3db0f4a4 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 21 Jul 2024 00:14:28 +0200 Subject: [PATCH 380/810] Update `plone.api` contributing link --- docs/contributing/plone-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/plone-api.md b/docs/contributing/plone-api.md index f567f0a6c..a95beafa0 100644 --- a/docs/contributing/plone-api.md +++ b/docs/contributing/plone-api.md @@ -9,4 +9,4 @@ myst: # Contributing to `plone.api` -See {doc}`/plone.api/contribute/index` under {guilabel}`Backend > plone.api`. +See {doc}`/plone.api/contribute` under {guilabel}`Backend > plone.api`. From 1c25b55cf78b000f76bdfab984f11ebf8d500767 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 23 Jul 2024 12:58:38 +0200 Subject: [PATCH 381/810] Opsworks was EOL on May 26, 2024 https://aws.amazon.com/blogs/mt/seamlessly-off-board-from-aws-opsworks-stacks-by-detaching-resources/ --- docs/glossary.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/glossary.md b/docs/glossary.md index bf30a43de..09662074e 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -94,9 +94,6 @@ S3 TTW Through-The-Web allows editing or customizing a Plone site through a web browser. -Amazon Opsworks - [AWS OpsWorks](https://aws.amazon.com/opsworks/) is a configuration management service that uses Chef, an automation platform that treats server configurations as code. - Ansible [Ansible](https://www.ansible.com/) is an open source automation platform. Ansible can help you with configuration management, application deployment, task automation. From 448c41d2be1c5668d0e86cd3f98d1deaaf9f910e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 24 Jul 2024 02:30:33 +0200 Subject: [PATCH 382/810] Update tips submodules/plone.api submodules/volto --- submodules/plone.api | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index f29d2a178..360c5965f 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit f29d2a178b51f659171c4f773fced1d9b3005d3e +Subproject commit 360c5965ffe3f9840c68f0f9f65999a3f81eab2b diff --git a/submodules/volto b/submodules/volto index b958cb251..a937f98dd 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit b958cb25149ffd8e8a6112fe6c9c310ddbba89ab +Subproject commit a937f98dd3fc43a0c83209d77785c9afa2b5a8f3 From 61ba8060e596151a45bad8b5dbe2991b8f3f29af Mon Sep 17 00:00:00 2001 From: Philip Bauer Date: Tue, 30 Jul 2024 11:38:36 +0200 Subject: [PATCH 383/810] link to finished docs, not to ticket --- .../upgrading/version-specific-migration/migrate-to-volto.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend/upgrading/version-specific-migration/migrate-to-volto.md b/docs/backend/upgrading/version-specific-migration/migrate-to-volto.md index 9a7c5bda1..eb8aa0896 100644 --- a/docs/backend/upgrading/version-specific-migration/migrate-to-volto.md +++ b/docs/backend/upgrading/version-specific-migration/migrate-to-volto.md @@ -107,5 +107,5 @@ It is recommended to use the default settings, but you can choose to skip some m If you are migrating an existing site to Plone 6 using [{py:mod}`collective.exportimport`](https://pypi.org/project/collective.exportimport) and want to use Volto in the new site, then you do not need to use the form `@@migrate_to_volto`. All the changes documented above can be done efficiently during export and import. -[Read details](https://github.com/collective/collective.exportimport/issues/133). +[Read details](https://github.com/collective/collective.exportimport?tab=readme-ov-file#migrate-to-volto). ``` From 772451fd95795f997fb047c841e9244c1bb1ea14 Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Wed, 31 Jul 2024 09:49:52 +0200 Subject: [PATCH 384/810] document how to contribute using Weblate --- docs/i18n-l10n/contributing-translations.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index 9f8af6981..34dc11e35 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -77,6 +77,20 @@ The process of translating the Volto frontend is the following. 4. Commit your changes, and create a pull request. +(contributing-plone-core-translations-using-weblate)= + +## Using Weblate to translate Plone + +[Weblate](https://weblate.org/) is an Open Source project to help software developers translate their projects. + +It lets the translator to work in a web based interface, without the need of installing any third-party software or without the need to use git or GitHub. + +Plone Foundation has obtained a so called `libre` account for Plone, meaning we get the hosting with many other Open Source Projects at the [Hosted](https://hosted.weblate.org/) platform that Weblate offers to Open Source projects. + +This means that the translator can go to the [Plone project and Weblate](https://hosted.weblate.org/projects/plone/) and start translating there. + +You will need to create an account there and then your translations will be automatically contributed back to Plone's GitHub repository. + (contributing-plone-core-translations-support-label)= From 71e9edb1c06585a8e0dcf5b34af30dc905711d1a Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Wed, 31 Jul 2024 09:50:54 +0200 Subject: [PATCH 385/810] add volto note --- docs/i18n-l10n/contributing-translations.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index 34dc11e35..89b2a644a 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -91,6 +91,10 @@ This means that the translator can go to the [Plone project and Weblate](https:/ You will need to create an account there and then your translations will be automatically contributed back to Plone's GitHub repository. +```{note} +At this moment Volto translations can't be contributed using Weblate. We are working on this issue and we hope to have it fixed as soon as possible. +``` + (contributing-plone-core-translations-support-label)= From a92d3d132cf77de1b870af9872dca54ece936334 Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Thu, 1 Aug 2024 09:18:53 +0200 Subject: [PATCH 386/810] Update docs/i18n-l10n/contributing-translations.md Co-authored-by: Steve Piercy --- docs/i18n-l10n/contributing-translations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index 89b2a644a..25746b23e 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -79,7 +79,7 @@ The process of translating the Volto frontend is the following. (contributing-plone-core-translations-using-weblate)= -## Using Weblate to translate Plone +## Weblate for translations [Weblate](https://weblate.org/) is an Open Source project to help software developers translate their projects. From f8eb930232ce5c588d059d48e5f40c836363e101 Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Thu, 1 Aug 2024 09:19:03 +0200 Subject: [PATCH 387/810] Update docs/i18n-l10n/contributing-translations.md Co-authored-by: Steve Piercy --- docs/i18n-l10n/contributing-translations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index 25746b23e..aa62441f8 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -77,7 +77,7 @@ The process of translating the Volto frontend is the following. 4. Commit your changes, and create a pull request. -(contributing-plone-core-translations-using-weblate)= +(contributing-weblate-for-translations)= ## Weblate for translations From 66bf1ef70156346a1ff5bf25f4e6df181e06ec06 Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Thu, 1 Aug 2024 09:19:29 +0200 Subject: [PATCH 388/810] Update docs/i18n-l10n/contributing-translations.md Co-authored-by: Steve Piercy --- docs/i18n-l10n/contributing-translations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index aa62441f8..4a0b36f11 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -81,7 +81,7 @@ The process of translating the Volto frontend is the following. ## Weblate for translations -[Weblate](https://weblate.org/) is an Open Source project to help software developers translate their projects. +[Weblate](https://weblate.org/) is an open source project to help software developers translate their projects. It lets the translator to work in a web based interface, without the need of installing any third-party software or without the need to use git or GitHub. From e4e094c0eef40498295679941083fd48131deffc Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Thu, 1 Aug 2024 09:19:44 +0200 Subject: [PATCH 389/810] Update docs/i18n-l10n/contributing-translations.md Co-authored-by: Steve Piercy --- docs/i18n-l10n/contributing-translations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index 4a0b36f11..a0b9acaa9 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -83,7 +83,7 @@ The process of translating the Volto frontend is the following. [Weblate](https://weblate.org/) is an open source project to help software developers translate their projects. -It lets the translator to work in a web based interface, without the need of installing any third-party software or without the need to use git or GitHub. +Translators can work in a web interface, and not have to install third-party software or use git or GitHub. Plone Foundation has obtained a so called `libre` account for Plone, meaning we get the hosting with many other Open Source Projects at the [Hosted](https://hosted.weblate.org/) platform that Weblate offers to Open Source projects. From b36518e7a8c5a9ddb5d727b7067ea749a40670bb Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Thu, 1 Aug 2024 09:20:05 +0200 Subject: [PATCH 390/810] Update docs/i18n-l10n/contributing-translations.md Co-authored-by: Steve Piercy --- docs/i18n-l10n/contributing-translations.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index a0b9acaa9..09f2a10e7 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -85,7 +85,8 @@ The process of translating the Volto frontend is the following. Translators can work in a web interface, and not have to install third-party software or use git or GitHub. -Plone Foundation has obtained a so called `libre` account for Plone, meaning we get the hosting with many other Open Source Projects at the [Hosted](https://hosted.weblate.org/) platform that Weblate offers to Open Source projects. +The Plone Foundation has obtained a "gratis Libre plan" account for Plone. +Plone gets free hosting at the [Hosted](https://hosted.weblate.org/) platform that Weblate offers to open source projects. This means that the translator can go to the [Plone project and Weblate](https://hosted.weblate.org/projects/plone/) and start translating there. From 77fe6eacb35d45df6db5e55e7cf24026d9516315 Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Thu, 1 Aug 2024 09:20:16 +0200 Subject: [PATCH 391/810] Update docs/i18n-l10n/contributing-translations.md Co-authored-by: Steve Piercy --- docs/i18n-l10n/contributing-translations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index 09f2a10e7..bd63e3252 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -88,7 +88,7 @@ Translators can work in a web interface, and not have to install third-party sof The Plone Foundation has obtained a "gratis Libre plan" account for Plone. Plone gets free hosting at the [Hosted](https://hosted.weblate.org/) platform that Weblate offers to open source projects. -This means that the translator can go to the [Plone project and Weblate](https://hosted.weblate.org/projects/plone/) and start translating there. +Translators can go to the [Plone project in Weblate](https://hosted.weblate.org/projects/plone/) to write translations. You will need to create an account there and then your translations will be automatically contributed back to Plone's GitHub repository. From f35c1f08f0ff788f203c3795473648efcaa9d31f Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Thu, 1 Aug 2024 09:20:32 +0200 Subject: [PATCH 392/810] Update docs/i18n-l10n/contributing-translations.md Co-authored-by: Steve Piercy --- docs/i18n-l10n/contributing-translations.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index bd63e3252..a20b38883 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -90,7 +90,8 @@ Plone gets free hosting at the [Hosted](https://hosted.weblate.org/) platform th Translators can go to the [Plone project in Weblate](https://hosted.weblate.org/projects/plone/) to write translations. -You will need to create an account there and then your translations will be automatically contributed back to Plone's GitHub repository. +Translators will need to create an account there. +Then your translations will be automatically contributed back to Plone's GitHub repository. ```{note} At this moment Volto translations can't be contributed using Weblate. We are working on this issue and we hope to have it fixed as soon as possible. From a8f2c3fd35f9c25f527d9dc16b9288929b232675 Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Thu, 1 Aug 2024 09:20:51 +0200 Subject: [PATCH 393/810] Update docs/i18n-l10n/contributing-translations.md Co-authored-by: Steve Piercy --- docs/i18n-l10n/contributing-translations.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index a20b38883..a48e8769f 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -94,7 +94,8 @@ Translators will need to create an account there. Then your translations will be automatically contributed back to Plone's GitHub repository. ```{note} -At this moment Volto translations can't be contributed using Weblate. We are working on this issue and we hope to have it fixed as soon as possible. +At this moment Volto translations can't be contributed using Weblate. +The Volto Team are working on this issue, and hope to fix it as soon as possible. ``` From 2c64e0f4a2e3d1cce266172fa579b01a7e37c57d Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Thu, 1 Aug 2024 19:25:51 +0200 Subject: [PATCH 394/810] Plone 6.0.12 --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 13a8ca8af..ffe125d00 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -350,7 +350,7 @@ def source_replace(app, docname, source): # Dict of replacements. source_replacements = { "{PLONE_BACKEND_MINOR_VERSION}": "6.0", - "{PLONE_BACKEND_PATCH_VERSION}": "6.0.11.1", + "{PLONE_BACKEND_PATCH_VERSION}": "6.0.12", "{NVM_VERSION}": "0.39.5", "{SUPPORTED_PYTHON_VERSIONS}": "3.8, 3.9, 3.10, 3.11, or 3.12", } From daf7d0d449563cac8a0c5fd766850fd2bccc84dc Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 6 Aug 2024 00:28:07 -0700 Subject: [PATCH 395/810] Update contributing-translations.md Using our combined super powers, add information from @mauritsvanrees and @erral to clarify the process. --- docs/i18n-l10n/contributing-translations.md | 24 ++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index a48e8769f..4041b8913 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -82,22 +82,36 @@ The process of translating the Volto frontend is the following. ## Weblate for translations [Weblate](https://weblate.org/) is an open source project to help software developers translate their projects. - Translators can work in a web interface, and not have to install third-party software or use git or GitHub. - The Plone Foundation has obtained a "gratis Libre plan" account for Plone. Plone gets free hosting at the [Hosted](https://hosted.weblate.org/) platform that Weblate offers to open source projects. -Translators can go to the [Plone project in Weblate](https://hosted.weblate.org/projects/plone/) to write translations. -Translators will need to create an account there. -Then your translations will be automatically contributed back to Plone's GitHub repository. +### Weblate workflow + +Translators will need to create an account on Weblate with an email and password. +Authentication with GitHub and other third-party accounts might not work. + +Translators can go to the [Plone project in Weblate](https://hosted.weblate.org/projects/plone/). + +You will see several components listed. +The `volto` component is for the package `volto`, whose repository is at https://github.com/plone/volto. ```{note} At this moment Volto translations can't be contributed using Weblate. The Volto Team are working on this issue, and hope to fix it as soon as possible. ``` +All other components are for the package `plone.app.locales`, whose repository is at https://github.com/collective/plone.app.locales. + +See the Weblate documentation, [Translating using Weblate](https://docs.weblate.org/en/latest/user/translating.html), for how to use it to write translations. + +When you save a translation, then it is committed on a branch used only for translations in the respective GitHub repository. + +[Compare recent commits to the branch `translations-plone` on the package `plone.app.locales`](https://github.com/collective/plone.app.locales/compare/master...translations-plone). + +Maintainers will periodically create a pull request from the changes, and merge it. + (contributing-plone-core-translations-support-label)= From adf44ef64c791c7b64ca502036a3362f1a4f42a0 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 6 Aug 2024 00:53:28 -0700 Subject: [PATCH 396/810] Fix redirect to weblate.org --- docs/i18n-l10n/contributing-translations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index 4041b8913..068ba5bf1 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -81,7 +81,7 @@ The process of translating the Volto frontend is the following. ## Weblate for translations -[Weblate](https://weblate.org/) is an open source project to help software developers translate their projects. +[Weblate](https://weblate.org/en/) is an open source project to help software developers translate their projects. Translators can work in a web interface, and not have to install third-party software or use git or GitHub. The Plone Foundation has obtained a "gratis Libre plan" account for Plone. Plone gets free hosting at the [Hosted](https://hosted.weblate.org/) platform that Weblate offers to open source projects. From a49cb6c8aba0d5134ad3406777824cb6a4c97653 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 6 Aug 2024 01:00:11 -0700 Subject: [PATCH 397/810] Fix redirect --- docs/install/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install/index.md b/docs/install/index.md index fbe83381b..2cdb8af20 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -21,7 +21,7 @@ In this part of the documentation, you can find how to {ref}`try Plone Date: Tue, 6 Aug 2024 01:21:38 -0700 Subject: [PATCH 398/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index a937f98dd..1d58a3062 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit a937f98dd3fc43a0c83209d77785c9afa2b5a8f3 +Subproject commit 1d58a3062037b428267a953b7d99d61351e3eae1 From bd2f83acd3515680ce71dc1763f0a809f97a8e17 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 12 Aug 2024 17:47:35 -0700 Subject: [PATCH 399/810] Update tips submodules/plone.api submodules/plone.restapi submodules/volto --- submodules/plone.api | 2 +- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index 360c5965f..47245aa8d 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit 360c5965ffe3f9840c68f0f9f65999a3f81eab2b +Subproject commit 47245aa8d3a0bde5c645818a441dac44e1919a0f diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 86e62411c..602ccc695 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 86e62411cb9910c907facd428219690fc8a1307c +Subproject commit 602ccc6955eb066a989b24bfc0ac85b72da7cdc6 diff --git a/submodules/volto b/submodules/volto index 1d58a3062..861554273 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 1d58a3062037b428267a953b7d99d61351e3eae1 +Subproject commit 861554273f4b1679059b8cc59005c21d0a49115f From 12d8220dd1ee5a26ba8657e2d965870d9166cb5c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 12 Aug 2024 18:01:31 -0700 Subject: [PATCH 400/810] Fix redirect --- docs/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/glossary.md b/docs/glossary.md index 09662074e..7776a1095 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -719,7 +719,7 @@ Prettier GitHub workflow GitHub workflows - A [GitHub workflow](https://docs.github.com/en/actions/using-workflows) is a configurable automated process that will run one or more jobs. + A [GitHub workflow](https://docs.github.com/en/actions/writing-workflows) is a configurable automated process that will run one or more jobs. husky [Husky](https://typicode.github.io/husky/) automatically lints your commit messages, code, and runs tests upon committing or pushing commits to a remote repository. From eb74510597765b49e3d71d20cbe53881867c44fc Mon Sep 17 00:00:00 2001 From: Gil Forcada Codinachs Date: Sun, 7 Jul 2024 19:26:36 +0200 Subject: [PATCH 401/810] feat: rewrite the continuous integration docs Explain Jenkins. --- .../core/continuous-integration.md | 107 ++++++------------ 1 file changed, 36 insertions(+), 71 deletions(-) diff --git a/docs/contributing/core/continuous-integration.md b/docs/contributing/core/continuous-integration.md index 9cf3e6fda..c53bcba25 100644 --- a/docs/contributing/core/continuous-integration.md +++ b/docs/contributing/core/continuous-integration.md @@ -7,105 +7,70 @@ myst: "keywords": "Plone, continuous integration, best practices" --- -# Essential continuous integration practices +# Continuous Integration -The {term}`CI` system at [jenkins.plone.org](https://jenkins.plone.org) is a shared resource for Plone core developers to notify them of regressions in Plone core code. +As a complex system build out of hundreds of small packages, Plone can be easily broken, inadvertently, with any change on any of its packages. -Build breakages are a normal and expected part of the development process. -The aim is to find errors and remove them as quickly as possible, without expecting perfection and zero errors. -However, there are some essential practices that you need follow to achieve a stable build: +For that a mix of a {term}`CI` system at [jenkins.plone.org](https://jenkins.plone.org) and GitHub Actions ensure that any change is thoroughly checked. +## Jenkins -## 1) Don't check in on a broken build +Jenkins is the primary source of truth to know if the complete test suite of any Plone versions in development is passing or not. -Do not make things more complicated for the developer who is responsible for breaking the build. +Jenkins is configured to react on changes done in any of the hundreds of repositories that all together make Plone. -If the build breaks, the developer has to identify the cause of the breakage as soon as possible and should fix it. -This strategy gives the developer the best option to find out what caused the breakage and fix it immediately. -Fixing the build is easier with a clear look at the problem. -Checking in further changes and triggering new builds will complicate matters and lead to more problems. +Whenever a change on any of those repositories happen, Jenkins starts a slew of testing jobs that ultimately answer the question of if those changes pass Plone's test suite. -If the build is broken over a longer period of time (more than a couple of hours) you should either: +### Triggering jobs (automatically) -- notify the developer who is responsible for the breakage -- fix the problem yourself -- revert the commit so you and others can continue to work +As running the Jenkins jobs is a bit expensive, in time, Jenkins does not run automatically on any new commit. -```{note} -There is one exception to this rule. -Sometimes there are changes or tests that depend on changes in other packages. -If this is the case, there is no way around breaking a single build for a certain period of time. -In this case, run the all tests locally with all the changes and commit them within a time frame of ten minutes. -``` - - -## 2) Always run all commit tests locally before committing - -Follow this practice so the build stays green, and other developers can continue to work without breaking the first rule. - -Remember that Plone development can happen all over the world, at all times. -Other developers may have checked in changes since your last synchronization. -These may interact with your work. - -Therefore it's essential that you merge changes from the main branch into your feature branch, then run the tests again, before you push your changes to GitHub. - -A common source of errors on check-in is to forget to add some files to the repository. -Use {command}`git status` to check and correct for this. -Also double-check to not check in files that should not be part of a package, such as editor configuration files and git submodules. +Rather, Jenkins waits for a special comment to be found in a pull request on a repository that is monitored by Jenkins. +```text +@jenkins-plone-org please run jobs +``` -## 3) Wait for commit tests to pass before moving on - -Always monitor the build's progress, and fix the problem right away if it fails. -If you introduced a regression, you have a far better chance of fixing the build sooner than later. -Also another developer might have committed in the meantime (by breaking rule 1), making things more complicated for you. - - -## 4) Never go home on a broken build - -Take into account the first rule of CI ("Don't check in on a broken build"). -Breaking the build essentially stops all other developers from working on it. -Therefore going home on a broken build—or even on a build that has not finished yet—is _not_ acceptable. -It will prevent all other developers from working, or they will need to fix the errors that you introduced. +Pasting the text above on a pull request, will trigger Jenkins to run all configured test suites related to the current pull request, **with the changes of the pull request itself**. +#### buildout.coredev special case -## 5) Always be prepared to revert to the previous revision +`buildout.coredev` is the special repository where our configuration and tooling to orchestrate Plone lies in. -For other developers to work on the build, you should always be prepared to revert to the previous passing revision. +Contrary to all the other repositories, whenever a commit is made on this repository, it automatically triggers Jenkins jobs to be run. +### Triggering jobs (manually) -## 6) Time-box fixing before reverting +Jenkins jobs can also be triggered manually by going to our Jenkins server, login in with your GitHub account, finding the right job, and triggering the `Run` button. -When the build breaks on check-in, try to fix it for ten minutes. -If, after ten minutes, you aren't finished with the solution, revert to the previous version from your version control system. -This way you will allow other developers to continue to work. +### Results +Once a jenkins job is finished, it will update its status icon on Jenkins UI itself, but also report back to GitHub, the result of the job. -## 7) Don't comment out failing tests +For pull requests, this means a green check mark or a red cross will be displayed at the end of the pull request, on pull requests listings, even on the favicon itself. -Once you begin to enforce the previous rule, the result is often that developers start commenting out failing tests in order to get the build passing again as quickly as possible. -While this impulse is understandable, it is _not acceptable_. +This gives the expected feedback to the pull request author, or any reviewer interested in knowing how a given pull request fared in Jenkins. Thus allowing pull request reviewers or authors to decide if the pull request can already be merged. -The tests were passing for a while and then start to fail. -This means that you either caused a regression, made assumptions that are no longer valid, or the application has changed the functionality being tested for a valid reason. +#### On failures -You should always either fix the code (if a regression has been found), modify the test (if one of the assumptions has changed), or delete it (if the functionality under test no longer exists). +If the Jenkins jobs reports failures, the statuses of the pull request will provide a `Details` link back to Jenkins. +That link leads back to the Jenkins job build for that pull request. -## 8) Take responsibility for all breakages that result from your changes +In that page, there is the list of test failures (if any) already listed. Clicking on them show the stacktrace that should help diagnose why there was an error on a given test. -If you commit a change and all the tests you wrote pass, but others break, the build is still broken. -This also applies to tests that fail in `buildout.coredev` and don't belong directly to the package you worked on. -This means that you have introduced a regression bug into the application. +On the side bar of the job build page in Jenkins there is also `Console Output` link. This leads to the **full job output**, note that is large, where it can be seen all the steps and debugging information that Jenkins generated running the job. -It is _your responsibility_ to fix all tests that do not pass because of your changes. +This can be helpful whenever the errors where not on a single test, but rather a general testing set up/tear down problem. -There are some tests in Plone that fail randomly, and the community is always working on fixing those. -If you think you hit such a test, try to fix it or re-run the Jenkins job to see if it passes again. +### Retrying -In any case, the developer who made the commit is responsible to make it pass. +If there were errors on the Jenkins jobs, and corrections have been made on the code, triggering the jenkins jobs again is a matter of giving the special comment on the GitHub pull request again: +```text +@jenkins-plone-org please run jobs +``` -## Further reading +Jenkins jobs can also be restarted within Jenkins UI itself. On the Jenkins job itself, and provided you are logged in, you can find a `Retry` link on the left toolbar. Clicking it will trigger a new Jenkins job with the same configuration as the one you are on. -These rules were taken from the excellent book "Continuous Delivery" by Jez Humble and David Farley (Addison Wesley), and have been adopted and rewritten for the Plone community. +Jenkins will update GitHub statuses accordingly. From 001699bf2f9753b5d47c7e6d11cc456416bef1fd Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 20 Aug 2024 02:29:07 -0700 Subject: [PATCH 402/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 861554273..fdcc8740d 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 861554273f4b1679059b8cc59005c21d0a49115f +Subproject commit fdcc8740d821d6c6c5a6669bd4a572d2784fd203 From 8b9b418890107df5e1715b52805bc85f23f1631c Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Tue, 20 Aug 2024 12:41:57 +0200 Subject: [PATCH 403/810] document that when providing Volto translation one needs to run yarn i18n --- docs/i18n-l10n/contributing-translations.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index 068ba5bf1..3ff047c16 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -75,7 +75,10 @@ The process of translating the Volto frontend is the following. - To update a translation, translate your language's `po` file found at `locales/{language_code}/LC_MESSAGES/volto.po`. - To create a new translation, create a new directory at `locales/{language_code}/LC_MESSAGES/`, copy the file `locales/volto.pot` to `locales/{language_code}/LC_MESSAGES/volto.po` (note to drop the trailing `t`), and start translating. -4. Commit your changes, and create a pull request. +4. Run `yarn i18n` to convert your `po` files into `json`. + Volto loads these `json` files to provide translated text strings in the interface. + +5. Commit your changes, and create a pull request. (contributing-weblate-for-translations)= From 4605f6a780aed0e8ffd4a741d086ba904f6fd33d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 20 Aug 2024 15:08:49 -0700 Subject: [PATCH 404/810] Remove unused term --- docs/glossary.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/glossary.md b/docs/glossary.md index 7776a1095..c2e0cdcda 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -107,10 +107,6 @@ Chef CloudFormation [AWS CloudFormation](https://aws.amazon.com/cloudformation/) gives developers and systems administrators an way to create and manage a collection of related AWS resources, provisioning and updating them in an orderly and predictable fashion. -Travis CI - Travis CI is a hosted, distributed continuous integration service used to build and test software projects hosted at GitHub. - Open source projects may be tested with limited runs via [travis-ci.com](https://www.travis-ci.com). - Solr [Solr](https://solr.apache.org/) is a popular, blazing-fast, open source enterprise search platform built on Apache Lucene. From e85e1aa0b30544af2bf7ddfa1aa832e62f7a9c3d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 20 Aug 2024 16:44:18 -0700 Subject: [PATCH 405/810] Use @gforcada's contribution as a base to further enhance docs - Make statements more concise - Address the reader with "you can do X" instead of passive voice "X is done" - Add pretty inline icons and MyST markup magic - Remove italicization style of `guilabel` elements - Add to index, remove from exclusion --- .../contributing/core/icon-build-now.svg | 1 + docs/_static/contributing/core/icon-retry.svg | 1 + .../contributing/core/icon-terminal.svg | 1 + docs/_static/custom.css | 1 - docs/conf.py | 1 - .../core/continuous-integration.md | 81 +++++++++++-------- docs/contributing/core/index.md | 4 +- 7 files changed, 52 insertions(+), 38 deletions(-) create mode 100644 docs/_static/contributing/core/icon-build-now.svg create mode 100644 docs/_static/contributing/core/icon-retry.svg create mode 100644 docs/_static/contributing/core/icon-terminal.svg diff --git a/docs/_static/contributing/core/icon-build-now.svg b/docs/_static/contributing/core/icon-build-now.svg new file mode 100644 index 000000000..70b5d54b2 --- /dev/null +++ b/docs/_static/contributing/core/icon-build-now.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/_static/contributing/core/icon-retry.svg b/docs/_static/contributing/core/icon-retry.svg new file mode 100644 index 000000000..cd349c507 --- /dev/null +++ b/docs/_static/contributing/core/icon-retry.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/_static/contributing/core/icon-terminal.svg b/docs/_static/contributing/core/icon-terminal.svg new file mode 100644 index 000000000..9f15c271a --- /dev/null +++ b/docs/_static/contributing/core/icon-terminal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 41bdd4361..6242c425c 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -422,7 +422,6 @@ span.menuselection { padding: 4px 5px; font-size: 90%; font-weight: bold; - font-style: italic; white-space: nowrap; } diff --git a/docs/conf.py b/docs/conf.py index ffe125d00..13b6e95bf 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -125,7 +125,6 @@ "**/CONTRIBUTORS.rst", "**/LICENSE.rst", "**/README.rst", - "contributing/core/continuous-integration.md", "plone.restapi/.*", "plone.restapi/bin", "plone.restapi/docs/source/glossary.md", # There can be only one Glossary. diff --git a/docs/contributing/core/continuous-integration.md b/docs/contributing/core/continuous-integration.md index c53bcba25..70f754865 100644 --- a/docs/contributing/core/continuous-integration.md +++ b/docs/contributing/core/continuous-integration.md @@ -1,76 +1,89 @@ --- myst: html_meta: - "description": "Essential continuous integration practices" - "property=og:description": "Essential continuous integration practices" - "property=og:title": "Essential continuous integration practices" - "keywords": "Plone, continuous integration, best practices" + "description": "Working with continuous integration via Jenkins and GitHub workflows in Plone" + "property=og:description": "Working with continuous integration via Jenkins and GitHub workflows in Plone" + "property=og:title": "Continuous integration" + "keywords": "Plone, continuous integration, Jenkins, GitHub workflows" --- -# Continuous Integration +# Continuous integration -As a complex system build out of hundreds of small packages, Plone can be easily broken, inadvertently, with any change on any of its packages. +As a complex system built from hundreds of small packages, Plone can be easily and inadvertently broken from a change to any of its packages. +To help prevent breaking Plone, a mix of a {term}`continuous integration` (CI) systems of GitHub workflows and Jenkins thoroughly checks all changes. -For that a mix of a {term}`CI` system at [jenkins.plone.org](https://jenkins.plone.org) and GitHub Actions ensure that any change is thoroughly checked. +Do not use continuous integration as a replacement for running tests and other checks locally before pushing commits to a Plone repository. +See {ref}`test-and-code-quality-label` for an explanation, and {ref}`contributing-specific-contribution-policies-for-projects-label` for a project's specific contributing guidelines. -## Jenkins -Jenkins is the primary source of truth to know if the complete test suite of any Plone versions in development is passing or not. +## GitHub workflows + +Most Plone repositories use {term}`GitHub workflows` to run tests, check code quality, and perform other CI tasks on pushed commits to an open pull request. + +If a pull request is opened from a branch in the repository, then checks will automatically run. +Only members of certain Plone GitHub organization teams and users with write permission in the repository can do this. +Otherwise GitHub workflows do not run automatically, and require a member with write permission to run the checks. -Jenkins is configured to react on changes done in any of the hundreds of repositories that all together make Plone. +GitHub workflows should pass before running Jenkins checks and before merging an open pull request. -Whenever a change on any of those repositories happen, Jenkins starts a slew of testing jobs that ultimately answer the question of if those changes pass Plone's test suite. -### Triggering jobs (automatically) +## Jenkins + +[Jenkins](https://jenkins.plone.org) is the authoritative source to see whether the complete test suite passes for any Plone version under development. +Jenkins can be run on a change to any of Plone's hundreds of repositories that it monitors. -As running the Jenkins jobs is a bit expensive, in time, Jenkins does not run automatically on any new commit. -Rather, Jenkins waits for a special comment to be found in a pull request on a repository that is monitored by Jenkins. +### Run Jenkins + +Running the entire test suite on Jenkins takes at least 30 minutes, and consumes precious server resources. +For this reason, Jenkins is configured not to run automatically on each push to an open pull request. +Instead you should wait until you have completed pushing commits to an open pull request, and have seen that all GitHub workflows have passed. + +After all GitHub checks pass, and if Jenkins monitors the project, you can run Jenkins by adding a comment to the open pull request. ```text @jenkins-plone-org please run jobs ``` -Pasting the text above on a pull request, will trigger Jenkins to run all configured test suites related to the current pull request, **with the changes of the pull request itself**. +This will trigger Jenkins to run all configured test suites using the changes in the pull request. -#### buildout.coredev special case +You can also manually run Jenkins jobs by visiting our [Jenkins server](https://jenkins.plone.org/), logging in with your GitHub account, finding the right job, and clicking the Build now icon {guilabel}`Build now` button. -`buildout.coredev` is the special repository where our configuration and tooling to orchestrate Plone lies in. -Contrary to all the other repositories, whenever a commit is made on this repository, it automatically triggers Jenkins jobs to be run. +#### `buildout.coredev` special case -### Triggering jobs (manually) +`buildout.coredev` contains the configuration and tooling to orchestrate Plone. +Contrary to all the other repositories, whenever a push is made to this repository, it automatically triggers Jenkins to run its jobs. -Jenkins jobs can also be triggered manually by going to our Jenkins server, login in with your GitHub account, finding the right job, and triggering the `Run` button. ### Results -Once a jenkins job is finished, it will update its status icon on Jenkins UI itself, but also report back to GitHub, the result of the job. +Once a Jenkins job completes, it updates its status icon in the Jenkins UI, and reports the result of the job to the open pull request on GitHub. -For pull requests, this means a green check mark or a red cross will be displayed at the end of the pull request, on pull requests listings, even on the favicon itself. +In GitHub at the end of the pull request, a status indicator of either a green check mark {guilabel}`✅` or a red cross {guilabel}`❌` will be displayed for the job, followed by a {guilabel}`Details` link back to the Jenkins job build for that pull request. +The status indicator will also appear in the GitHub Octocat favicon in the web browser tab on the pull request, and on lists of pull requests. -This gives the expected feedback to the pull request author, or any reviewer interested in knowing how a given pull request fared in Jenkins. Thus allowing pull request reviewers or authors to decide if the pull request can already be merged. +You can use the results to decide whether to merge the pull request. -#### On failures -If the Jenkins jobs reports failures, the statuses of the pull request will provide a `Details` link back to Jenkins. +### Failure -That link leads back to the Jenkins job build for that pull request. +If the Jenkins job reports a failure, you can investigate its cause. +Click the {guilabel}`Details` link to show the stacktrace on Jenkins. -In that page, there is the list of test failures (if any) already listed. Clicking on them show the stacktrace that should help diagnose why there was an error on a given test. +In the side bar of the job build page in Jenkins, click the Console Output terminal icon {guilabel}` Console Output` link to show the full console output. +You can examine all the steps and debugging information that Jenkins generated while running the job. +This can be helpful whenever the errors were not in a single test, but rather a test set up or tear down or other problem. -On the side bar of the job build page in Jenkins there is also `Console Output` link. This leads to the **full job output**, note that is large, where it can be seen all the steps and debugging information that Jenkins generated running the job. -This can be helpful whenever the errors where not on a single test, but rather a general testing set up/tear down problem. +### Retry -### Retrying - -If there were errors on the Jenkins jobs, and corrections have been made on the code, triggering the jenkins jobs again is a matter of giving the special comment on the GitHub pull request again: +If there were errors on the Jenkins jobs, and you push additional commits to correct the errors, you can trigger the Jenkins jobs again by adding a comment to the open pull request in GitHub. ```text @jenkins-plone-org please run jobs ``` -Jenkins jobs can also be restarted within Jenkins UI itself. On the Jenkins job itself, and provided you are logged in, you can find a `Retry` link on the left toolbar. Clicking it will trigger a new Jenkins job with the same configuration as the one you are on. - +You can also restart Jenkins jobs in the Jenkins UI. +After logging in to Jenkins, and finding the appropriate job, you can click the Retry icon {guilabel}`Retry` link on the left toolbar to retry the failed job. Jenkins will update GitHub statuses accordingly. diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 4b7773c0b..4bab9b6dd 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -299,7 +299,7 @@ Plone has a continuous integration ({term}`CI`) setup and follows CI rules. When you push a change to a Plone package, there may be GitHub workflows that run automatically. The CI package [mr.roboto](https://github.com/plone/mr.roboto) will perform some checks and suggest that you run Jenkins after all other CI runs. -%% See {doc}`continuous-integration` for more information. +See {doc}`continuous-integration` for more information. ## Additional material @@ -308,7 +308,7 @@ The CI package [mr.roboto](https://github.com/plone/mr.roboto) will perform some :maxdepth: 1 documentation -%% continuous-integration +continuous-integration mrdeveloper plips plip-review From 5def3ac3df9aee28854be4aaafe69ad6901a5ec7 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 20 Aug 2024 17:16:11 -0700 Subject: [PATCH 406/810] Fix redirect --- docs/install/containers/images/backend.md | 2 +- docs/install/containers/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/install/containers/images/backend.md b/docs/install/containers/images/backend.md index a2c629fb8..013b5a05f 100644 --- a/docs/install/containers/images/backend.md +++ b/docs/install/containers/images/backend.md @@ -31,7 +31,7 @@ There are several ways to store data used by applications that run in Docker con We encourage users of the `Plone` images to familiarize themselves with the options available. -[The Docker documentation](https://docs.docker.com/guides/docker-concepts/running-containers/persisting-container-data) is a good starting point for understanding the different storage options and variations. +[The Docker documentation](https://docs.docker.com/get-started/docker-concepts/running-containers/persisting-container-data/) is a good starting point for understanding the different storage options and variations. ## Configuration Variables diff --git a/docs/install/containers/index.md b/docs/install/containers/index.md index f8bd11f77..7c5fa7a79 100644 --- a/docs/install/containers/index.md +++ b/docs/install/containers/index.md @@ -55,7 +55,7 @@ See its {ref}`install-packages-hardware-requirements-label`. ### Install Docker -Install [Docker Desktop](https://docs.docker.com/get-docker/) for your operating system. +Install [Docker Desktop](https://docs.docker.com/get-started/get-docker/) for your operating system. Docker Desktop includes all Docker tools. {term}`Docker Compose` is one of the Docker tools that will be used in much of this documentation. From 29d9684473436ef5cf5fb0397c1e88eaf05dd07f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 20 Aug 2024 17:41:57 -0700 Subject: [PATCH 407/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index fdcc8740d..16b61471d 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit fdcc8740d821d6c6c5a6669bd4a572d2784fd203 +Subproject commit 16b61471d33f84eb9b48f79bc66186bbcc2b01b1 From fc5c391c4f4c647e89280628eda5e9adc3c5955d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 20 Aug 2024 17:43:00 -0700 Subject: [PATCH 408/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index fdcc8740d..16b61471d 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit fdcc8740d821d6c6c5a6669bd4a572d2784fd203 +Subproject commit 16b61471d33f84eb9b48f79bc66186bbcc2b01b1 From ae6f90eccff55c29db84ccc7665b33bbf2a9d5b2 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 20 Aug 2024 18:16:45 -0700 Subject: [PATCH 409/810] Add pre-requisites and set up information --- docs/i18n-l10n/contributing-translations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index 3ff047c16..c4613fa4f 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -40,7 +40,7 @@ Optionally sign the [Plone Contributor Agreement](https://plone.org/foundation/c The process of translating Plone Classic UI is the following. -1. Go to https://github.com/collective/plone.app.locales and clone it into your computer. +1. Follow the instructions to set up Volto for development as described in {doc}`../volto/contributing/developing-core`. 2. Create a new branch to work on your translations. Name the branch with something identifiable. From 2a8c0f92b04fac5d1e718f205fd51f2765d944db Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 30 Aug 2024 01:39:38 -0700 Subject: [PATCH 410/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 16b61471d..e49fb93c0 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 16b61471d33f84eb9b48f79bc66186bbcc2b01b1 +Subproject commit e49fb93c04a0e4a6048013a1114ffbbf835376f8 From 693e1e744958754cd508e31a0263f8e6afc91ac4 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 30 Aug 2024 01:43:49 -0700 Subject: [PATCH 411/810] Update tip submodules/plone.restapi --- submodules/plone.restapi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 602ccc695..37d02e777 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 602ccc6955eb066a989b24bfc0ac85b72da7cdc6 +Subproject commit 37d02e7772b1b402ef74b8e55bc7ea4ad786d014 From af04e507ee9a99aafb20659b4f9e620e1aa80dde Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 30 Aug 2024 02:06:27 -0700 Subject: [PATCH 412/810] Fix redirects --- .../upgrading/version-specific-migration/upgrade-to-51.md | 2 +- docs/i18n-l10n/contributing-translations.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-51.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-51.md index 8a90da856..1570a5183 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-51.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-51.md @@ -432,7 +432,7 @@ Your folderish content types should either use the templates from `plone.app.con ### Rejected And Postponed PLIPs -For details about rejected or postponed PLIPs see the [github PLIP project](https://github.com/plone/Products.CMFPlone/projects/1) and the [Framework Team PLIP status sheet](https://docs.google.com/spreadsheets/d/15Cut73TS5l_x8djkxNre5k8fd7haGC5OOSGigtL2drQ/edit). +For details about rejected or postponed PLIPs see the [github PLIP project](https://github.com/orgs/plone/projects/47) and the [Framework Team PLIP status sheet](https://docs.google.com/spreadsheets/d/15Cut73TS5l_x8djkxNre5k8fd7haGC5OOSGigtL2drQ/edit). ## Known Issues diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index c4613fa4f..0109c31f9 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -111,7 +111,7 @@ See the Weblate documentation, [Translating using Weblate](https://docs.weblate. When you save a translation, then it is committed on a branch used only for translations in the respective GitHub repository. -[Compare recent commits to the branch `translations-plone` on the package `plone.app.locales`](https://github.com/collective/plone.app.locales/compare/master...translations-plone). +[See recent commits to the package `plone.app.locales`](https://github.com/collective/plone.app.locales/commits/master/). Maintainers will periodically create a pull request from the changes, and merge it. From 23bd8f016e39744205f4e8a7f382a05131fd75de Mon Sep 17 00:00:00 2001 From: Faakhir30 Date: Fri, 30 Aug 2024 14:19:30 +0500 Subject: [PATCH 413/810] Update translation command to make i18n --- docs/i18n-l10n/contributing-translations.md | 2 +- docs/i18n-l10n/resync-translations.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index c4613fa4f..eedc23845 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -75,7 +75,7 @@ The process of translating the Volto frontend is the following. - To update a translation, translate your language's `po` file found at `locales/{language_code}/LC_MESSAGES/volto.po`. - To create a new translation, create a new directory at `locales/{language_code}/LC_MESSAGES/`, copy the file `locales/volto.pot` to `locales/{language_code}/LC_MESSAGES/volto.po` (note to drop the trailing `t`), and start translating. -4. Run `yarn i18n` to convert your `po` files into `json`. +4. Run `make i18n` to convert your `po` files into `json`. Volto loads these `json` files to provide translated text strings in the interface. 5. Commit your changes, and create a pull request. diff --git a/docs/i18n-l10n/resync-translations.md b/docs/i18n-l10n/resync-translations.md index 727f28860..ead95c001 100644 --- a/docs/i18n-l10n/resync-translations.md +++ b/docs/i18n-l10n/resync-translations.md @@ -103,10 +103,10 @@ When the release manager requests to create a new `plone.app.locales` release, t ## Resync translations in Volto In Volto, the GitHub test setup warns a developer when their new contributions require regenerating the translation file. -This is done by running a yarn script as follows: +This is done by running a make command as follows: ```shell -yarn i18n +make i18n ``` This will update the PO files and will leave them ready to be translated by translators. @@ -116,9 +116,9 @@ This will update the PO files and will leave them ready to be translated by tran ## Create a release of Volto with the new translations -The Volto release process requires running the same yarn script as in the previous step. +The Volto release process requires running the same make command as in the previous step. It will convert the translations in PO files to the JSON files that Volto uses to render the user interface. ```shell -yarn i18n +make i18n ``` From d4abb61908e059b086c2edf70a924d0d5d9c9b4f Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Mon, 2 Sep 2024 17:18:31 +0200 Subject: [PATCH 414/810] Documentation for Discussion migration to 6.1. This is for the PLIP that I have just merged: https://github.com/plone/Products.CMFPlone/issues/3958 I changed the existing section title from "Discussion is disabled by default" to "Discussion is a core add-on". Discussion was always disabled by default, so this would not be a change. Note that the Discussion control panel is still missing from Volto: https://github.com/plone/volto/issues/29 But the upgrade to 6.1 does not change anything to this. --- .../upgrade-to-61.md | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md index 1b47d0379..6452b6c83 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md @@ -90,17 +90,29 @@ The goal of turning more of the current core packages into core add-ons is to ma (backend-upgrade-plone-v61-discussion-label)= -## Discussion is disabled by default + +## Discussion is a core add-on Discussion is a feature that allows your site visitors to comment on web pages for any content object. +The code behind this is in the `plone.app.discussion` package. +In Plone 6.0 and earlier, this was a dependency of `Products.CMFPlone`, making it available for installation in all Plone sites. +In Plone 6.1 it's a dependency of the `Plone` package. + Discussion is disabled by default in Plone 6.1 and later. To enable discussion, you need to perform the following tasks. -% Please add sufficient details for how to do this task, then delete this comment. -% Also consider that there might be different approaches between Classic UI and Volto that need to be mentioned. - 1. In your Python {file}`requirements.txt` or {file}`pyproject.toml` file, add the core add-on `plone.app.discussion` to your dependencies. 1. Run pip to install `plone.app.discussion`. 1. Restart the Plone backend to load `plone.app.discussion`. -1. Enable the {guilabel}`Discussion` add-on in the Plone control panel under {menuselection}`Site Setup --> General`. +1. Enable the {guilabel}`Discussion Support` add-on in the {guilabel}`Add-ons` control panel under {menuselection}`Site Setup --> General`. +1. If you use Plone Classic UI, you can then use the {guilabel}`Discussion` control panel to further configure this feature, for example for enabling comment moderation. 1. 🍻 + +If you have an existing Plone 5.2 or 6.0 site and you migrate to 6.1, then migration code handles the change: + +* If the `plone.app.discussion` Python package is in your setup, the migration does nothing: existing discussion configuration and comments remain unchanged. +* If the `plone.app.discussion` Python package is _not_ in your setup, and the site has no existing comments (discussions), then the migration code removes the Discussion configuration from your site. + Apparently you were _not_ using comments in your site, so the configuration is no longer needed. +* If the `plone.app.discussion` Python package is _not_ in your setup, but the site has existing comments (discussions), then the migration code stops with an error. + Apparently you _were_ using comments in your site. + Easiest solution here is to add the `plone.app.discussion` package to your dependencies. From 38841042e411127384c886c42a9358d5f58ee4fb Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 2 Sep 2024 15:42:34 -0700 Subject: [PATCH 415/810] Review from @stevepiercy Mostly style guide stuff, but I added a clause to the final bullet point that needs review from @mauritsvanrees: ``` Add the `plone.app.discussion` package to your dependencies, and run the migration again. ``` --- .../version-specific-migration/upgrade-to-61.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md index 6452b6c83..47655a1aa 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md @@ -105,14 +105,15 @@ To enable discussion, you need to perform the following tasks. 1. Run pip to install `plone.app.discussion`. 1. Restart the Plone backend to load `plone.app.discussion`. 1. Enable the {guilabel}`Discussion Support` add-on in the {guilabel}`Add-ons` control panel under {menuselection}`Site Setup --> General`. -1. If you use Plone Classic UI, you can then use the {guilabel}`Discussion` control panel to further configure this feature, for example for enabling comment moderation. +1. If you use Plone Classic UI, you can then use the {guilabel}`Discussion` control panel to further configure this feature, for example, to enable comment moderation. 1. 🍻 -If you have an existing Plone 5.2 or 6.0 site and you migrate to 6.1, then migration code handles the change: +If you have an existing Plone 5.2 or 6.0 site and you migrate to 6.1, then migration code handles the change as follows. -* If the `plone.app.discussion` Python package is in your setup, the migration does nothing: existing discussion configuration and comments remain unchanged. -* If the `plone.app.discussion` Python package is _not_ in your setup, and the site has no existing comments (discussions), then the migration code removes the Discussion configuration from your site. - Apparently you were _not_ using comments in your site, so the configuration is no longer needed. -* If the `plone.app.discussion` Python package is _not_ in your setup, but the site has existing comments (discussions), then the migration code stops with an error. - Apparently you _were_ using comments in your site. - Easiest solution here is to add the `plone.app.discussion` package to your dependencies. +- If the `plone.app.discussion` Python package is in your setup, the migration does nothing. + Existing discussion configuration and comments remain unchanged. +- If the `plone.app.discussion` Python package is _not_ in your setup, and the site has no existing comments (discussions), then the migration code removes the Discussion configuration from your site. + Apparently you were _not_ using comments in your site, so the configuration is no longer needed. +- If the `plone.app.discussion` Python package is _not_ in your setup, but the site has existing comments (discussions), then the migration code stops with an error. + Apparently you _were_ using comments in your site. + Add the `plone.app.discussion` package to your dependencies, and run the migration again. From aa80a9124ed3df605d3487dc74dfcaa86d5455b6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 5 Sep 2024 16:53:26 -0700 Subject: [PATCH 416/810] Bump PLONE_BACKEND_PATCH_VERSION to 6.0.13 --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 13b6e95bf..224c02171 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -349,7 +349,7 @@ def source_replace(app, docname, source): # Dict of replacements. source_replacements = { "{PLONE_BACKEND_MINOR_VERSION}": "6.0", - "{PLONE_BACKEND_PATCH_VERSION}": "6.0.12", + "{PLONE_BACKEND_PATCH_VERSION}": "6.0.13", "{NVM_VERSION}": "0.39.5", "{SUPPORTED_PYTHON_VERSIONS}": "3.8, 3.9, 3.10, 3.11, or 3.12", } From a40fc3d024d42cad96fc658e411482608357b6fd Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Fri, 6 Sep 2024 14:19:07 +0200 Subject: [PATCH 417/810] explain how to avoid errors when overriding translations --- docs/i18n-l10n/translating-text-strings.md | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/i18n-l10n/translating-text-strings.md b/docs/i18n-l10n/translating-text-strings.md index b8e523dcd..0a12a4722 100644 --- a/docs/i18n-l10n/translating-text-strings.md +++ b/docs/i18n-l10n/translating-text-strings.md @@ -437,6 +437,31 @@ environment-vars = zcml = my.package ``` +When doing so, you may need to add the following zcml stanza in your package's `configure.zcml` file: + +```xml + + + +``` + +This **must** go *after* the `registerTranslations` stanza, before any other registration you may have in your package. + +It should look like this: + +```xml + + + + + + + + +``` + + See the *Overriding Translations* section of Maurits van Rees's [blog entry on Plone i18n](https://maurits.vanrees.org/weblog/archive/2010/10/i18n-plone-4#overriding-translations). From 207f71fc5ae701de8b9d3c95071f4b7b077e7c21 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 6 Sep 2024 17:10:41 -0700 Subject: [PATCH 418/810] Apply suggestions from code review --- docs/i18n-l10n/translating-text-strings.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/i18n-l10n/translating-text-strings.md b/docs/i18n-l10n/translating-text-strings.md index 0a12a4722..22d307e88 100644 --- a/docs/i18n-l10n/translating-text-strings.md +++ b/docs/i18n-l10n/translating-text-strings.md @@ -437,17 +437,15 @@ environment-vars = zcml = my.package ``` -When doing so, you may need to add the following zcml stanza in your package's `configure.zcml` file: +When doing so, you may need to add the following ZCML stanza in your package's {file}`configure.zcml` file: ```xml - - ``` -This **must** go *after* the `registerTranslations` stanza, before any other registration you may have in your package. +This **must** go *after* the `registerTranslations` stanza, and before any other registration you might have in your package. -It should look like this: +The registration should look like the following example. ```xml Date: Fri, 13 Sep 2024 03:52:18 -0700 Subject: [PATCH 419/810] Fix link to Docker for Linux installation (#1704) * Fix link to Docker for Linux installation * Remove errant trailing slash --- docs/install/containers/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install/containers/index.md b/docs/install/containers/index.md index 7c5fa7a79..e6167c21f 100644 --- a/docs/install/containers/index.md +++ b/docs/install/containers/index.md @@ -45,7 +45,7 @@ Although there are many container engine tools for developing, managing, and run The system requirements include those required by Docker itself. -- [Linux](https://docs.docker.com/desktop/install/linux-install/) +- [Linux](https://docs.docker.com/desktop/install/linux/) - [macOS](https://docs.docker.com/desktop/install/mac-install/) - [Windows](https://docs.docker.com/desktop/install/windows-install/) From 4d9394c52208a440a983174aa320bd53237efd47 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 13 Sep 2024 16:02:12 -0700 Subject: [PATCH 420/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 37d02e777..057c59a04 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 37d02e7772b1b402ef74b8e55bc7ea4ad786d014 +Subproject commit 057c59a04d4cb2e5d51e83cdab41b7e921aaae88 diff --git a/submodules/volto b/submodules/volto index e49fb93c0..1e0107017 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit e49fb93c04a0e4a6048013a1114ffbbf835376f8 +Subproject commit 1e01070176d05fc5c36bd330a141d0acd61543d2 From 88c97a488ff57919b00b02a1250d99abd331ea78 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 13 Sep 2024 17:55:34 -0700 Subject: [PATCH 421/810] Remove obsolete and dead link (#1708) --- .../upgrading/version-specific-migration/upgrade-to-python3.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-python3.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-python3.md index d5554a191..02bcbd7d8 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-python3.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-python3.md @@ -14,9 +14,6 @@ myst: This chapter provides instructions and tips for porting Plone projects to Python 3. -```{seealso} -If you want to upgrade add-ons to Python 3, the list of all Plone packages that still need to be ported can be found on the GitHub project board [Python 3 porting state for Plone add-ons](https://github.com/orgs/collective/projects/1). -``` ## Principles From cbd090104118569911a8fec41fd059353cf1d4e9 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 17 Sep 2024 03:28:15 -0700 Subject: [PATCH 422/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 1e0107017..08aab5a37 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 1e01070176d05fc5c36bd330a141d0acd61543d2 +Subproject commit 08aab5a3781c9f892aef3f951706295ddf152d26 From 38e17ce735fd03bba5da307c7c2e0e0238e94542 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 18 Sep 2024 12:22:54 -0700 Subject: [PATCH 423/810] Include changes to http-examples to build docs preview --- submodules/plone.restapi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 057c59a04..875070473 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 057c59a04d4cb2e5d51e83cdab41b7e921aaae88 +Subproject commit 87507047392e07f33d2f0f365d03d50a70e0815a From b474dcbb539be31c623d0ec7998b563d12980bc7 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 21 Sep 2024 01:35:53 -0700 Subject: [PATCH 424/810] Update tip submodules/plone.restapi --- submodules/plone.restapi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 057c59a04..913f49b7e 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 057c59a04d4cb2e5d51e83cdab41b7e921aaae88 +Subproject commit 913f49b7e48f6e7dc3dbea5ea72428611d16e796 From f743b3a16e292b225c664a54a62af492079f2e3a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 21 Sep 2024 17:27:36 -0700 Subject: [PATCH 425/810] Update tip submodules/plone.restapi --- submodules/plone.restapi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 913f49b7e..682567a86 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 913f49b7e48f6e7dc3dbea5ea72428611d16e796 +Subproject commit 682567a86b9fc022fbad32e27906475c5410eee1 From 9ba13aa6c18e50610895bc9420520cf2bf772186 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 23 Sep 2024 02:21:53 -0700 Subject: [PATCH 426/810] Continuous integration consolidation (#1711) * Consolidate continuous integration documentation * Exclude plone.restapi installed stuff from docs --- docs/_inc/_continuous-integration.md | 7 +++++++ docs/conf.py | 6 ++++++ docs/contributing/core/continuous-integration.md | 6 ++++++ docs/contributing/core/index.md | 10 +++------- docs/contributing/index.md | 6 +++--- docs/glossary.md | 2 ++ 6 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 docs/_inc/_continuous-integration.md diff --git a/docs/_inc/_continuous-integration.md b/docs/_inc/_continuous-integration.md new file mode 100644 index 000000000..4b2964224 --- /dev/null +++ b/docs/_inc/_continuous-integration.md @@ -0,0 +1,7 @@ +Plone project repositories use {term}`continuous integration` (CI) to run tests, ensure code quality, or provide previews for every contribution. +Plone uses GitHub workflows, Jenkins, Cypress, Read the Docs, and other services for CI. +All of a project's CI jobs must pass before a contribution may be accepted. + +```{seealso} +{doc}`/contributing/core/continuous-integration` +``` diff --git a/docs/conf.py b/docs/conf.py index 224c02171..ebfff44d4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -125,15 +125,21 @@ "**/CONTRIBUTORS.rst", "**/LICENSE.rst", "**/README.rst", + "**/eggs", + "_inc/.*", "plone.restapi/.*", "plone.restapi/bin", + "plone.restapi/develop-eggs", "plone.restapi/docs/source/glossary.md", # There can be only one Glossary. + "plone.restapi/eggs", "plone.restapi/ideas", "plone.restapi/include", "plone.restapi/lib", "plone.restapi/news", + "plone.restapi/parts", "plone.restapi/performance", "plone.restapi/src", + "plone.restapi/var", "volto/contributing/branch-policy.md", "volto/contributing/install-docker.md", "volto/contributing/install-git.md", diff --git a/docs/contributing/core/continuous-integration.md b/docs/contributing/core/continuous-integration.md index 70f754865..5f1d51c48 100644 --- a/docs/contributing/core/continuous-integration.md +++ b/docs/contributing/core/continuous-integration.md @@ -27,6 +27,12 @@ Otherwise GitHub workflows do not run automatically, and require a member with w GitHub workflows should pass before running Jenkins checks and before merging an open pull request. +## `mr-roboto` + +[`mr-roboto`](https://github.com/plone/mr.roboto) enforces the requirement of a signed Plone Contributor Agreement from a new contributor, and being assigned to a Plone team on GitHub. +It also suggests to run Jenkins for many Plone packages. + + ## Jenkins [Jenkins](https://jenkins.plone.org) is the authoritative source to see whether the complete test suite passes for any Plone version under development. diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 4bab9b6dd..888d16f16 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -292,14 +292,10 @@ This enables automatic closing of the related issue when the pull request is mer This also creates a hyperlink to the original issue for easy reference. -## Jenkins and mr.roboto +## Continuous integration -Plone has a continuous integration ({term}`CI`) setup and follows CI rules. - -When you push a change to a Plone package, there may be GitHub workflows that run automatically. -The CI package [mr.roboto](https://github.com/plone/mr.roboto) will perform some checks and suggest that you run Jenkins after all other CI runs. - -See {doc}`continuous-integration` for more information. +```{include} /_inc/_continuous-integration.md +``` ## Additional material diff --git a/docs/contributing/index.md b/docs/contributing/index.md index 5214b687e..0b2bb8d50 100644 --- a/docs/contributing/index.md +++ b/docs/contributing/index.md @@ -60,13 +60,13 @@ All contributors to the Plone Documentation follow the Code of Conduct. First-time contributors should read and follow our guide {doc}`first-time`. + (contributing-continuous-integration-label)= ## Continuous integration -Plone project repositories use continuous integration (CI) to run tests, ensure code quality, or provide previews for every contribution. -Plone uses GitHub Actions, Jenkins, Cypress, Netlify, and other services for CI. -All of a project's CI jobs must pass before a contribution may be accepted. +```{include} /_inc/_continuous-integration.md +``` (contributing-change-log-label)= diff --git a/docs/glossary.md b/docs/glossary.md index c2e0cdcda..0c487f5eb 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -756,6 +756,8 @@ Load balancer CI continuous integration Continuous integration (CI) is the practice of integrating all your code changes into the main branch of a shared source code repository early and often, automatically testing each change when you commit or merge them, and automatically kicking off a build. + + Read about Plone's {doc}`/contributing/core/continuous-integration`. CD continuous deployment From 1f35844c885651b2199456713861e500d53096ca Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 27 Sep 2024 05:23:11 -0700 Subject: [PATCH 427/810] Fix redirects (#1717) --- docs/contributing/documentation/index.md | 2 +- docs/contributing/first-time.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/contributing/documentation/index.md b/docs/contributing/documentation/index.md index 851ea7de3..e63c36592 100644 --- a/docs/contributing/documentation/index.md +++ b/docs/contributing/documentation/index.md @@ -111,7 +111,7 @@ After your Plone Contributor Agreement has been approved, and you have been adde 1. Clarify the scope of work that needs to be done. Check for previous work, assignment to another developer, or whether the requirements have changed. -1. [Assign yourself to the issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/assigning-issues-and-pull-requests-to-other-github-users). +1. [Assign yourself to the issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/assigning-issues-and-pull-requests-to-other-github-users). This signals to other developers that you are working on the issue. From here, you can either make {ref}`contributing-quick-edits-label` or {ref}`contributing-large-edits-label`. diff --git a/docs/contributing/first-time.md b/docs/contributing/first-time.md index 25ec6f892..5e4121784 100644 --- a/docs/contributing/first-time.md +++ b/docs/contributing/first-time.md @@ -260,7 +260,7 @@ Once you have completed, tested, and linted your code, and created a {ref}`contr This also creates a hyperlink to the original issue for easy reference. ```{seealso} - [Linking a pull request to an issue using a keyword](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) + [Linking a pull request to an issue using a keyword](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) ``` 1. **Request a review.** From ba64b36e64d8953bfa0b002a1420b4245be32b1a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 27 Sep 2024 05:24:53 -0700 Subject: [PATCH 428/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 08aab5a37..d81a0d339 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 08aab5a3781c9f892aef3f951706295ddf152d26 +Subproject commit d81a0d339e25cf3a4efa98429edd66b3cf509b9b From eda7efbb1fbf1801e9b86c0af478a2f79545b10e Mon Sep 17 00:00:00 2001 From: David Glick Date: Fri, 27 Sep 2024 05:34:49 -0700 Subject: [PATCH 429/810] Disable VSCode's format-on-save feature for markdown (#1713) Co-authored-by: Steve Piercy --- .vscode/settings.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..a836b007c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "[markdown]": { + "editor.formatOnSave": false + } +} From de0f8e9e5eb2b987f4c7b39b8bd4b15e6cc6c67d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 27 Sep 2024 06:08:03 -0700 Subject: [PATCH 430/810] Add html_meta stuff for annotations.md --- docs/backend/annotations.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/backend/annotations.md b/docs/backend/annotations.md index 0f2ff39f2..7371002fd 100644 --- a/docs/backend/annotations.md +++ b/docs/backend/annotations.md @@ -1,10 +1,10 @@ --- myst: html_meta: - "description": "" - "property=og:description": "" - "property=og:title": "" - "keywords": "" + "description": "Annotations store arbitrary values on Python objects—such as a Plone site or HTTP request—for storage and caching purposes." + "property=og:description": "Annotations store arbitrary values on Python objects—such as a Plone site or HTTP request—for storage and caching purposes." + "property=og:title": "Annotations" + "keywords": "Annotations, plone.memoize, cache, portal, content object" --- (backend-annotations-label)= From aa4496688f479af397345c66a555a6bbcc92d947 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 29 Sep 2024 00:38:39 -0700 Subject: [PATCH 431/810] Document how to resolve issues with `mr-roboto` --- docs/contributing/core/continuous-integration.md | 8 ++++++++ docs/contributing/index.md | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/contributing/core/continuous-integration.md b/docs/contributing/core/continuous-integration.md index 5f1d51c48..43723d199 100644 --- a/docs/contributing/core/continuous-integration.md +++ b/docs/contributing/core/continuous-integration.md @@ -32,6 +32,14 @@ GitHub workflows should pass before running Jenkins checks and before merging an [`mr-roboto`](https://github.com/plone/mr.roboto) enforces the requirement of a signed Plone Contributor Agreement from a new contributor, and being assigned to a Plone team on GitHub. It also suggests to run Jenkins for many Plone packages. +When you push a commit to a Plone repository on GitHub, the email address in your commit must match an email address in your GitHub account. +If it does not match, then `mr.roboto` will notify you that there is a problem that prevents your pull request from being merged. +You must resolve the issue. + +To change the email address in your commits, see [Setting your commit email address](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/setting-your-commit-email-address]. + +To add an email address to your GitHub account, see [Adding an email address to your GitHub account](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/adding-an-email-address-to-your-github-account). + ## Jenkins diff --git a/docs/contributing/index.md b/docs/contributing/index.md index 0b2bb8d50..a84af9a7c 100644 --- a/docs/contributing/index.md +++ b/docs/contributing/index.md @@ -31,7 +31,7 @@ You grant permission by signing and returning the Plone Contributor Agreement. A volunteer member of the Plone Foundation will review your signed agreement. -If accepted, your GitHub account will be added to a team in the Plone GitHub organization with appropriate access, and you will simultaneously receive an email notification from GitHub. +If accepted, your GitHub account will be added to a team in the Plone GitHub organization with appropriate access, and you will simultaneously receive an email from GitHub for you to accept the invitation to join the team. Allow up to one week for processing. Contact the Plone Foundation by its email address for further information, including the status of your request. From 5a5fb148e1291f7180086627c50fca2fba70682f Mon Sep 17 00:00:00 2001 From: David Glick Date: Sun, 29 Sep 2024 17:18:32 -0700 Subject: [PATCH 432/810] Add "create project" docs for cookieplone (#1714) * Add "create project" docs for cookieplone * Add overlooked comma * Rename file * Rename file * Remove "the" from Classic UI. MyST syntax standard. Clarify introduction * Apply suggestions from code review * Overhaul the Install index. - promote stable releases over development pre-releases - Move demos to end - Replace Sphinx Design grid and cards a plain old definition list. * Simplify introductions for create-project* * Update meta information * Current version of Sphinx does not support replacements in includes, so use this temporary workaround and add TODO. * Hyphenate pre-requisite and tidy * Update meta information * Use narrow terminal to avoid horizontal scrolling of console. * Add next steps to view the site. Much excite! * Update meta information and correct Volto version * Correct introduction * Add terms Cookieplone and cookieplone-templates to Glossary. * Use include for Python prerequisite * Update docs/glossary.md Remove documentation as a Cookieplone option Co-authored-by: David Glick * Update docs/install/create-project-cookieplone.md Co-authored-by: David Glick * Include corepack enable as an enumerated step, and use shell for syntax * Avoid horizontal scrolling and anonymize path to project * Finalize tidy and update screenshots to 2024 * Link to correct repo. See https://github.com/plone/cookieplone/pull/41 * Add plone/generator-volto deprecation to Glossary * Cannot use `@` at the start of a term in the Glossary * Nope, `@` is fine, there was whitespace that broke the glossary. * Add note about installing Pillow requirements. See https://github.com/plone/documentation/issues/1712 * Update docs/glossary.md Co-authored-by: David Glick --------- Co-authored-by: Steve Piercy --- docs/_inc/_hardware-requirements.md | 19 ++ docs/_inc/_install-pillow.md | 24 ++ docs/_inc/_install-python.md | 6 + .../_static/plone-classic-ui-landing-page.png | Bin 72838 -> 128653 bytes docs/_static/plone-classic-ui-site-page.png | Bin 0 -> 91618 bytes docs/_static/plone-home-page.png | Bin 42263 -> 123366 bytes docs/_static/plone-login-page.png | Bin 59781 -> 59439 bytes docs/glossary.md | 19 ++ docs/install/create-project-classic-ui.md | 229 +++++++++++++ docs/install/create-project-cookieplone.md | 320 ++++++++++++++++++ docs/install/create-project.md | 75 +--- docs/install/index.md | 49 ++- 12 files changed, 656 insertions(+), 85 deletions(-) create mode 100644 docs/_inc/_hardware-requirements.md create mode 100644 docs/_inc/_install-pillow.md create mode 100644 docs/_inc/_install-python.md create mode 100644 docs/_static/plone-classic-ui-site-page.png create mode 100644 docs/install/create-project-classic-ui.md create mode 100644 docs/install/create-project-cookieplone.md diff --git a/docs/_inc/_hardware-requirements.md b/docs/_inc/_hardware-requirements.md new file mode 100644 index 000000000..76bd3c02f --- /dev/null +++ b/docs/_inc/_hardware-requirements.md @@ -0,0 +1,19 @@ +The hardware requirements below give a rough estimate of the minimum hardware setup needed for a Plone server. + +A single Plone installation is able to run many Plone sites. + +- Installation of the Plone backend and Classic UI frontend requires a minimum of 256 MB of RAM and 2GB of disk swap space. +- Installation of the Volto frontend requires a minimum of 2GB of RAM. +- After installation, running Plone requires a minimum of 256 MB RAM and 512 MB of disk swap space per Plone site. + 2 GB or more RAM per Plone site is recommended. +- Minimum 512 MB hard disk space is required. + 40 GB or more hard disk space is recommended. + + +````{warning} +{term}`Add-on` products and caching solutions may also increase RAM and disk swap space requirements. +To avoid RAM and disk swap limitations, we recommend either temporarily resizing your remote machine to accommodate the build, or build your images locally and upload them to an image store, such as [Docker Hub](https://hub.docker.com/) or [GitHub Packages](https://github.com/features/packages). +```{seealso} +[How much RAM is required to build a Volto front end?](https://community.plone.org/t/how-much-ram-is-required-to-build-a-volto-front-end/17949) and [Dealing with heap exhaustion while building Volto 17 on limited-RAM host](https://community.plone.org/t/dealing-with-heap-exhaustion-while-building-volto-17-on-limited-ram-host/18078). +``` +```` diff --git a/docs/_inc/_install-pillow.md b/docs/_inc/_install-pillow.md new file mode 100644 index 000000000..08aa5a3f1 --- /dev/null +++ b/docs/_inc/_install-pillow.md @@ -0,0 +1,24 @@ +``````{note} +After generating a project, then running `make install`, if you see an error message `ERROR: Failed building wheel for Pillow`, then you need to install Pillow's dependencies. + +`````{tab-set} + +````{tab-item} macOS +```shell +brew install zlib libjpeg +``` +```` + +````{tab-item} Linux +```shell +apt-get zlib libjpeg +``` +```` +````` + +You will then need to run `make install` again. + +```{seealso} +See also the Pillow documentation [External Libraries](https://pillow.readthedocs.io/en/latest/installation/building-from-source.html#external-libraries) for additional libraries that you might need. +``` +`````` diff --git a/docs/_inc/_install-python.md b/docs/_inc/_install-python.md new file mode 100644 index 000000000..4f0add878 --- /dev/null +++ b/docs/_inc/_install-python.md @@ -0,0 +1,6 @@ +Installing Python is beyond the scope of this documentation. +However, it is recommended to use a Python version manager, {term}`pyenv`, that allows you to install multiple versions of Python on your development environment without destroying your system's Python. +% TODO: uncomment this line after upgrading to plone-sphinx-theme and latest Sphinx which supports replacements inside includes. +% Plone requires Python version {SUPPORTED_PYTHON_VERSIONS}. + +Plone requires Python version 3.8, 3.9, 3.10, 3.11, or 3.12. diff --git a/docs/_static/plone-classic-ui-landing-page.png b/docs/_static/plone-classic-ui-landing-page.png index 018b0af215601e649ba90d2d1ca4922d5f13df8a..a4f101987a7ad22890d1c89f9fa6d4dcdf58b75f 100644 GIT binary patch literal 128653 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
W57}vt0JWH(nR-iRWa!% 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 diff --git a/docs/_static/plone-classic-ui-site-page.png b/docs/_static/plone-classic-ui-site-page.png new file mode 100644 index 0000000000000000000000000000000000000000..7c27b5ad9ec2481c264bcd2a6c6e168ffb452349 GIT binary patch literal 91618 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 Id@%6)U%g1TZU6uP literal 0 HcmV?d00001 diff --git a/docs/_static/plone-home-page.png b/docs/_static/plone-home-page.png index c670a93602aff8be848458460478c5dea0da559f..b2321e0eaf76b0bfe72d03a81725099c8e195af6 100644 GIT binary patch literal 123366 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

tLmaIhuyA{(H0;1>y&`$I2y<$!3n)rw56 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 Mj-h6Wy3Nb~0OfV6sQ>@~ diff --git a/docs/_static/plone-login-page.png b/docs/_static/plone-login-page.png index 25a1d0a31f2038f37f50e7d2fc511ab893951354..8a2f90e723aedc9eeda8b2167a99aa0bd70ad11f 100644 GIT binary patch literal 59439 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 GFaHPb07z*7 literal 59781 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 diff --git a/docs/glossary.md b/docs/glossary.md index 0c487f5eb..05eae946a 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -28,6 +28,25 @@ Cookiecutter A command-line utility that creates projects from cookiecutters (project templates), for example, creating a Python package project from a Python package project template. [See Cookiecutter's documentation](https://cookiecutter.readthedocs.io/en/stable/). +Cookieplone + ```{versionadded} Volto 18.0.0-alpha.43 + ``` + + [Cookieplone](https://github.com/plone/cookieplone) is the method to create a Plone project. + You can use Cookieplone to build a backend add-on, a new Volto add-on, or a full project with both backend and frontend. + Cookieplone simplifies the process using robust Cookiecutter templates from {term}`cookieplone-templates`. + +cookieplone-templates + [`cookieplone-templates`](https://github.com/plone/cookieplone-templates) is a collection of templates used by {term}`Cookieplone`. + +@plone/generator-volto +plone/generator-volto + ```{deprecated} Volto 18.0.0-alpha.43 + ``` + + [@plone/generator-volto](https://www.npmjs.com/package/@plone/generator-volto) is deprecated in favor of {term}`Cookieplone` since Volto 18.0.0-alpha.43. + See {ref}`upgrade-18-cookieplone-label`. + cookiecutter-plone-starter [cookiecutter-plone-starter](https://github.com/collective/cookiecutter-plone-starter/) is a framework for jumpstarting Plone 6 projects quickly. diff --git a/docs/install/create-project-classic-ui.md b/docs/install/create-project-classic-ui.md new file mode 100644 index 000000000..c04189f92 --- /dev/null +++ b/docs/install/create-project-classic-ui.md @@ -0,0 +1,229 @@ +--- +myst: + html_meta: + "description": "Create a Plone project with Classic UI (stable release)" + "property=og:description": "Create a Plone project with Classic UI (stable release)" + "property=og:title": "Create a Plone project with Classic UI (stable release)" + "keywords": "Plone, Plone 6, Classic UI, create, project, install, cookiecutter, Cookieplone" +--- + + +(create-a-project-classic-ui-label)= + +# Create a project with Classic UI (stable release) + +This chapter describes how you can create a web application using the current **stable release** version of Plone with **Classic UI** for the frontend, while having full control over its development and deployment. + +```{seealso} +For other installation options, see {doc}`/install/index`. +``` + + +## System requirements + +Plone 6 has both hardware requirements and software pre-requisites. + + +### Hardware requirements + +```{include} /_inc/_hardware-requirements.md +``` + +### Pre-requisites for installation + +```{include} ../volto/contributing/install-operating-system.md +``` + +- Python {SUPPORTED_PYTHON_VERSIONS} +- {term}`pipx` +- {term}`GNU make` +- {term}`Git` + + +#### Python + +```{include} /_inc/_install-python.md +``` + + +#### pipx + +Install {term}`pipx`. + +```shell +pip install pipx +``` + + +#### Make + +```{include} ../volto/contributing/install-make.md +``` + + +#### Git + +```{include} ../volto/contributing/install-git.md +``` + + +## Generate the project + +After satisfying the pre-requisites, generate the project. + +```shell +pipx run cookieplone backend_addon +``` + +You will be presented with a series of prompts. +You can accept the default values in square brackets (`[default-option]`) by hitting the {kbd}`Enter` key, or enter your preferred values. +For ease of documentation, we will use the default values. + +```{tip} +See the cookiecutter's README for how to [Use options to avoid prompts](https://github.com/collective/cookiecutter-plone-starter/?tab=readme-ov-file#use-options-to-avoid-prompts). +``` + +```{important} +For {guilabel}`Project Slug`, you must not use any of the Plone core package names listed in [`constraints.txt`](https://dist.plone.org/release/6.0-latest/constraints.txt). +Note that pip normalizes these names, so `plone.volto` and `plone-volto` are the same package. +``` + +```console +% pipx run cookieplone backend_addon +╭─────────────────────────────────── cookieplone ────────────────────────────────────╮ +│ │ +│ .xxxxxxxxxxxxxx. │ +│ ;xxxxxxxxxxxxxxxxxxxxxx; │ +│ ;xxxxxxxxxxxxxxxxxxxxxxxxxxxx; │ +│ xxxxxxxxxx xxxxxxxxxx │ +│ xxxxxxxx. .xxxxxxxx │ +│ xxxxxxx xxxxxxx: xxxxxxx │ +│ :xxxxxx xxxxxxxxxx xxxxxx: │ +│ :xxxxx+ xxxxxxxxxxx +xxxxx: │ +│ .xxxxx. :xxxxxxxxxx .xxxxx. │ +│ xxxxx+ ;xxxxxxxx +xxxxx │ +│ xxxxx +xx. xxxxx. │ +│ xxxxx: .xxxxxxxx :xxxxx │ +│ xxxxx .xxxxxxxxxx xxxxx │ +│ xxxxx xxxxxxxxxxx xxxxx │ +│ xxxxx .xxxxxxxxxx xxxxx │ +│ xxxxx: .xxxxxxxx :xxxxx │ +│ .xxxxx ;xx. ... xxxxx. │ +│ xxxxx+ :xxxxxxxx +xxxxx │ +│ .xxxxx. :xxxxxxxxxx .xxxxx. │ +│ :xxxxx+ xxxxxxxxxxx ;xxxxx: │ +│ :xxxxxx xxxxxxxxxx xxxxxx: │ +│ xxxxxxx xxxxxxx; xxxxxxx │ +│ xxxxxxxx. .xxxxxxxx │ +│ xxxxxxxxxx xxxxxxxxxx │ +│ ;xxxxxxxxxxxxxxxxxxxxxxxxxxxx+ │ +│ ;xxxxxxxxxxxxxxxxxxxxxx; │ +│ .xxxxxxxxxxxxxx. │ +│ │ +╰────────────────────────────────────────────────────────────────────────────────────╯ +╭─────────────────────────────────── Plone Addon ────────────────────────────────────╮ +│ Creating a new Plone Addon │ +╰────────────────────────────────────────────────────────────────────────────────────╯ + [1/7] Addon Title (Addon): + [2/7] A short description of your addon (A new addon for Plone): + [3/7] Author (Plone Community): + [4/7] Author E-mail (collective@plone.org): + [5/7] GitHub Username or Organization (collective): + [6/7] Python package name (collective.addon): + [7/7] Support headless Plone? + 1 - Yes + 2 - No + Choose from [1/2] (1): + -> Initialize Git repository +╭───────────────────────────── New addon was generated ──────────────────────────────╮ +│ │ +│ Addon │ +│ │ +│ Now, enter the repository run the code formatter with: │ +│ │ +│ make format │ +│ │ +│ start coding, and push to your organization. │ +│ │ +│ Sorry for the convenience, │ +│ The Plone Community. │ +│ │ +│ https://plone.org/ │ +╰────────────────────────────────────────────────────────────────────────────────────╯ +``` + + +## Install the project + +Change to your project directory. + +```shell +cd collective.addon +``` + +To install the project's dependencies, use the following command. + +```shell +make install +``` + +This will take a few minutes. +☕️ + +When the process completes successfully, it will exit with no message. + +```{include} /_inc/_install-pillow.md +``` + + +## Start Plone + +To start Plone, issue the following command. + +```shell +make start +``` + +The Plone backend server starts up and emits messages to the console. + +```console +2024-09-25 16:47:15,699 INFO [chameleon.config:39][MainThread] directory cache: //instance/var/cache. +2024-09-25 16:47:16,387 WARNING [ZODB.FileStorage:412][MainThread] Ignoring index for //instance/var/filestorage/Data.fs +2024-09-25 16:47:16,508 INFO [plone.restapi.patches:16][MainThread] PATCH: Disabled ZPublisher.HTTPRequest.ZopeFieldStorage.VALUE_LIMIT. This enables file uploads larger than 1MB. +2024-09-25 16:47:17,018 INFO [plone.volto:23][MainThread] Aliasing collective.folderish classes to plone.volto classes. +2024-09-25 16:47:17,760 INFO [Zope:42][MainThread] Ready to handle requests +Starting server in PID 20912. +2024-09-25 16:47:17,772 INFO [waitress:486][MainThread] Serving on http://[::1]:8080 +2024-09-25 16:47:17,772 INFO [waitress:486][MainThread] Serving on http://127.0.0.1:8080 +``` + +You can stop the site with {kbd}`ctrl-c`. + + +## Create Classic UI Plone site + +While the Plone backend server is running, open a browser and visit the following URL. + +http://localhost:8080 + +```{image} /_static/plone-classic-ui-landing-page.png +:class: figure +:alt: Plone Classic UI landing page +``` + +Click the button {guilabel}`Create Classic UI Plone site` to do exactly that. + +Use the username and password of `admin` to authenticate. +You will be redirected to the Create a Plone site page. + +```{image} /_static/plone-classic-ui-site-page.png +:class: figure +:alt: Plone Classic UI site page +``` + +Enter values for {guilabel}`Path identifier`, {guilabel}`Title`, {guilabel}`Language`, and {guilabel}`Default timezone`. +The default values are usually good. + +Click the button {guilabel}`Create Plone site`. + +You will be redirected to the Plone site you just created. diff --git a/docs/install/create-project-cookieplone.md b/docs/install/create-project-cookieplone.md new file mode 100644 index 000000000..2fcf7da48 --- /dev/null +++ b/docs/install/create-project-cookieplone.md @@ -0,0 +1,320 @@ +--- +myst: + html_meta: + "description": "Create a Plone project with the Volto frontend (development or pre-release)" + "property=og:description": "Create a Plone project with the Volto frontend (development or pre-release)" + "property=og:title": "Create a Plone project with the Volto frontend (development or pre-release)" + "keywords": "Plone, Plone 6, Volto, create, project, install, Cookieplone" +--- + + +(create-project-cookieplone-label)= + +# Create a project with Volto (development or pre-release) + +This chapter describes how you can create a web application using the latest **development release** version of Plone with **Volto 18 or later** for the frontend, while having full control over its development and deployment. + +```{seealso} +For other installation options, see {doc}`/install/index`. +``` + +```{versionadded} Volto 18.0.0-alpha.43 +{term}`Cookieplone` is now the method to create a Plone project with unstable versions of Volto, version 18.0.0-alpha.43 and above. +``` + + +## System requirements + +Plone 6 has both hardware requirements and software pre-requisites. + + +### Hardware requirements + +```{include} /_inc/_hardware-requirements.md +``` + +### Pre-requisites for installation + +```{include} ../volto/contributing/install-operating-system.md +``` + +- Python {SUPPORTED_PYTHON_VERSIONS} +- {term}`pipx` +- {term}`nvm` +- {term}`Node.js` LTS 20.x +- {term}`GNU make` +- {term}`Git` + + +#### Python + +```{include} /_inc/_install-python.md +``` + + +#### pipx + +Install {term}`pipx`. + +```shell +pip install pipx +``` + + +#### nvm + +```{include} ../volto/contributing/install-nvm.md +``` + + +#### Node.js + +```{include} ../volto/contributing/install-nodejs.md +``` + +3. Enable {term}`corepack` so that Node.js will install {term}`pnpm` as a package manager. + + ```shell + corepack enable + ``` + + +#### Make + +```{include} ../volto/contributing/install-make.md +``` + + +#### Git + +```{include} ../volto/contributing/install-git.md +``` + + +## Generate the project + +After satisfying the pre-requisites and having activated an LTS version of Node, +generate the project. + +```shell +pipx run cookieplone project +``` + +You will be presented with a series of prompts. +You can accept the default values in square brackets (`[default-option]`) by hitting the {kbd}`Enter` key, or enter your preferred values. +For ease of documentation, we will use the default values. + +```{tip} +See the cookiecutter's README for how to [Use options to avoid prompts](https://github.com/collective/cookieplone/?tab=readme-ov-file#use-options-to-avoid-prompts). +``` + +```{important} +For {guilabel}`Project Slug`, you must not use any of the Plone core package names listed in [`constraints.txt`](https://dist.plone.org/release/6.0-latest/constraints.txt). +Note that pip normalizes these names, so `plone.volto` and `plone-volto` are the same package. +``` + +```console +% pipx run cookieplone project +╭──────────────────────────────── cookieplone ────────────────────────────────╮ +│ │ +│ .xxxxxxxxxxxxxx. │ +│ ;xxxxxxxxxxxxxxxxxxxxxx; │ +│ ;xxxxxxxxxxxxxxxxxxxxxxxxxxxx; │ +│ xxxxxxxxxx xxxxxxxxxx │ +│ xxxxxxxx. .xxxxxxxx │ +│ xxxxxxx xxxxxxx: xxxxxxx │ +│ :xxxxxx xxxxxxxxxx xxxxxx: │ +│ :xxxxx+ xxxxxxxxxxx +xxxxx: │ +│ .xxxxx. :xxxxxxxxxx .xxxxx. │ +│ xxxxx+ ;xxxxxxxx +xxxxx │ +│ xxxxx +xx. xxxxx. │ +│ xxxxx: .xxxxxxxx :xxxxx │ +│ xxxxx .xxxxxxxxxx xxxxx │ +│ xxxxx xxxxxxxxxxx xxxxx │ +│ xxxxx .xxxxxxxxxx xxxxx │ +│ xxxxx: .xxxxxxxx :xxxxx │ +│ .xxxxx ;xx. ... xxxxx. │ +│ xxxxx+ :xxxxxxxx +xxxxx │ +│ .xxxxx. :xxxxxxxxxx .xxxxx. │ +│ :xxxxx+ xxxxxxxxxxx ;xxxxx: │ +│ :xxxxxx xxxxxxxxxx xxxxxx: │ +│ xxxxxxx xxxxxxx; xxxxxxx │ +│ xxxxxxxx. .xxxxxxxx │ +│ xxxxxxxxxx xxxxxxxxxx │ +│ ;xxxxxxxxxxxxxxxxxxxxxxxxxxxx+ │ +│ ;xxxxxxxxxxxxxxxxxxxxxx; │ +│ .xxxxxxxxxxxxxx. │ +│ │ +╰─────────────────────────────────────────────────────────────────────────────╯ +You've downloaded /Users/stevepiercy/.cookiecutters/cookieplone-templates +before. Is it okay to delete and re-download it? [y/n] (y): +╭─────────────────────────────── Plone Project ───────────────────────────────╮ +│ Creating a new Plone Project │ +╰─────────────────────────────────────────────────────────────────────────────╯ + [1/17] Project Title (Project Title): + [2/17] Project Description (A new project using Plone 6.): + [3/17] Project Slug (Used for repository id) (project-title): + [4/17] Project URL (without protocol) (project-title.example.com): + [5/17] Author (Plone Foundation): + [6/17] Author E-mail (collective@plone.org): + [7/17] Should we use prerelease versions? (No): + [8/17] Plone Version (6.0.13): + [9/17] Volto Version (18.0.0-alpha.43): + [10/17] Python Package Name (project.title): + [11/17] Volto Addon Name (volto-project-title): + [12/17] Language + 1 - English + 2 - Deutsch + 3 - Español + 4 - Português (Brasil) + 5 - Nederlands + 6 - Suomi + Choose from [1/2/3/4/5/6] (1): + [13/17] GitHub or GitLab Username or Organization (collective): + [14/17] Container Registry + 1 - GitHub Container Registry + 2 - Docker Hub + 3 - GitLab + Choose from [1/2/3] (1): + [15/17] Should we setup a caching server? + 1 - Yes + 2 - No + Choose from [1/2] (1): + [16/17] Add Ansible playbooks? + 1 - Yes + 2 - No + Choose from [1/2] (1): + [17/17] Add GitHub Action to Deploy this project? + 1 - Yes + 2 - No + Choose from [1/2] (1): +╭───────────────────────── Project Title generation ──────────────────────────╮ +│ │ +│ Summary: │ +│ │ +│ - Plone version: 6.0.13 │ +│ - Volto version: 18.0.0-alpha.43 │ +│ - Output folder: │ +│ /project-title │ +│ │ +│ │ +╰─────────────────────────────────────────────────────────────────────────────╯ + -> Initialize Git repository + -> Setup Backend + -> Setup Frontend + -> Setup Cache + -> Setup Project Settings +╭───────────────────────── New project was generated ─────────────────────────╮ +│ │ +│ Project Title │ +│ │ +│ Now, code it, create a git repository, push to your organization. │ +│ │ +│ Sorry for the convenience, │ +│ The Plone Community. │ +│ │ +│ https://plone.org/ │ +╰─────────────────────────────────────────────────────────────────────────────╯ +``` + +## Install the project + +To work on your project, you need to install both the frontend and backend. + +Change your current working directory to {file}`project-title`. + +```shell +cd project-title +``` + +To install both the Plone backend and frontend, use the following command. + +```shell +make install +``` + +This will take a few minutes. +☕️ +First the backend, then the frontend will be installed. + +When the process completes successfully, it will exit with no message. + +```{include} /_inc/_install-pillow.md +``` + + +## Start Plone + +Plone 6 has two servers: one for the frontend, and one for the backend. +As such, we need to maintain two active shell sessions, one for each server, to start your Plone site. + + +### Start Plone backend + +In the currently open session, issue the following command. + +```shell +make backend-start +``` + +The Plone backend server starts up and emits messages to the console. + +```console +2024-09-25 16:47:15,699 INFO [chameleon.config:39][MainThread] directory cache: //backend/instance/var/cache. +2024-09-25 16:47:16,387 WARNING [ZODB.FileStorage:412][MainThread] Ignoring index for //backend/instance/var/filestorage/Data.fs +2024-09-25 16:47:16,508 INFO [plone.restapi.patches:16][MainThread] PATCH: Disabled ZPublisher.HTTPRequest.ZopeFieldStorage.VALUE_LIMIT. This enables file uploads larger than 1MB. +2024-09-25 16:47:17,018 INFO [plone.volto:23][MainThread] Aliasing collective.folderish classes to plone.volto classes. +2024-09-25 16:47:17,760 INFO [Zope:42][MainThread] Ready to handle requests +Starting server in PID 20912. +2024-09-25 16:47:17,772 INFO [waitress:486][MainThread] Serving on http://[::1]:8080 +2024-09-25 16:47:17,772 INFO [waitress:486][MainThread] Serving on http://127.0.0.1:8080 +``` + + +### Start Plone frontend + +Create a second shell session in a new window. +Change your current working directory to {file}`project-title`. +Start the Plone frontend with the following command. + +```shell +make frontend-start +``` + +The Plone frontend server starts up and emits messages to the console, and should end with the following. + +```console +webpack 5.90.1 compiled successfully in 11004 ms +sswp> Handling Hot Module Reloading +Using volto.config.js in: //frontend/volto.config.js +✅ Server-side HMR Enabled! +Volto is running in SEAMLESS mode +Proxying API requests from http://localhost:3000/++api++ to http://localhost:8080/Plone +🎭 Volto started at 0.0.0.0:3000 🚀 +``` + +Note that the Plone frontend uses an internal proxy server to connect with the Plone backend. +Open a browser at the following URL to visit your Plone site. + +http://localhost:3000 + +You will see a page similar to the following. + +```{image} /_static/plone-home-page.png +:alt: Plone home page +:class: figure +``` + +Select the {guilabel}`Login` link to visit the login form, and enter the following credentials. + +- {guilabel}`Login name`: `admin` +- {guilabel}`Password`: `admin` + +```{image} /_static/plone-login-page.png +:alt: Plone login page +:class: figure +``` + +Now you can edit content or configure your Plone site. + +You can stop the site with {kbd}`ctrl-c`. diff --git a/docs/install/create-project.md b/docs/install/create-project.md index 396f8447a..db008515f 100644 --- a/docs/install/create-project.md +++ b/docs/install/create-project.md @@ -1,20 +1,22 @@ --- myst: html_meta: - "description": "Create a Plone project" - "property=og:description": "Create a Plone project" - "property=og:title": "Create a Plone project" - "keywords": "Plone, Plone 6, create, project, install, cookiecutter" + "description": "Create a Plone project with the Volto frontend (stable release)" + "property=og:description": "Create a Plone project with the Volto frontend (stable release)" + "property=og:title": "Create a Plone project with the Volto frontend (stable release)" + "keywords": "Plone, Plone 6, Volto, create, project, install, cookiecutter" --- (create-a-project-label)= -# Create a project +# Create a project with Volto (stable release) -This chapter describes how you can create a web application project using Plone, with full control over development and deployment. +This chapter describes how you can create a web application using the current **stable release** version of Plone with **Volto 17 or earlier** for the frontend, while having full control over its development and deployment. -If instead you want to contribute to a Plone package, see {doc}`/contributing/index`. +```{seealso} +For other installation options, see {doc}`/install/index`. +``` (install-packages-system-requirements-label)= @@ -28,25 +30,8 @@ Plone 6 has both hardware requirements and software pre-requisites. ### Hardware requirements -The hardware requirements below give a rough estimate of the minimum hardware setup needed for a Plone server. - -A single Plone installation is able to run many Plone sites. - -- Installation of the Plone backend and Classic UI frontend requires a minimum of 256 MB of RAM and 2GB of disk swap space. -- Installation of the Volto frontend requires a minimum of 2GB of RAM. -- After installation, running Plone requires a minimum of 256 MB RAM and 512 MB of disk swap space per Plone site. - 2 GB or more RAM per Plone site is recommended. -- Minimum 512 MB hard disk space is required. - 40 GB or more hard disk space is recommended. - - -````{warning} -{term}`Add-on` products and caching solutions may also increase RAM and disk swap space requirements. -To avoid RAM and disk swap limitations, we recommend either temporarily resizing your remote machine to accommodate the build, or build your images locally and upload them to an image store, such as [Docker Hub](https://hub.docker.com/) or [GitHub Packages](https://github.com/features/packages). -```{seealso} -[How much RAM is required to build a Volto front end?](https://community.plone.org/t/how-much-ram-is-required-to-build-a-volto-front-end/17949) and [Dealing with heap exhaustion while building Volto 17 on limited-RAM host](https://community.plone.org/t/dealing-with-heap-exhaustion-while-building-volto-17-on-limited-ram-host/18078). +```{include} /_inc/_hardware-requirements.md ``` -```` (install-packages-prerequisites-label)= @@ -71,9 +56,8 @@ To avoid RAM and disk swap limitations, we recommend either temporarily resizing #### Python -Installing Python is beyond the scope of this documentation. -However, it is recommended to use a Python version manager, {term}`pyenv` that allows you to install multiple versions of Python on your development environment without destroying your system's Python. -Plone requires Python version {SUPPORTED_PYTHON_VERSIONS}. +```{include} /_inc/_install-python.md +``` (install-prerequisites-pipx-label)= @@ -91,39 +75,9 @@ pip install pipx #### nvm -The following terminal session commands use `bash` for the shell. -Adapt them for your flavor of shell. - -```{seealso} -See the [`nvm` install and update script documentation](https://github.com/nvm-sh/nvm#install--update-script). -For the `fish` shell, see [`nvm.fish`](https://github.com/jorgebucaran/nvm.fish). +```{include} ../volto/contributing/install-nvm.md ``` -1. Create your shell profile, if it does not exist. - - ```shell - touch ~/.bash_profile - ``` - -2. Download and run the `nvm` install and update script, and pipe it into `bash`. - - ```shell - curl -o- https://raw.githubusercontent.com/creationix/nvm/v{NVM_VERSION}/install.sh | bash - ``` - -3. Source your profile. - Alternatively close the session and open a new one. - - ```shell - source ~/.bash_profile - ``` - -4. Verify that the `nvm` version is that which you just installed or updated: - - ```shell - nvm --version - ``` - (install-prerequisites-nodejs-label)= @@ -353,6 +307,9 @@ First the backend, then the frontend will be installed. When the process completes successfully, it will exit with no message. +```{include} /_inc/_install-pillow.md +``` + ````{note} If you used a Plone core package name, then `make install` will return an error message such as the following. diff --git a/docs/install/index.md b/docs/install/index.md index 2cdb8af20..3f0091b15 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -11,17 +11,8 @@ myst: # Install -In this part of the documentation, you can find how to {ref}`try Plone ` or how to install Plone to either {doc}`Create a Plone project ` or {doc}`Contribute to a Plone package `. - - -(install-index-try-plone-label)= - -## Try a Plone demo - -Choose a version to demo. - -- [Plone 6 with Volto frontend](https://demo.plone.org/) -- [Plone 6 with Classic UI](https://classic.demo.plone.org/login?came_from=/en) +In this part of the documentation, you can find how to install Plone to either create a Plone project or contribute to a Plone package. +You can also {ref}`try a Plone demo `. (install-index-getting-started-label)= @@ -31,26 +22,30 @@ Choose a version to demo. Choose an option to get started with Plone. If you are following a [Plone training](https://training.plone.org/), it should specify which option to choose. -::::{grid} 1 2 2 2 -:gutter: 1 1 1 2 +{doc}`create-project` +: This option is for developers who want to create a web application using the current **stable release** version of Plone with **Volto 17 or earlier** for the frontend. + +{doc}`create-project-classic-ui` +: This option is for developers who want to create a web application using the current **stable release** version of Plone with **Classic UI** for the frontend. -:::{grid-item-card} {octicon}`browser;1.5em;sd-mr-1` Create a project -:link: create-project -:link-type: doc +{doc}`create-project-cookieplone` +: This option is for developers who want to create a web application using the latest **development release** version of Plone with **Volto 18 or later** for the frontend. + The "development" version also means "pre-release", and includes alpha and beta versions and release candidates. + It allows developers to work with the cutting edge of Plone. + A development version is not stable, and features may change with little notice. -This option is for developers who want to create a web application using Plone. -See {doc}`create-project`. -::: +{doc}`Contribute to a Plone package ` +: This option is for developers who want to contribute to Plone and its packages. -:::{grid-item-card} {octicon}`repo-push;1.5em;sd-mr-1` Contribute to a Plone package -:link: plone:contributing/index -:link-type: doc -This option is for developers who want to contribute to Plone and its packages. -See {doc}`plone:contributing/index`. -::: +(install-index-try-plone-label)= + +## Try a Plone demo -:::: +Choose a version to demo. + +- [Plone 6 with Volto frontend](https://demo.plone.org/) +- [Plone 6 with Classic UI](https://classic.demo.plone.org/login?came_from=/en) ```{toctree} @@ -58,6 +53,8 @@ See {doc}`plone:contributing/index`. :hidden: true create-project +create-project-classic-ui +create-project-cookieplone manage-add-ons-packages containers/index ``` From 159548b28c948021f4ff4a7af1266adf5c3fc16e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 1 Oct 2024 04:27:07 -0700 Subject: [PATCH 433/810] Clean up plone/generator-volto glossary entry (#1725) --- docs/glossary.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/glossary.md b/docs/glossary.md index 05eae946a..ffd071fad 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -39,12 +39,12 @@ Cookieplone cookieplone-templates [`cookieplone-templates`](https://github.com/plone/cookieplone-templates) is a collection of templates used by {term}`Cookieplone`. -@plone/generator-volto plone/generator-volto +@plone/generator-volto ```{deprecated} Volto 18.0.0-alpha.43 ``` - [@plone/generator-volto](https://www.npmjs.com/package/@plone/generator-volto) is deprecated in favor of {term}`Cookieplone` since Volto 18.0.0-alpha.43. + [`@plone/generator-volto`](https://www.npmjs.com/package/@plone/generator-volto) is deprecated in favor of {term}`Cookieplone` since Volto 18.0.0-alpha.43. See {ref}`upgrade-18-cookieplone-label`. cookiecutter-plone-starter From c6fc36406e3f4f20bfee9dabe4259c8ff09b014a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 1 Oct 2024 04:28:14 -0700 Subject: [PATCH 434/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 682567a86..a6533499e 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 682567a86b9fc022fbad32e27906475c5410eee1 +Subproject commit a6533499ef33a27a2e4840b76023a09af3903750 diff --git a/submodules/volto b/submodules/volto index d81a0d339..8aff340d8 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit d81a0d339e25cf3a4efa98429edd66b3cf509b9b +Subproject commit 8aff340d809d2334ae2bb30609f0f50fc6631856 From 36e1a447606b843001b79ea4d4dee05f7de9db80 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 2 Oct 2024 00:34:25 -0700 Subject: [PATCH 435/810] GitHub moved Packages under Actions (#1726) --- docs/_inc/_hardware-requirements.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_inc/_hardware-requirements.md b/docs/_inc/_hardware-requirements.md index 76bd3c02f..bd6847682 100644 --- a/docs/_inc/_hardware-requirements.md +++ b/docs/_inc/_hardware-requirements.md @@ -12,7 +12,7 @@ A single Plone installation is able to run many Plone sites. ````{warning} {term}`Add-on` products and caching solutions may also increase RAM and disk swap space requirements. -To avoid RAM and disk swap limitations, we recommend either temporarily resizing your remote machine to accommodate the build, or build your images locally and upload them to an image store, such as [Docker Hub](https://hub.docker.com/) or [GitHub Packages](https://github.com/features/packages). +To avoid RAM and disk swap limitations, we recommend either temporarily resizing your remote machine to accommodate the build, or build your images locally and upload them to an image store, such as [Docker Hub](https://hub.docker.com/) or [GitHub Actions](https://github.com/features/actions). ```{seealso} [How much RAM is required to build a Volto front end?](https://community.plone.org/t/how-much-ram-is-required-to-build-a-volto-front-end/17949) and [Dealing with heap exhaustion while building Volto 17 on limited-RAM host](https://community.plone.org/t/dealing-with-heap-exhaustion-while-building-volto-17-on-limited-ram-host/18078). ``` From 5f879e601901a27a1d5356b7d8f7cf2ea9149e5c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 2 Oct 2024 00:52:53 -0700 Subject: [PATCH 436/810] Overhaul Manage Add-ons and Packages (#1724) * Overhaul Manage Add-ons and Packages - Create a new Diataxis explanation section, Conceptual guides. - Create a new section, Manage Plone, and pages for frontend and backend. - Move bits from manage-add-ons-packages.md into appropriate files * Add a redirect * Move cookiecutter info to Glossary * Move Configuration with `cookiecutter-zope-instance` to manage/backend.md * Remove manage-add-ons-packages.md --- .../xkcd-1987-python-environment.png | Bin 0 -> 52253 bytes docs/conceptual-guides/index.md | 20 +++ .../make-build-backend-walk-through.md | 58 +++++++ docs/conceptual-guides/package-management.md | 64 ++++++++ docs/conf.py | 1 + docs/glossary.md | 4 +- docs/index.md | 2 + docs/install/index.md | 1 - .../backend.md} | 149 +++--------------- docs/manage/frontend.md | 18 +++ docs/manage/index.md | 20 +++ 11 files changed, 212 insertions(+), 125 deletions(-) create mode 100644 docs/_static/conceptual-guides/xkcd-1987-python-environment.png create mode 100644 docs/conceptual-guides/index.md create mode 100644 docs/conceptual-guides/make-build-backend-walk-through.md create mode 100644 docs/conceptual-guides/package-management.md rename docs/{install/manage-add-ons-packages.md => manage/backend.md} (57%) create mode 100644 docs/manage/frontend.md create mode 100644 docs/manage/index.md diff --git a/docs/_static/conceptual-guides/xkcd-1987-python-environment.png b/docs/_static/conceptual-guides/xkcd-1987-python-environment.png new file mode 100644 index 0000000000000000000000000000000000000000..a8e8fd619e3bd94fef1aee89877967c78aab32bd GIT binary patch literal 52253 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 Setup Virtual Env$(RESET)" + python3 -m venv . + bin/pip install -U "pip" "wheel" "cookiecutter" "mxdev" + +instance/etc/zope.ini: bin/pip + @echo "$(GREEN)==> Install Plone and create instance$(RESET)" + bin/cookiecutter -f --no-input --config-file instance.yaml https://github.com/plone/cookiecutter-zope-instance + mkdir -p var/{filestorage,blobstorage,cache,log} + +# ... + +.PHONY: build-dev +build-dev: instance/etc/zope.ini ## pip install Plone packages + @echo "$(GREEN)==> Setup Build$(RESET)" + bin/mxdev -c mx.ini + bin/pip install -r requirements-mxdev.txt +``` + +The command `make build-backend`: + +- Invokes the target `build-dev` target in `backend/Makefile`. +- This invokes the target `instance/etc/zope.ini`. +- This invokes the target `bin/pip`. + + - This creates a `Python` virtual environment if one does not exist. + - It installs and upgrades Python package management tools in that virtual environment. + +- Returning to the target `instance/etc/zope.ini`: + + - This creates or updates the Zope configuration from its `instance.yaml` file using `cookiecutter-zope-instance`. + - Creates specified directories, if they do not exist. + +- Returning to the target `build-dev`: + + - This generates the `mxdev` files as described above in {ref}`manage-mxdev-usage-overview-label`. + - Installs Plone core packages and add-ons from the files generated by `mxdev`. + +You can configure your Zope instance as described in the section {ref}`manage-common-management-tasks-label`. diff --git a/docs/conceptual-guides/package-management.md b/docs/conceptual-guides/package-management.md new file mode 100644 index 000000000..7e5dd4084 --- /dev/null +++ b/docs/conceptual-guides/package-management.md @@ -0,0 +1,64 @@ +--- +myst: + html_meta: + "description": "Package management in Plone." + "property=og:description": "Package management in Plone." + "property=og:title": "Package management" + "keywords": "Plone 6, package management, mxdev" +--- + +# Package management + +Plone 6 consists of a collection of Python and Node.js packages. +Over the decades of its existence, Plone has used several package management tools, sometimes multiple tools at one time. +Each one has its strengths and weaknesses for performing specific tasks, such as installation, conflict resolution, updates and upgrades, and working with virtual environments and across platforms. + +With Volto as the default frontend in Plone 6, first npm, then pnpm, was brought into the mix as a package manager for its Node.js packages. + +Python itself has a complex and convoluted history with package management, as [xkcd](https://xkcd.com/1987/) illustrates. + +```{image} /_static/conceptual-guides/xkcd-1987-python-environment.png +:alt: A comic from xkcd entitled Python Environment +:class: figure +:target: https://xkcd.com/1987/ +``` + + +(manage-backend-python-packages-label)= + +## Manage backend Python packages + +If you want to check out a Plone core package for development, or want to override the constraints of Plone, normally you would define constraints with a file {file}`constraints.txt` to tell `pip` to install a different version of a Plone package. + +```text +# constraints.txt with unresolvable version conflict +-c https://dist.plone.org/release/{PLONE_BACKEND_PATCH_VERSION}/constraints.txt +plone.api>=2.0.0a3 +``` + +Unfortunately `pip` does not allow overriding constraints this way. +{term}`mxdev` solves this issue. + + +### `mxdev` to the rescue! + +`mxdev` resolves Plone constraints according to your needs for pinning versions or source checkouts. +It reads its configuration file {file}`mx.ini`, and your {file}`requirements.txt` and {file}`constraints.txt` files. +Then it fetches the requirements and constraints of Plone. +Finally, it writes new combined requirements in {file}`requirements-mxdev.txt` and new constraints in {file}`constraints-mxdev.txt`. +Together these two files contain the combined requirements and constraints, but modified according to the configuration in {file}`mx.ini`. +The generated files indicate from where the constraints were fetched, and comments are added when a modification was necessary. + +`mxdev` does not run `pip` or install packages. +You or your development tools, such as GNU Make, must perform that step. + +```{seealso} +{doc}`/manage/backend` +``` + + +## Manage frontend Node.js packages + +```{todo} +Why do we use pnpm? +``` \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index ebfff44d4..44d4834df 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -245,6 +245,7 @@ "contributing/plone-restapi": "/plone.restapi/docs/source/contributing/index.html", "contributing/volto": "/volto/contributing/index.html", "install/install-from-packages": "/install/create-project.html", + "manage/frontend": "/volto/addons/index.html", } diff --git a/docs/glossary.md b/docs/glossary.md index ffd071fad..d637dca9b 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -48,7 +48,9 @@ plone/generator-volto See {ref}`upgrade-18-cookieplone-label`. cookiecutter-plone-starter - [cookiecutter-plone-starter](https://github.com/collective/cookiecutter-plone-starter/) is a framework for jumpstarting Plone 6 projects quickly. + [cookiecutter-plone-starter](https://github.com/collective/cookiecutter-plone-starter/) creates a Plone project that you can install using {term}`Make`. + It generates files for installing and configuring both the frontend and backend. + For the backend, it uses {term}`cookiecutter-zope-instance` to generate configuration files for a Zope WSGI instance. cookiecutter-zope-instance [cookiecutter-zope-instance](https://github.com/plone/cookiecutter-zope-instance) is a cookiecutter template to create a full and complex configuration of a Zope WSGI instance. diff --git a/docs/index.md b/docs/index.md index ef7dcb6b2..0ab3dbaca 100644 --- a/docs/index.md +++ b/docs/index.md @@ -32,6 +32,7 @@ Read the [documentation for the previous version, Plone 5](https://5.docs.plone. overview/index install/index +manage/index upgrade/index deployment/index volto/index @@ -39,6 +40,7 @@ plone.restapi/docs/source/index backend/index classic-ui/index i18n-l10n/index +conceptual-guides/index contributing/index ``` diff --git a/docs/install/index.md b/docs/install/index.md index 3f0091b15..1f8c95ce7 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -55,6 +55,5 @@ Choose a version to demo. create-project create-project-classic-ui create-project-cookieplone -manage-add-ons-packages containers/index ``` diff --git a/docs/install/manage-add-ons-packages.md b/docs/manage/backend.md similarity index 57% rename from docs/install/manage-add-ons-packages.md rename to docs/manage/backend.md index e1b432dfe..8f24599d2 100644 --- a/docs/install/manage-add-ons-packages.md +++ b/docs/manage/backend.md @@ -1,90 +1,30 @@ --- myst: html_meta: - "description": "Manage add-ons, packages, and processes" - "property=og:description": "Manage add-ons, packages, and processes" - "property=og:title": "Manage add-ons, packages, and processes" - "keywords": "Plone 6, manage, backend, add-ons, packages, processes, cookiecutter, Zope" + "description": "Manage Plone backend" + "property=og:description": "Manage Plone backend" + "property=og:title": "Manage Plone backend" + "keywords": "Plone 6, manage, backend, add-ons, packages, mxdev" --- +(manage-plone-backend-label)= -(manage-add-ons-packages-and-processes-label)= +# Manage Plone backend -# Manage add-ons and packages +This part of the documentation describes how to perform common management tasks in the Plone backend. +This chapter assumes you have previously followed {doc}`/install/create-project`. -This chapter assumes you have previously followed {doc}`create-project`. -In this section, we discuss details of the installation process so that you can customize your Plone installation. -It also covers routine management tasks that a developer might perform. +## Manage add-ons and packages -(manage-installation-details-with-cookiecutter-label)= - -## Installation details with Cookiecutter - -{term}`Cookiecutter` creates projects from project templates. -The cookiecutter [`cookiecutter-plone-starter`](https://github.com/collective/cookiecutter-plone-starter/) creates a Plone project that you can install using {term}`Make`. -It generates files for installing and configuring both the frontend and backend. -For the backend, it uses [`cookiecutter-zope-instance`](https://github.com/plone/cookiecutter-zope-instance) to generate configuration files for a Zope WSGI instance. - - -(manage-configuration-with-cookiecutter-zope-instance-label)= - -## Configuration with `cookiecutter-zope-instance` - -You can configure your instance's options, including the following. - -- persistent storage: blobs, direct filestorage, relational database, ZEO, and so on -- ports -- threads -- cache -- debugging and profiling for development +Plone uses `mxdev` to manage packages and constraints. ```{seealso} -For a complete list of features, usage, and options, read [`cookiecutter-zope-instance`'s `README.rst`](https://github.com/plone/cookiecutter-zope-instance#readme). +For an explanation of why Plone uses `mxdev`, see {ref}`manage-backend-python-packages-label`. ``` -(manage-plone-backend-packages-with-mxdev-label)= - -## Manage Plone backend packages with `mxdev` - -This section describes how to manage packages for the Plone backend with `mxdev`. - -For developing add-ons for the Plone frontend, Volto, see {doc}`volto/addons/index`. - - -(manage-the-problem-with-pip-label)= - -### The problem with `pip` - -If you want to check out a Plone core package for development, or want to override the constraints of Plone, normally you would define constraints with a file {file}`constraints.txt` to tell `pip` to install a different version of a Plone package. - -``` -# constraints.txt with unresolvable version conflict --c https://dist.plone.org/release/{PLONE_BACKEND_PATCH_VERSION}/constraints.txt -plone.api>=2.0.0a3 -``` - -Unfortunately `pip` does not allow overriding constraints this way. -{term}`mxdev` solves this issue. - - -(manage-mxdev-to-the-rescue-label)= - -### `mxdev` to the rescue! - -`mxdev` resolves Plone constraints according to your needs for version pinning or source checkouts. -It reads its configuration file {file}`mx.ini`, and your {file}`requirements.txt` and {file}`constraints.txt` files. -Then it fetches the requirements and constraints of Plone. -Finally, it writes new combined requirements in {file}`requirements-mxdev.txt` and new constraints in {file}`constraints-mxdev.txt`. -Together these two files contain the combined requirements and constraints, but modified according to the configuration in {file}`mx.ini`. -The generated files indicate from where the constraints were fetched, and comments are added when a modification was necessary. - -`mxdev` does not run `pip` or install packages. -You must perform that step. - - -(manage-mxdev-usage-overview-label)= +(mxdev-usage-overview-label)= ### `mxdev` usage overview @@ -140,7 +80,7 @@ make build-backend `make build-backend` invokes `mxdev`, which generates the files {file}`requirements-mxdev.txt` and {file}`constraints-mxdev.txt`. It then invokes `pip` to install packages with the new requirements file. -To reload the packages, stop your Zope instance/Plone site with {kbd}`ctrl-c`, and start it with the following command. +To reload the packages, stop your Plone site with {kbd}`ctrl-c`, and start it with the following command. ```shell make start-backend @@ -151,15 +91,6 @@ See the [documentation of `mxdev` in its README.md](https://github.com/mxstack/m ``` -(manage-common-management-tasks-label)= - -## Common management tasks - -This section provides examples of common add-on and package management tasks. -For the examples, we will modify the default files from the previous section {ref}`manage-mxdev-usage-overview-label`. -We will also use Classic UI for the interface because some packages and add-ons have not yet been updated to work with the new frontend. - - (manage-add-an-add-on)= ### Add an add-on @@ -346,51 +277,23 @@ In a web browser, visit http://localhost:8080/ to see that Plone is running. Your instance is running in the foreground. - -(manage-installation-details-label)= - -## Backend installation details - -The `Makefile` at the root of your project invokes commands in `backend/Makefile`. -Here are excerpts from `backend/Makefile` to show details of the `make build-backend` command. - -```makefile -bin/pip: - @echo "$(GREEN)==> Setup Virtual Env$(RESET)" - python3 -m venv . - bin/pip install -U "pip" "wheel" "cookiecutter" "mxdev" - -instance/etc/zope.ini: bin/pip - @echo "$(GREEN)==> Install Plone and create instance$(RESET)" - bin/cookiecutter -f --no-input --config-file instance.yaml https://github.com/plone/cookiecutter-zope-instance - mkdir -p var/{filestorage,blobstorage,cache,log} - -# ... - -.PHONY: build-dev -build-dev: instance/etc/zope.ini ## pip install Plone packages - @echo "$(GREEN)==> Setup Build$(RESET)" - bin/mxdev -c mx.ini - bin/pip install -r requirements-mxdev.txt +```{seealso} +For an explanation of the command `make build-backend`, see {doc}`/conceptual-guides/make-build-backend-walk-through`. ``` -The command `make build-backend`: - -- Invokes the target `build-dev` target in `backend/Makefile`. -- This invokes the target `instance/etc/zope.ini`. -- This invokes the target `bin/pip`. - - - This creates a `Python` virtual environment if one does not exist. - - It installs and upgrades Python package management tools in that virtual environment. -- Returning to the target `instance/etc/zope.ini`: +(manage-configuration-with-cookiecutter-zope-instance-label)= - - This creates or updates the Zope configuration from its `instance.yaml` file using `cookiecutter-zope-instance`. - - Creates specified directories, if they do not exist. +## Configuration with `cookiecutter-zope-instance` -- Returning to the target `build-dev`: +You can configure your instance's options, including the following. - - This generates the `mxdev` files as described above in {ref}`manage-mxdev-usage-overview-label`. - - Installs Plone core packages and add-ons from the files generated by `mxdev`. +- persistent storage: blobs, direct filestorage, relational database, ZEO, and so on +- ports +- threads +- cache +- debugging and profiling for development -You can configure your Zope instance as described in the section {ref}`manage-common-management-tasks-label`. +```{seealso} +For a complete list of features, usage, and options, read [`cookiecutter-zope-instance`'s `README.rst`](https://github.com/plone/cookiecutter-zope-instance#readme). +``` diff --git a/docs/manage/frontend.md b/docs/manage/frontend.md new file mode 100644 index 000000000..9d3c275c9 --- /dev/null +++ b/docs/manage/frontend.md @@ -0,0 +1,18 @@ +--- +myst: + html_meta: + "description": "Manage Plone frontend" + "property=og:description": "Manage Plone frontend" + "property=og:title": "Manage Plone frontend" + "keywords": "Plone 6, manage, frontend, add-ons, packages" +--- + +(manage-plone-frontend-label)= + +# Manage Plone frontend + +This part of the documentation describes how to perform common management tasks in the Plone frontend. + +```{seealso} +{doc}`/volto/addons/index` +``` diff --git a/docs/manage/index.md b/docs/manage/index.md new file mode 100644 index 000000000..4e7fb946e --- /dev/null +++ b/docs/manage/index.md @@ -0,0 +1,20 @@ +--- +myst: + html_meta: + "description": "Manage add-ons, packages, and processes in Plone" + "property=og:description": "Manage add-ons, packages, and processes in Plone" + "property=og:title": "Manage add-ons, packages, and processes in Plone" + "keywords": "Plone 6, manage, backend, frontend, Volto, Classic UI, add-ons, packages, processes, cookiecutter, Zope" +--- + +# Manage Plone + +This part of the documentation describes how to perform common management tasks in Plone. + + +```{toctree} +:maxdepth: 2 + +backend +frontend +``` From 85fda2dbf15b443d97655b8871055cf8d17ccc0d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 2 Oct 2024 01:26:06 -0700 Subject: [PATCH 437/810] Fix spelling of prerequisites --- docs/classic-ui/theming/barceloneta.md | 8 ++++---- docs/contributing/core/index.md | 6 +++--- docs/contributing/documentation/setup-build.md | 2 +- docs/i18n-l10n/contributing-translations.md | 4 ++-- docs/install/containers/index.md | 2 +- docs/install/create-project-classic-ui.md | 6 +++--- docs/install/create-project-cookieplone.md | 6 +++--- docs/install/create-project.md | 4 ++-- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/classic-ui/theming/barceloneta.md b/docs/classic-ui/theming/barceloneta.md index ea26643c3..0080106f1 100644 --- a/docs/classic-ui/theming/barceloneta.md +++ b/docs/classic-ui/theming/barceloneta.md @@ -15,17 +15,17 @@ This chapter describes how to create a custom theme for Plone Classic UI based o Barceloneta is the default enabled theme for Plone Classic UI. -(classic-ui-theming-barceloneta-pre-requisites-label)= +(classic-ui-theming-barceloneta-prerequisites-label)= -## Pre-requisites +## Prerequisites -To create an add-on package with a Plone Classic UI theme, you need to install the following pre-requisites. +To create an add-on package with a Plone Classic UI theme, you need to install the following prerequisites. - [Node.js (16/18)](https://nodejs.org/en) - [Python (>=3.8)](https://www.python.org/) - [plonecli](https://pypi.org/project/plonecli/) -Read more about how to install pre-requisites in {doc}`/install/create-project`. +Read more about how to install prerequisites in {doc}`/install/create-project`. (classic-ui-theming-barceloneta-create-a-classic-ui-theme-add-on-package-label)= diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 888d16f16..a8fea1426 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -30,11 +30,11 @@ You must {ref}`contributing-sign-and-return-the-plone-contributor-agreement-labe Before you contribute to Plone core, check the [version support policy](https://plone.org/download/release-schedule) to see which versions of Plone are currently supported. -(plone-pre-requisites-label)= +(plone-prerequisites-label)= -## Pre-requisites +## Prerequisites -It is beyond the scope of this documentation to provide installation instructions for all pre-requisites for your operating system. +It is beyond the scope of this documentation to provide installation instructions for all prerequisites for your operating system. However, the following links and sections below may be helpful. ```{include} ../../volto/contributing/install-operating-system.md diff --git a/docs/contributing/documentation/setup-build.md b/docs/contributing/documentation/setup-build.md index e39d3e728..db25b73fe 100644 --- a/docs/contributing/documentation/setup-build.md +++ b/docs/contributing/documentation/setup-build.md @@ -18,7 +18,7 @@ This document covers how to set up and build the Plone Documentation and check i ## Installation -Installation of Plone 6 Documentation includes pre-requisites and the repository itself. +Installation of Plone 6 Documentation includes prerequisites and the repository itself. ```{include} ../../volto/contributing/install-operating-system.md ``` diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index 7b9ca1ad8..d93c1c1ef 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -23,9 +23,9 @@ Translations can be added or updated as needed by the citizens of Earth. You will need to work in one repository for Plone core, and optionally another one for Volto. -(contributing-plone-core-translations-pre-requisites-label)= +(contributing-plone-core-translations-prerequisites-label)= -## Pre-requisites +## Prerequisites Request write access to https://github.com/collective/plone.app.locales to be able to commit your translation directly. diff --git a/docs/install/containers/index.md b/docs/install/containers/index.md index e6167c21f..5aef61ee6 100644 --- a/docs/install/containers/index.md +++ b/docs/install/containers/index.md @@ -11,7 +11,7 @@ myst: # Containers -The Plone 6 images have all the system requirements, pre-requisites, and Plone 6 already installed, except those requirements needed for running the container engine itself. +The Plone 6 images have all the system requirements, prerequisites, and Plone 6 already installed, except those requirements needed for running the container engine itself. Using containers is the easiest way to deploy Plone 6. Containers may also be used when {doc}`creating a Plone project <../create-project>` and {doc}`contributing to Plone `. diff --git a/docs/install/create-project-classic-ui.md b/docs/install/create-project-classic-ui.md index c04189f92..1826a1056 100644 --- a/docs/install/create-project-classic-ui.md +++ b/docs/install/create-project-classic-ui.md @@ -21,7 +21,7 @@ For other installation options, see {doc}`/install/index`. ## System requirements -Plone 6 has both hardware requirements and software pre-requisites. +Plone 6 has both hardware requirements and software prerequisites. ### Hardware requirements @@ -29,7 +29,7 @@ Plone 6 has both hardware requirements and software pre-requisites. ```{include} /_inc/_hardware-requirements.md ``` -### Pre-requisites for installation +### Prerequisites for installation ```{include} ../volto/contributing/install-operating-system.md ``` @@ -69,7 +69,7 @@ pip install pipx ## Generate the project -After satisfying the pre-requisites, generate the project. +After satisfying the prerequisites, generate the project. ```shell pipx run cookieplone backend_addon diff --git a/docs/install/create-project-cookieplone.md b/docs/install/create-project-cookieplone.md index 2fcf7da48..5f2122aff 100644 --- a/docs/install/create-project-cookieplone.md +++ b/docs/install/create-project-cookieplone.md @@ -25,7 +25,7 @@ For other installation options, see {doc}`/install/index`. ## System requirements -Plone 6 has both hardware requirements and software pre-requisites. +Plone 6 has both hardware requirements and software prerequisites. ### Hardware requirements @@ -33,7 +33,7 @@ Plone 6 has both hardware requirements and software pre-requisites. ```{include} /_inc/_hardware-requirements.md ``` -### Pre-requisites for installation +### Prerequisites for installation ```{include} ../volto/contributing/install-operating-system.md ``` @@ -93,7 +93,7 @@ pip install pipx ## Generate the project -After satisfying the pre-requisites and having activated an LTS version of Node, +After satisfying the prerequisites and having activated an LTS version of Node, generate the project. ```shell diff --git a/docs/install/create-project.md b/docs/install/create-project.md index db008515f..7e7ab358f 100644 --- a/docs/install/create-project.md +++ b/docs/install/create-project.md @@ -23,7 +23,7 @@ For other installation options, see {doc}`/install/index`. ## System requirements -Plone 6 has both hardware requirements and software pre-requisites. +Plone 6 has both hardware requirements and software prerequisites. (install-packages-hardware-requirements-label)= @@ -36,7 +36,7 @@ Plone 6 has both hardware requirements and software pre-requisites. (install-packages-prerequisites-label)= -### Pre-requisites for installation +### Prerequisites for installation ```{include} ../volto/contributing/install-operating-system.md ``` From 27c22c0b979d28f974ebb8d4341a80a82a5f9e39 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 2 Oct 2024 01:29:04 -0700 Subject: [PATCH 438/810] Reject hyphenated `pre-requisite` and sort accept.txt items --- styles/Vocab/Plone/accept.txt | 6 +++--- styles/Vocab/Plone/reject.txt | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/styles/Vocab/Plone/accept.txt b/styles/Vocab/Plone/accept.txt index 45c67d02c..ee6ce6d9d 100644 --- a/styles/Vocab/Plone/accept.txt +++ b/styles/Vocab/Plone/accept.txt @@ -30,9 +30,9 @@ Pastanaga PLIP(s) Plone pluggab(le|ility) -programatically [Pp]ortlet prerendered +programatically [Qq]uerystring Razzle [Rr]enderer @@ -42,10 +42,10 @@ Schuko subfolder [Tt]owncrier transpile[dr]{0,1} -unregister -UUID [Uu]ncomment [Uu]nhide +unregister +UUID validator [Vv]iewlet Volto diff --git a/styles/Vocab/Plone/reject.txt b/styles/Vocab/Plone/reject.txt index 1cefa812f..81510d55a 100644 --- a/styles/Vocab/Plone/reject.txt +++ b/styles/Vocab/Plone/reject.txt @@ -1,2 +1,3 @@ [^.]js NodeJS +[Pp]re-requisite From 83b05609c8e6f2c5d216a25e391b249b31865ad1 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 2 Oct 2024 02:42:08 -0700 Subject: [PATCH 439/810] Add where to report bugs and feature requests when you don't know the source repository (#1728) --- docs/contributing/index.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/contributing/index.md b/docs/contributing/index.md index a84af9a7c..a5c78b3f0 100644 --- a/docs/contributing/index.md +++ b/docs/contributing/index.md @@ -54,6 +54,7 @@ Sign the Plone Contributor Agreement The Plone Foundation has published a [Code of Conduct](https://plone.org/foundation/materials/foundation-resolutions/code-of-conduct). All contributors to the Plone Documentation follow the Code of Conduct. + (contributing-first-time-contributors-label)= ## First-time contributors @@ -61,6 +62,14 @@ All contributors to the Plone Documentation follow the Code of Conduct. First-time contributors should read and follow our guide {doc}`first-time`. +(report-bugs-and-feature-requests-label)= + +## Report bugs and request features + +When you experience a bug with, or want to request a feature for Plone, but you don't know in which package you should create the GitHub issue, you can create an issue in the primary Plone repository, [`Products.CMFPlone`](https://github.com/plone/Products.CMFPlone/). +Someone will help identify in which of the dozens of repositories that make up Plone the actual change and pull request should be made. + + (contributing-continuous-integration-label)= ## Continuous integration From bd2b407fc7afdd13a417d7f54e0973aa99108b58 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 2 Oct 2024 13:49:33 -0700 Subject: [PATCH 440/810] Update tips submodules/plone.api submodules/plone.restapi submodules/volto --- submodules/plone.api | 2 +- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index 47245aa8d..ae64739ff 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit 47245aa8d3a0bde5c645818a441dac44e1919a0f +Subproject commit ae64739ff0cc5cc88fa19beafc875456268014bf diff --git a/submodules/plone.restapi b/submodules/plone.restapi index a6533499e..6e5e669ca 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit a6533499ef33a27a2e4840b76023a09af3903750 +Subproject commit 6e5e669ca11585ed69a5a02cd00175dfb5a73b46 diff --git a/submodules/volto b/submodules/volto index 8aff340d8..ff84416d6 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 8aff340d809d2334ae2bb30609f0f50fc6631856 +Subproject commit ff84416d69d89bb86fd36e378a52f27be31f2c40 From fe984c1a033bd9258cdc289b2c26c4480ab017d6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 2 Oct 2024 23:32:09 -0700 Subject: [PATCH 441/810] Fix syntax (#1732) --- docs/contributing/core/continuous-integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/core/continuous-integration.md b/docs/contributing/core/continuous-integration.md index 43723d199..a3f3408ab 100644 --- a/docs/contributing/core/continuous-integration.md +++ b/docs/contributing/core/continuous-integration.md @@ -36,7 +36,7 @@ When you push a commit to a Plone repository on GitHub, the email address in you If it does not match, then `mr.roboto` will notify you that there is a problem that prevents your pull request from being merged. You must resolve the issue. -To change the email address in your commits, see [Setting your commit email address](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/setting-your-commit-email-address]. +To change the email address in your commits, see [Setting your commit email address](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/setting-your-commit-email-address). To add an email address to your GitHub account, see [Adding an email address to your GitHub account](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/adding-an-email-address-to-your-github-account). From 4ae0e9af043d7f001c54bbeb752ef1908f8056cb Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 5 Oct 2024 01:46:59 -0700 Subject: [PATCH 442/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 6e5e669ca..f68fab7ea 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 6e5e669ca11585ed69a5a02cd00175dfb5a73b46 +Subproject commit f68fab7ea3209a096423d8567fa7f70a93786c7a diff --git a/submodules/volto b/submodules/volto index ff84416d6..78ae6dd10 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit ff84416d69d89bb86fd36e378a52f27be31f2c40 +Subproject commit 78ae6dd107cc4bda9a5080640fb905745c6c120a From 41696ab47052eb16399a5f0157e4c28a84b62ce9 Mon Sep 17 00:00:00 2001 From: Mikel Larreategi Date: Mon, 7 Oct 2024 13:08:33 +0200 Subject: [PATCH 443/810] document how to use Google Translate to translate content (#1723) * document how to use Google Translate to translate content * add a note saying that one needs to enter something in the API key field * Review of PR --------- Co-authored-by: Steve Piercy --- docs/i18n-l10n/index.md | 1 + .../use-an-external-translation-service.md | 101 ++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 docs/i18n-l10n/use-an-external-translation-service.md diff --git a/docs/i18n-l10n/index.md b/docs/i18n-l10n/index.md index efd6ce6de..c80dee7a5 100644 --- a/docs/i18n-l10n/index.md +++ b/docs/i18n-l10n/index.md @@ -160,5 +160,6 @@ language-negotiation-volto translating-content contributing-translations resync-translations +use-an-external-translation-service ``` diff --git a/docs/i18n-l10n/use-an-external-translation-service.md b/docs/i18n-l10n/use-an-external-translation-service.md new file mode 100644 index 000000000..f396ca82f --- /dev/null +++ b/docs/i18n-l10n/use-an-external-translation-service.md @@ -0,0 +1,101 @@ +--- +myst: + html_meta: + "description": "When translating content items in Plone, you can connect to an external translation service to translate your content." + "property=og:description": "When translating content items in Plone, you can connect to an external translation service to translate your content." + "property=og:title": "Use an external translation service to translate content" + "keywords": "Plone, Internationalization, i18n, language, translate, content, localization, l10n" +--- + +(use-an-external-translation-service-label)= + +# Use an external translation service to translate content + +When translating content items in Plone, you can connect to an external translation service to translate your content. + + +## Using Google Cloud Translation API + +The `plone.app.multilingual` product that turns Plone into a multilingual-content site supports [Google Cloud Translation API](https://cloud.google.com/translate/docs/reference/rest), which allows the content editor to use its translations. + +To use this service as a site administrator, you need to create a project in Google Cloud, enable the Cloud Translation API, and create an API key under the Credentials of the Google Cloud Console. +You should enter this API key in the {guilabel}`Multilingual Settings` control panel in Plone. + +After doing so, as a content editor, when you edit a translation of a given content page, an icon will display next to the original content. +When you click this icon, it invokes the Google Cloud Translation API, and the translation obtained through the service will be entered automatically in the corresponding field. + +```{note} +The usage of Google Cloud Translation API may create extra cost for the site administrator. +See [Cloud Translation pricing](https://cloud.google.com/translate/pricing) for details. +``` + + +## Using other translation services + +If you want to use another service beside Google Cloud Translation API, you will need to override the view that calls Google Cloud Translation API. + +To do so, `plone.app.multilingual` registers a view called `gtranslation_service`. +Its code is in [`plone.app.multilingual.brwoser.translate.gtranslation_service_dexterity`](https://github.com/plone/plone.app.multilingual/blob/7aedd0ab71d3edf5d1fb4cb86b9f611d428ed76b/src/plone/app/multilingual/browser/translate.py#L52). +This view gets three parameters: + +`context_uid` +: The UID of the object to be translated. + +`field` +: The name of the field of the object that needs to be translated. + This view's job is to extract the value of that field from the object. + +`lang_source` +: The source language code. + +The first part of the view—that which gets the object and the field content to be translated—can be copied from the original code. +You need to write only the call to the translation service. +The required code would be something like the following example: + +```python +class TranslateUsingMyService(BrowserView): + def __call__(self): + if self.request.method != "POST" and not ( + "field" in self.request.form.keys() + and "lang_source" in self.request.form.keys() + ): + return _("Need a field") + else: + manager = ITranslationManager(self.context) + context_uid = self.request.form.get("context_uid", None) + if context_uid is None: + # try with context if no translation uid is present + manager = ITranslationManager(self.context) + else: + catalog = getToolByName(self.context, "portal_catalog") + brains = catalog(UID=context_uid) + if len(brains): + context = brains[0].getObject() + manager = ITranslationManager(context) + else: + manager = ITranslationManager(self.context) + + registry = getUtility(IRegistry) + settings = registry.forInterface( + IMultiLanguageExtraOptionsSchema, prefix="plone" + ) + lang_target = ILanguage(self.context).get_language() + lang_source = self.request.form["lang_source"] + orig_object = manager.get_translation(lang_source) + field = self.request.form["field"].split(".")[-1] + if hasattr(orig_object, field): + question = getattr(orig_object, field, "") + if hasattr(question, "raw"): + question = question.raw + else: + return _("Invalid field") + + # And here do the call to the external translation service + return call_to_my_service(question, lang_target, lang_source) +``` + +```{note} +Due to the way that the Google Translate integration is built in `plone.app.multilingual`, you will need to enter something in the {guilable}`Google Translate API Key` field in the {guilable}`Multilingual Settings` +control panel of your site. +It doesn't need to be a valid Google Translate API Key; it can be a random string. +``` From 20efe396f128a7f6b1e58c5c6b9d99c2a986343b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 8 Oct 2024 17:59:28 -0700 Subject: [PATCH 444/810] Linkcheck 2024 10 08 (#1735) * Include changes to http-examples to build docs preview * Update link to PST requirements file --- docs/contributing/documentation/admins.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/contributing/documentation/admins.md b/docs/contributing/documentation/admins.md index fe3c2db89..ac0c177f1 100644 --- a/docs/contributing/documentation/admins.md +++ b/docs/contributing/documentation/admins.md @@ -96,8 +96,7 @@ The following are example files that you can use to configure your project for p - [Plone Sphinx Theme `Makefile`](https://github.com/plone/plone-sphinx-theme/blob/main/Makefile), specifically the `rtd-pr-preview` section. This is the command to use to build documentation previews on Read the Docs. -- [Plone Sphinx Theme `requirements-initial.txt`](https://github.com/plone/plone-sphinx-theme/blob/main/requirements-initial.txt) specifies the initial Python packaging tool requirements to set up a virtual environment. -- [Plone Sphinx Theme `requirements-docs.txt`](https://github.com/plone/plone-sphinx-theme/blob/main/requirements-docs.txt) specifies the requirements to use Plone Sphinx Theme and build the docs. +- [Plone Sphinx Theme `requirements-dev.txt`](https://github.com/plone/plone-sphinx-theme/blob/main/requirements-docs.txt) specifies the requirements to use Plone Sphinx Theme and build the docs. - [Plone Sphinx Theme `conf.py`](https://github.com/plone/plone-sphinx-theme/blob/main/docs/conf.py) the Sphinx configuration file to build the docs. - [Plone Sphinx Theme `.readthedocs.yaml`](https://github.com/plone/plone-sphinx-theme/blob/main/.readthedocs.yaml) specifies the configuration and command to build the docs. - [Plone Sphinx Theme `.github/workflows/rtd-pr-preview.yml`](https://github.com/plone/plone-sphinx-theme/blob/main/.github/workflows/rtd-pr-preview.yml) specifies when to build the docs, specifically only when a pull request is opened against the `main` branch and there are changes to documentation files. From 263c6a46062ac15ecd0ce4781dc3538cda568179 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 8 Oct 2024 23:02:13 -0700 Subject: [PATCH 445/810] Minor syntax fixes (#1736) * Include changes to http-examples to build docs preview * Fix syntax of guilabel * Fix references --- docs/conceptual-guides/make-build-backend-walk-through.md | 4 ++-- docs/i18n-l10n/use-an-external-translation-service.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/conceptual-guides/make-build-backend-walk-through.md b/docs/conceptual-guides/make-build-backend-walk-through.md index 59435e114..a39bc9cba 100644 --- a/docs/conceptual-guides/make-build-backend-walk-through.md +++ b/docs/conceptual-guides/make-build-backend-walk-through.md @@ -52,7 +52,7 @@ The command `make build-backend`: - Returning to the target `build-dev`: - - This generates the `mxdev` files as described above in {ref}`manage-mxdev-usage-overview-label`. + - This generates the `mxdev` files as described above in {ref}`mxdev-usage-overview-label`. - Installs Plone core packages and add-ons from the files generated by `mxdev`. -You can configure your Zope instance as described in the section {ref}`manage-common-management-tasks-label`. +You can configure your Zope instance as described in the section {ref}`manage-configuration-with-cookiecutter-zope-instance-label`. diff --git a/docs/i18n-l10n/use-an-external-translation-service.md b/docs/i18n-l10n/use-an-external-translation-service.md index f396ca82f..a7d3ba27a 100644 --- a/docs/i18n-l10n/use-an-external-translation-service.md +++ b/docs/i18n-l10n/use-an-external-translation-service.md @@ -95,7 +95,7 @@ class TranslateUsingMyService(BrowserView): ``` ```{note} -Due to the way that the Google Translate integration is built in `plone.app.multilingual`, you will need to enter something in the {guilable}`Google Translate API Key` field in the {guilable}`Multilingual Settings` +Due to the way that the Google Translate integration is built in `plone.app.multilingual`, you will need to enter something in the {guilabel}`Google Translate API Key` field in the {guilabel}`Multilingual Settings` control panel of your site. It doesn't need to be a valid Google Translate API Key; it can be a random string. ``` From 0b236ab833383d38797930923d66687af2466c0b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 8 Oct 2024 23:03:21 -0700 Subject: [PATCH 446/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 78ae6dd10..436c45d45 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 78ae6dd107cc4bda9a5080640fb905745c6c120a +Subproject commit 436c45d457470355fcfd64ef7a74f86745b2b9d8 From 2738abce4f4ad2f9da8b5696b6d0f61ead7062c7 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 9 Oct 2024 00:56:07 -0700 Subject: [PATCH 447/810] Add more mr.bob, bobtemplates.plone, plonecli references (#1734) * Add more references. See https://github.com/plone/cookieplone-templates/pull/63/ * Incorporate @erral's suggestions, I think --- docs/classic-ui/mockup.md | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/docs/classic-ui/mockup.md b/docs/classic-ui/mockup.md index 15a5fbe4e..a68167cd3 100644 --- a/docs/classic-ui/mockup.md +++ b/docs/classic-ui/mockup.md @@ -18,24 +18,49 @@ View the [interactive documentation of Mockup](https://plone.github.io/mockup/). ## Get started -[bobtemplates.plone](https://github.com/plone/bobtemplates.plone) provides [mr.bob](https://mrbob.readthedocs.io/en/latest/) templates to generate packages for Plone projects. -[plonecli](https://github.com/plone/plonecli) provides a command line client for bobtemplates.plone. +[`bobtemplates.plone`](https://github.com/plone/bobtemplates.plone) provides [`mr.bob`](https://github.com/collective/mr.bob) templates to generate packages for Plone projects. +[Plone CLI (`plonecli`)](https://github.com/plone/plonecli) provides a command line client for `bobtemplates.plone`. -Install plonecli into your Python user packages to make it available to all your projects. +Install {term}`plonecli` into your Python user packages to make it available to all your projects. ```shell pip install plonecli --user ``` -Create a theme package add-on with {term}`plonecli`. +Create an add-on package with `plonecli`. ```shell -plonecli add mockup_pattern +plonecli add project.addon +``` + +This will create a package `project.addon`, which you can install in your Plone site. + +You can `cd` to the project, and add features to that package, such as content types, behaviors, control panels, or REST API endpoints. + +```shell +cd project.addon +plonecli add content_type +plonecli add behavior +plonecli theme_barceloneta +``` + +Each of the features asks several questions to create the desired feature, customized to your preferences. + +You can check the full list of available features using the `-l` parameter: + +```shell +plonecli -l ``` ## References +- [`bobtemplates.plone` documentation](https://bobtemplatesplone.readthedocs.io/en/latest/) +- [`mr.bob` documentation](https://mrbob.readthedocs.io/en/latest/) +- [Plone CLI documentation](https://plonecli.readthedocs.io/en/latest/) +- [`bobtemplates.plone` repository](https://github.com/plone/bobtemplates.plone) +- [`mr.bob` repository](https://github.com/collective/mr.bob) +- [Plone CLI (`plonecli`) repository](https://github.com/plone/plonecli) - {ref}`v60-mockup-resource-registry-label` in Plone 6.0 - [Mockup repository on GitHub](https://github.com/plone/mockup) - [Patternslib](https://patternslib.com/) From b76b6e69ee1832625c7b55ca4bb7d0ec1900d186 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 9 Oct 2024 11:36:03 -0700 Subject: [PATCH 448/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 436c45d45..0dcfb588e 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 436c45d457470355fcfd64ef7a74f86745b2b9d8 +Subproject commit 0dcfb588ec566a40d609fab1cb77e821c632bf08 From 77b00fc6cc31293d3559666d7426f63c93eea5de Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 9 Oct 2024 12:45:03 -0700 Subject: [PATCH 449/810] Align the Storybook build with Volto (#1739) --- .github/workflows/build_deploy.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build_deploy.yml b/.github/workflows/build_deploy.yml index c62f25b7f..ad0983b10 100644 --- a/.github/workflows/build_deploy.yml +++ b/.github/workflows/build_deploy.yml @@ -43,11 +43,9 @@ jobs: with: node-version: ${{ env.node-version }} - - uses: pnpm/action-setup@v3 - name: Install pnpm - with: - version: 8 - run_install: false + - name: Enable corepack + shell: bash + run: corepack enable - name: Get pnpm store directory shell: bash From 7f23c3efefc6e328a34efe2e97851eb7ce3b1eb9 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 10 Oct 2024 00:29:42 -0700 Subject: [PATCH 450/810] Add reference to Volto i18n (#1737) Co-authored-by: Mikel Larreategi --- docs/i18n-l10n/contributing-translations.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/i18n-l10n/contributing-translations.md b/docs/i18n-l10n/contributing-translations.md index d93c1c1ef..ef73751d7 100644 --- a/docs/i18n-l10n/contributing-translations.md +++ b/docs/i18n-l10n/contributing-translations.md @@ -80,6 +80,10 @@ The process of translating the Volto frontend is the following. 5. Commit your changes, and create a pull request. +```{seealso} +{doc}`Volto frontend development internationalization ` +``` + (contributing-weblate-for-translations)= ## Weblate for translations From c05c5e3deb73df7ddb69be7d53991dc07b07514e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 10 Oct 2024 01:01:37 -0700 Subject: [PATCH 451/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 0dcfb588e..c962404dd 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 0dcfb588ec566a40d609fab1cb77e821c632bf08 +Subproject commit c962404ddee1dd0089d91b040f31a499f8ed01d8 From 81763393fe731f80ec1b0001f5a8bbadea6faac3 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 24 Oct 2024 23:31:40 -0700 Subject: [PATCH 452/810] Update tips submodules/plone.api submodules/plone.restapi submodules/volto --- submodules/plone.api | 2 +- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/submodules/plone.api b/submodules/plone.api index ae64739ff..0526ecddd 160000 --- a/submodules/plone.api +++ b/submodules/plone.api @@ -1 +1 @@ -Subproject commit ae64739ff0cc5cc88fa19beafc875456268014bf +Subproject commit 0526ecddd21ba08a3a8753cf1a2ca4611750d2b3 diff --git a/submodules/plone.restapi b/submodules/plone.restapi index f68fab7ea..dcdb41bca 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit f68fab7ea3209a096423d8567fa7f70a93786c7a +Subproject commit dcdb41bcab60b4bc32fa5c685f146b40d88c33bd diff --git a/submodules/volto b/submodules/volto index c962404dd..4b690be37 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit c962404ddee1dd0089d91b040f31a499f8ed01d8 +Subproject commit 4b690be37c317fb87160ff1d26fd05cb92cd30e7 From 11ecd0818614c5bced2dcaa9e42e35121be4470f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 25 Oct 2024 03:54:18 -0700 Subject: [PATCH 453/810] Move Classic UI immediately after Volto UI --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 0ab3dbaca..40d53f511 100644 --- a/docs/index.md +++ b/docs/index.md @@ -36,9 +36,9 @@ manage/index upgrade/index deployment/index volto/index +classic-ui/index plone.restapi/docs/source/index backend/index -classic-ui/index i18n-l10n/index conceptual-guides/index contributing/index From 55d3ca2c18ee18befecd537198611702a7a54e99 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 25 Oct 2024 04:57:58 -0700 Subject: [PATCH 454/810] Fix broken links --- docs/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/glossary.md b/docs/glossary.md index d637dca9b..66b15dd5b 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -523,7 +523,7 @@ manual `.po` entries Entries which cannot be detected by an automatic code scan. react-intl - A library that is part of [Format.JS](https://formatjs.io/docs/getting-started/installation) which helps developers set up their applications for internationalization. + A library that is part of [Format.JS](https://formatjs.github.io/docs/getting-started/installation) which helps developers set up their applications for internationalization. WSGI The Web Server Gateway Interface (WSGI, pronounced _WIZ-ghee_) is a simple calling convention for web servers to forward requests to web applications or frameworks written in the Python programming language. From 2b8cdb41b97ceb1b8c787a1f139d2889d1370131 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 25 Oct 2024 04:59:43 -0700 Subject: [PATCH 455/810] Update tips submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 4b690be37..8427cfb08 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 4b690be37c317fb87160ff1d26fd05cb92cd30e7 +Subproject commit 8427cfb087eab4899195134063701052777de59a From 1b8133fd1ed68466d717e7e76c20217de5d6c8c9 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 25 Oct 2024 06:03:58 -0700 Subject: [PATCH 456/810] Ignore https://opensource.org/ on linkcheck (#1745) --- docs/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/conf.py b/docs/conf.py index 44d4834df..43fd357ff 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -88,6 +88,7 @@ r"https://github.com/orgs/plone/teams/", # requires auth r"https://github.com/plone/documentation/issues/new/choose", # requires auth r"https://github.com/plone/volto/issues/new/choose", # requires auth + r"https://opensource.org/", # requires auth # Ignore github.com pages with anchors r"https://github.com/.*#.*", # Ignore other specific anchors From f4bd309cb3018d96b84097644e30d294d5c201b7 Mon Sep 17 00:00:00 2001 From: David Glick Date: Fri, 25 Oct 2024 09:44:15 -0700 Subject: [PATCH 457/810] Update volto tip --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 8427cfb08..bd591ca11 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 8427cfb087eab4899195134063701052777de59a +Subproject commit bd591ca11e4a875864aa7ecf0a73f5f2f6e8153e From c67ea35e4a67b161bec04b0da24ac7b0b5abef02 Mon Sep 17 00:00:00 2001 From: David Glick Date: Fri, 25 Oct 2024 09:53:43 -0700 Subject: [PATCH 458/810] Update redirected link --- docs/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/glossary.md b/docs/glossary.md index d637dca9b..eeb6c3aa1 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -523,7 +523,7 @@ manual `.po` entries Entries which cannot be detected by an automatic code scan. react-intl - A library that is part of [Format.JS](https://formatjs.io/docs/getting-started/installation) which helps developers set up their applications for internationalization. + A library that is part of [Format.JS](https://formatjs.github.io/) which helps developers set up their applications for internationalization. WSGI The Web Server Gateway Interface (WSGI, pronounced _WIZ-ghee_) is a simple calling convention for web servers to forward requests to web applications or frameworks written in the Python programming language. From 1ea91bda33b81817fd95f85b74d4d60bf8fc1f20 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 25 Oct 2024 14:31:41 -0700 Subject: [PATCH 459/810] Add link to react-intl API docs overview. --- docs/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/glossary.md b/docs/glossary.md index 66b15dd5b..2ad459d73 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -523,7 +523,7 @@ manual `.po` entries Entries which cannot be detected by an automatic code scan. react-intl - A library that is part of [Format.JS](https://formatjs.github.io/docs/getting-started/installation) which helps developers set up their applications for internationalization. + [`react-intl`](https://formatjs.github.io/docs/react-intl) is a library that is part of [Format.JS](https://formatjs.github.io/) which helps developers set up their applications for internationalization. WSGI The Web Server Gateway Interface (WSGI, pronounced _WIZ-ghee_) is a simple calling convention for web servers to forward requests to web applications or frameworks written in the Python programming language. From dda3bd49661eae122a581d4a40ca7dbd86406ccf Mon Sep 17 00:00:00 2001 From: David Glick Date: Fri, 25 Oct 2024 14:55:29 -0700 Subject: [PATCH 460/810] Start Admin Guide --- .../containers/examples/haproxy-plone-zeo.md | 0 .../containers/examples/index.md | 0 .../containers/examples/nginx-plone.md | 0 .../examples/nginx-volto-plone-postgresql.md | 0 .../examples/nginx-volto-plone-zeo.md | 0 .../containers/examples/nginx-volto-plone.md | 0 .../examples/traefik-volto-plone-varnish.md | 0 .../containers/images/backend.md | 0 .../containers/images/frontend.md | 0 .../containers/images/index.md | 0 .../containers/images/zeo.md | 0 .../containers/index.md | 2 +- docs/admin-guide/index.md | 43 ++++ docs/admin-guide/install-buildout.md | 105 ++++++++ .../install-cookieplone.md} | 19 +- docs/admin-guide/install-pip.md | 88 +++++++ .../install-plonestarter.md} | 18 +- .../index.md => admin-guide/upgrade.md} | 4 +- docs/classic-ui/theming/barceloneta.md | 2 - .../make-build-backend-walk-through.md | 2 +- docs/conceptual-guides/package-management.md | 2 +- docs/conf.py | 6 +- docs/contributing/index.md | 2 +- docs/glossary.md | 4 + docs/index.md | 2 +- docs/install/create-project-classic-ui.md | 229 ------------------ docs/install/index.md | 81 ++++--- docs/manage/backend.md | 2 +- 28 files changed, 322 insertions(+), 289 deletions(-) rename docs/{install => admin-guide}/containers/examples/haproxy-plone-zeo.md (100%) rename docs/{install => admin-guide}/containers/examples/index.md (100%) rename docs/{install => admin-guide}/containers/examples/nginx-plone.md (100%) rename docs/{install => admin-guide}/containers/examples/nginx-volto-plone-postgresql.md (100%) rename docs/{install => admin-guide}/containers/examples/nginx-volto-plone-zeo.md (100%) rename docs/{install => admin-guide}/containers/examples/nginx-volto-plone.md (100%) rename docs/{install => admin-guide}/containers/examples/traefik-volto-plone-varnish.md (100%) rename docs/{install => admin-guide}/containers/images/backend.md (100%) rename docs/{install => admin-guide}/containers/images/frontend.md (100%) rename docs/{install => admin-guide}/containers/images/index.md (100%) rename docs/{install => admin-guide}/containers/images/zeo.md (100%) rename docs/{install => admin-guide}/containers/index.md (97%) create mode 100644 docs/admin-guide/index.md create mode 100644 docs/admin-guide/install-buildout.md rename docs/{install/create-project-cookieplone.md => admin-guide/install-cookieplone.md} (94%) create mode 100644 docs/admin-guide/install-pip.md rename docs/{install/create-project.md => admin-guide/install-plonestarter.md} (93%) rename docs/{upgrade/index.md => admin-guide/upgrade.md} (90%) delete mode 100644 docs/install/create-project-classic-ui.md diff --git a/docs/install/containers/examples/haproxy-plone-zeo.md b/docs/admin-guide/containers/examples/haproxy-plone-zeo.md similarity index 100% rename from docs/install/containers/examples/haproxy-plone-zeo.md rename to docs/admin-guide/containers/examples/haproxy-plone-zeo.md diff --git a/docs/install/containers/examples/index.md b/docs/admin-guide/containers/examples/index.md similarity index 100% rename from docs/install/containers/examples/index.md rename to docs/admin-guide/containers/examples/index.md diff --git a/docs/install/containers/examples/nginx-plone.md b/docs/admin-guide/containers/examples/nginx-plone.md similarity index 100% rename from docs/install/containers/examples/nginx-plone.md rename to docs/admin-guide/containers/examples/nginx-plone.md diff --git a/docs/install/containers/examples/nginx-volto-plone-postgresql.md b/docs/admin-guide/containers/examples/nginx-volto-plone-postgresql.md similarity index 100% rename from docs/install/containers/examples/nginx-volto-plone-postgresql.md rename to docs/admin-guide/containers/examples/nginx-volto-plone-postgresql.md diff --git a/docs/install/containers/examples/nginx-volto-plone-zeo.md b/docs/admin-guide/containers/examples/nginx-volto-plone-zeo.md similarity index 100% rename from docs/install/containers/examples/nginx-volto-plone-zeo.md rename to docs/admin-guide/containers/examples/nginx-volto-plone-zeo.md diff --git a/docs/install/containers/examples/nginx-volto-plone.md b/docs/admin-guide/containers/examples/nginx-volto-plone.md similarity index 100% rename from docs/install/containers/examples/nginx-volto-plone.md rename to docs/admin-guide/containers/examples/nginx-volto-plone.md diff --git a/docs/install/containers/examples/traefik-volto-plone-varnish.md b/docs/admin-guide/containers/examples/traefik-volto-plone-varnish.md similarity index 100% rename from docs/install/containers/examples/traefik-volto-plone-varnish.md rename to docs/admin-guide/containers/examples/traefik-volto-plone-varnish.md diff --git a/docs/install/containers/images/backend.md b/docs/admin-guide/containers/images/backend.md similarity index 100% rename from docs/install/containers/images/backend.md rename to docs/admin-guide/containers/images/backend.md diff --git a/docs/install/containers/images/frontend.md b/docs/admin-guide/containers/images/frontend.md similarity index 100% rename from docs/install/containers/images/frontend.md rename to docs/admin-guide/containers/images/frontend.md diff --git a/docs/install/containers/images/index.md b/docs/admin-guide/containers/images/index.md similarity index 100% rename from docs/install/containers/images/index.md rename to docs/admin-guide/containers/images/index.md diff --git a/docs/install/containers/images/zeo.md b/docs/admin-guide/containers/images/zeo.md similarity index 100% rename from docs/install/containers/images/zeo.md rename to docs/admin-guide/containers/images/zeo.md diff --git a/docs/install/containers/index.md b/docs/admin-guide/containers/index.md similarity index 97% rename from docs/install/containers/index.md rename to docs/admin-guide/containers/index.md index 5aef61ee6..d5475b532 100644 --- a/docs/install/containers/index.md +++ b/docs/admin-guide/containers/index.md @@ -14,7 +14,7 @@ myst: The Plone 6 images have all the system requirements, prerequisites, and Plone 6 already installed, except those requirements needed for running the container engine itself. Using containers is the easiest way to deploy Plone 6. -Containers may also be used when {doc}`creating a Plone project <../create-project>` and {doc}`contributing to Plone `. +Containers may also be used when {doc}`creating a Plone project `. The Plone 6 container images are compliant with the [Open Container Initiative (OCI)](https://opencontainers.org/). They should work with any OCI-compliant container engine for developing, managing, and running Plone 6 images. diff --git a/docs/admin-guide/index.md b/docs/admin-guide/index.md new file mode 100644 index 000000000..0d701262e --- /dev/null +++ b/docs/admin-guide/index.md @@ -0,0 +1,43 @@ +--- +myst: + html_meta: + "description": "How to install, operate, configure, and deploy Plone 6" + "property=og:description": "How to install, operate, configure, and deploy Plone 6" + "property=og:title": "Admin Guide" + "keywords": "Plone 6, admin, install, configuration, deploy" +--- + +(admin-index-label)= + +# Admin Guide + +In this part of the documentation, you can find how to install, operate, configure, and deploy Plone. + + +```{toctree} +:caption: Install +:maxdepth: 1 + +install-cookieplone +install-buildout +install-pip +install-plonestarter +``` + +```{toctree} +:caption: Operate +:maxdepth: 1 + +upgrade +``` + +```{toctree} +:maxdepth: 1 +:caption: Deploy + +containers/index +``` + + +To do: +- move and update Manage section diff --git a/docs/admin-guide/install-buildout.md b/docs/admin-guide/install-buildout.md new file mode 100644 index 000000000..dbf8a2b3b --- /dev/null +++ b/docs/admin-guide/install-buildout.md @@ -0,0 +1,105 @@ +--- +myst: + html_meta: + "description": "Install Plone with Buildout" + "property=og:description": "Install Plone with Buildout" + "property=og:title": "Install Plone with Buildout" + "keywords": "Plone 6, install, Classic UI, buildout" +--- + +(install-buildout-label)= + +# Install Plone with Buildout + +This chapter describes how you can install Plone using {term}`Buildout`. + +This is one way to install Plone with the Classic UI. +Using Buildout will be the most familiar approach for admins who have experience with Plone 3, 4, or 5. + +```{seealso} +For other installation options, see {ref}`get-started-install-label`. +``` + +(install-buildout-prerequisites)= + +## Prerequisites + +- Python 3.10 or greater + +On Debian-based Linux systems you can install Python with the following command: + +```shell +sudo apt install python3.12 python3.12-dev python3.12-venv +``` + +## Installation + +Select a directory of your choice: + +```shell +mkdir -p /opt/plone && cd /opt/plone +``` + +Create a Python virtual environment: + +```shell +python3 -m venv . +``` + +Install the minimal Python packages needed in order to run Buildout: + +```shell +bin/pip install -r https://dist.plone.org/release/6-latest/requirements.txt +``` + +Create a `buildout.cfg` file in your directory with the following contents: + +```cfg +[buildout] +extends = + https://dist.plone.org/release/6-latest/versions.cfg + +parts = + instance + +[instance] +recipe = plone.recipe.zope2instance +user = admin:admin +http-address = 8080 +eggs = + Plone +``` + +Run buildout: + +```shell +bin/buildout +``` + +## Run Plone in foreground mode + +Start the instance for a quick test in foreground mode: + +```shell +bin/instance fg +``` + +Your instance starts in foreground mode, which is only advisable for troubleshooting or for local demonstration purposes. + +Now you can call the url `http://localhost:8080` in your browser and you can add a **Classic UI Plone site**. + +## Start Plone as a background service + +Start the instance: + +```shell +bin/instance start +``` + +## Stop Plone as a background service + +Stop the instance: + +```shell +bin/instance stop +``` diff --git a/docs/install/create-project-cookieplone.md b/docs/admin-guide/install-cookieplone.md similarity index 94% rename from docs/install/create-project-cookieplone.md rename to docs/admin-guide/install-cookieplone.md index 5f2122aff..651a1941d 100644 --- a/docs/install/create-project-cookieplone.md +++ b/docs/admin-guide/install-cookieplone.md @@ -1,25 +1,28 @@ --- myst: html_meta: - "description": "Create a Plone project with the Volto frontend (development or pre-release)" - "property=og:description": "Create a Plone project with the Volto frontend (development or pre-release)" - "property=og:title": "Create a Plone project with the Volto frontend (development or pre-release)" + "description": "Install Plone with Cookieplone" + "property=og:description": "Install Plone with Cookieplone" + "property=og:title": "Install Plone with Cookieplone" "keywords": "Plone, Plone 6, Volto, create, project, install, Cookieplone" --- -(create-project-cookieplone-label)= +(install-cookieplone-label)= -# Create a project with Volto (development or pre-release) +# Install Plone with Cookieplone -This chapter describes how you can create a web application using the latest **development release** version of Plone with **Volto 18 or later** for the frontend, while having full control over its development and deployment. +This chapter describes how you can create a web application using the {term}`Cookieplone` template. + +This template is the recommended way to start a new Plone project using the Volto frontend. +It also includes tools for development and deployment. ```{seealso} -For other installation options, see {doc}`/install/index`. +For other installation options, see {ref}`get-started-install-label`. ``` ```{versionadded} Volto 18.0.0-alpha.43 -{term}`Cookieplone` is now the method to create a Plone project with unstable versions of Volto, version 18.0.0-alpha.43 and above. +{term}`Cookieplone` was added as the recommended template to create a Plone project with Volto starting in Volto 18.0.0-alpha.43 and above. ``` diff --git a/docs/admin-guide/install-pip.md b/docs/admin-guide/install-pip.md new file mode 100644 index 000000000..5dcb2ae4a --- /dev/null +++ b/docs/admin-guide/install-pip.md @@ -0,0 +1,88 @@ +--- +myst: + html_meta: + "description": "Install Plone with pip" + "property=og:description": "Install Plone with pip" + "property=og:title": "Install Plone with pip" + "keywords": "Plone 6, install, Classic UI, pip" +--- + +(install-pip-label)= + +# Install Plone with pip + +This chapter describes how you can install Plone using {term}`pip`. + +This is one way to install Plone with the Classic UI. +It provides a basic installation without many additional tools to help with development. + +```{seealso} +For other installation options, see {ref}`get-started-install-label`. +``` + +## Prerequisites + +- Python 3.10 or greater + +On Debian-based systems you can install Python with following command: + +```shell +sudo apt install python3.12 python3.12-dev python3.12-venv +``` + +## Installation + +Select a directory of your choice: + +```shell +mkdir -p /opt/plone +cd /opt/plone +``` + +Create a Python virtual environment: + +```shell +python3 -m venv . +``` + +Install Plone and a helper package: + +```shell +bin/pip install -c https://dist.plone.org/release/6.0-latest/constraints.txt Plone pipx +``` + +## Create a Zope instance + +Create a file `instance.yaml` with the following contents: + +```yaml +# please change the password to a secure token! +default_context: + initial_user_name: "admin" + initial_user_password: "admin" + wsgi_listen: "localhost:8080" + debug_mode: false + verbose_security: false + db_storage: "direct" + environment: { + "zope_i18n_compile_mo_files": true, + } +``` + +Now run the {term}`cookiecutter` tool to create configuration for a Zope instance: + +``` +bin/pipx run cookiecutter -f --no-input --config-file instance.yaml gh:plone/cookiecutter-zope-instance +``` + +## Start Plone in foreground mode + +Start the instance for a quick test: + +```shell +bin/runwsgi -v instance/etc/zope.ini +``` + +Your instance starts in foreground mode, which is only advisable for troubleshooting or for local demonstration purposes. + +Now you can call the url `http://localhost:8080` in your browser and you can add a **Classic UI Plone site**. diff --git a/docs/install/create-project.md b/docs/admin-guide/install-plonestarter.md similarity index 93% rename from docs/install/create-project.md rename to docs/admin-guide/install-plonestarter.md index 7e7ab358f..7e8a25317 100644 --- a/docs/install/create-project.md +++ b/docs/admin-guide/install-plonestarter.md @@ -1,23 +1,27 @@ --- myst: html_meta: - "description": "Create a Plone project with the Volto frontend (stable release)" - "property=og:description": "Create a Plone project with the Volto frontend (stable release)" - "property=og:title": "Create a Plone project with the Volto frontend (stable release)" + "description": "Install Plone with cookiecutter-plone-starter (deprecated)" + "property=og:description": "Install Plone with cookiecutter-plone-starter (deprecated)" + "property=og:title": "Install Plone with cookiecutter-plone-starter (deprecated)" "keywords": "Plone, Plone 6, Volto, create, project, install, cookiecutter" --- (create-a-project-label)= -# Create a project with Volto (stable release) +# Install Plone with cookiecutter-plone-starter (deprecated) -This chapter describes how you can create a web application using the current **stable release** version of Plone with **Volto 17 or earlier** for the frontend, while having full control over its development and deployment. +This chapter describes how you can create a web application using the {term}`cookiecutter-plone-starter` template. -```{seealso} -For other installation options, see {doc}`/install/index`. +```{deprecated} +This way of installing Plone is now deprecated. +It was the recommended way to start a new Plone project with **Plone 6.0** and **Volto 17 or earlier**. +For other installation options, see {ref}`get-started-install-label`. ``` +This template creates a web application using Plone with the Volto frontend, along with tools for development and deployment. + (install-packages-system-requirements-label)= diff --git a/docs/upgrade/index.md b/docs/admin-guide/upgrade.md similarity index 90% rename from docs/upgrade/index.md rename to docs/admin-guide/upgrade.md index b211116b6..be78a1e7f 100644 --- a/docs/upgrade/index.md +++ b/docs/admin-guide/upgrade.md @@ -3,13 +3,13 @@ myst: html_meta: "description": "Plone 6 upgrade Guide" "property=og:description": "Plone 6 upgrade guide" - "property=og:title": "Plone 6 upgrade guide" + "property=og:title": "Upgrade Plone" "keywords": "Plone, upgrade" --- (upgrade-guide-label)= -# Upgrade guide +# Upgrade Plone Plone has several components, each of which have their own upgrade guides: diff --git a/docs/classic-ui/theming/barceloneta.md b/docs/classic-ui/theming/barceloneta.md index 0080106f1..18c767c81 100644 --- a/docs/classic-ui/theming/barceloneta.md +++ b/docs/classic-ui/theming/barceloneta.md @@ -25,8 +25,6 @@ To create an add-on package with a Plone Classic UI theme, you need to install t - [Python (>=3.8)](https://www.python.org/) - [plonecli](https://pypi.org/project/plonecli/) -Read more about how to install prerequisites in {doc}`/install/create-project`. - (classic-ui-theming-barceloneta-create-a-classic-ui-theme-add-on-package-label)= diff --git a/docs/conceptual-guides/make-build-backend-walk-through.md b/docs/conceptual-guides/make-build-backend-walk-through.md index a39bc9cba..3c0ce4347 100644 --- a/docs/conceptual-guides/make-build-backend-walk-through.md +++ b/docs/conceptual-guides/make-build-backend-walk-through.md @@ -11,7 +11,7 @@ myst: # `make build-backend` details -This chapter assumes you have previously followed {doc}`/install/create-project`. +This chapter assumes you have previously followed {doc}`/admin-guide/install-plonestarter`. The `Makefile` at the root of your project invokes commands in `backend/Makefile`. Here are excerpts from `backend/Makefile` to show details of the `make build-backend` command. diff --git a/docs/conceptual-guides/package-management.md b/docs/conceptual-guides/package-management.md index 7e5dd4084..7e19bf175 100644 --- a/docs/conceptual-guides/package-management.md +++ b/docs/conceptual-guides/package-management.md @@ -61,4 +61,4 @@ You or your development tools, such as GNU Make, must perform that step. ```{todo} Why do we use pnpm? -``` \ No newline at end of file +``` diff --git a/docs/conf.py b/docs/conf.py index 43fd357ff..ca61b9e21 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -245,8 +245,12 @@ "contributing/plone-api": "/plone.api/contribute/index.html", "contributing/plone-restapi": "/plone.restapi/docs/source/contributing/index.html", "contributing/volto": "/volto/contributing/index.html", - "install/install-from-packages": "/install/create-project.html", + "install/containers/index": "/admin-guide/containers/index.html", + "install/create-project-cookieplone": "/admin-guide/install-cookieplone.html", + "install/create-project": "/admin-guide/install-plonestarter.html", + "install/install-from-packages": "/admin-guide/install-cookieplone.html", "manage/frontend": "/volto/addons/index.html", + "upgrade/index": "/admin-guide/upgrade.html", } diff --git a/docs/contributing/index.md b/docs/contributing/index.md index a5c78b3f0..84ad3a044 100644 --- a/docs/contributing/index.md +++ b/docs/contributing/index.md @@ -13,7 +13,7 @@ myst: This part of the documentation describes how to contribute to Plone, including all its projects and repositories under the Plone GitHub organization. -If instead you want to create a web application project using Plone, see {doc}`/install/create-project`. +If instead you want to create a web application project using Plone, see {ref}`get-started-install-label`. To contribute to any project in Plone, you must follow the policies of the [Plone Foundation](https://plone.org/foundation), [Plone GitHub organization](https://github.com/plone/) and the specific project. diff --git a/docs/glossary.md b/docs/glossary.md index d637dca9b..c1fe40db8 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -21,6 +21,10 @@ AWS Barceloneta The default theme for Plone 5. +Buildout + [Buildout](https://github.com/buildout/buildout/) is a Python-based tool for building and assembling applications from multiple parts, based on a configuration file. + It was the most common way of installing Plone 3, 4, and 5, and can still be used with Plone 6. + CMS Content Management System diff --git a/docs/index.md b/docs/index.md index 0ab3dbaca..2a7b9cba6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -32,8 +32,8 @@ Read the [documentation for the previous version, Plone 5](https://5.docs.plone. overview/index install/index +admin-guide/index manage/index -upgrade/index deployment/index volto/index plone.restapi/docs/source/index diff --git a/docs/install/create-project-classic-ui.md b/docs/install/create-project-classic-ui.md deleted file mode 100644 index 1826a1056..000000000 --- a/docs/install/create-project-classic-ui.md +++ /dev/null @@ -1,229 +0,0 @@ ---- -myst: - html_meta: - "description": "Create a Plone project with Classic UI (stable release)" - "property=og:description": "Create a Plone project with Classic UI (stable release)" - "property=og:title": "Create a Plone project with Classic UI (stable release)" - "keywords": "Plone, Plone 6, Classic UI, create, project, install, cookiecutter, Cookieplone" ---- - - -(create-a-project-classic-ui-label)= - -# Create a project with Classic UI (stable release) - -This chapter describes how you can create a web application using the current **stable release** version of Plone with **Classic UI** for the frontend, while having full control over its development and deployment. - -```{seealso} -For other installation options, see {doc}`/install/index`. -``` - - -## System requirements - -Plone 6 has both hardware requirements and software prerequisites. - - -### Hardware requirements - -```{include} /_inc/_hardware-requirements.md -``` - -### Prerequisites for installation - -```{include} ../volto/contributing/install-operating-system.md -``` - -- Python {SUPPORTED_PYTHON_VERSIONS} -- {term}`pipx` -- {term}`GNU make` -- {term}`Git` - - -#### Python - -```{include} /_inc/_install-python.md -``` - - -#### pipx - -Install {term}`pipx`. - -```shell -pip install pipx -``` - - -#### Make - -```{include} ../volto/contributing/install-make.md -``` - - -#### Git - -```{include} ../volto/contributing/install-git.md -``` - - -## Generate the project - -After satisfying the prerequisites, generate the project. - -```shell -pipx run cookieplone backend_addon -``` - -You will be presented with a series of prompts. -You can accept the default values in square brackets (`[default-option]`) by hitting the {kbd}`Enter` key, or enter your preferred values. -For ease of documentation, we will use the default values. - -```{tip} -See the cookiecutter's README for how to [Use options to avoid prompts](https://github.com/collective/cookiecutter-plone-starter/?tab=readme-ov-file#use-options-to-avoid-prompts). -``` - -```{important} -For {guilabel}`Project Slug`, you must not use any of the Plone core package names listed in [`constraints.txt`](https://dist.plone.org/release/6.0-latest/constraints.txt). -Note that pip normalizes these names, so `plone.volto` and `plone-volto` are the same package. -``` - -```console -% pipx run cookieplone backend_addon -╭─────────────────────────────────── cookieplone ────────────────────────────────────╮ -│ │ -│ .xxxxxxxxxxxxxx. │ -│ ;xxxxxxxxxxxxxxxxxxxxxx; │ -│ ;xxxxxxxxxxxxxxxxxxxxxxxxxxxx; │ -│ xxxxxxxxxx xxxxxxxxxx │ -│ xxxxxxxx. .xxxxxxxx │ -│ xxxxxxx xxxxxxx: xxxxxxx │ -│ :xxxxxx xxxxxxxxxx xxxxxx: │ -│ :xxxxx+ xxxxxxxxxxx +xxxxx: │ -│ .xxxxx. :xxxxxxxxxx .xxxxx. │ -│ xxxxx+ ;xxxxxxxx +xxxxx │ -│ xxxxx +xx. xxxxx. │ -│ xxxxx: .xxxxxxxx :xxxxx │ -│ xxxxx .xxxxxxxxxx xxxxx │ -│ xxxxx xxxxxxxxxxx xxxxx │ -│ xxxxx .xxxxxxxxxx xxxxx │ -│ xxxxx: .xxxxxxxx :xxxxx │ -│ .xxxxx ;xx. ... xxxxx. │ -│ xxxxx+ :xxxxxxxx +xxxxx │ -│ .xxxxx. :xxxxxxxxxx .xxxxx. │ -│ :xxxxx+ xxxxxxxxxxx ;xxxxx: │ -│ :xxxxxx xxxxxxxxxx xxxxxx: │ -│ xxxxxxx xxxxxxx; xxxxxxx │ -│ xxxxxxxx. .xxxxxxxx │ -│ xxxxxxxxxx xxxxxxxxxx │ -│ ;xxxxxxxxxxxxxxxxxxxxxxxxxxxx+ │ -│ ;xxxxxxxxxxxxxxxxxxxxxx; │ -│ .xxxxxxxxxxxxxx. │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────╯ -╭─────────────────────────────────── Plone Addon ────────────────────────────────────╮ -│ Creating a new Plone Addon │ -╰────────────────────────────────────────────────────────────────────────────────────╯ - [1/7] Addon Title (Addon): - [2/7] A short description of your addon (A new addon for Plone): - [3/7] Author (Plone Community): - [4/7] Author E-mail (collective@plone.org): - [5/7] GitHub Username or Organization (collective): - [6/7] Python package name (collective.addon): - [7/7] Support headless Plone? - 1 - Yes - 2 - No - Choose from [1/2] (1): - -> Initialize Git repository -╭───────────────────────────── New addon was generated ──────────────────────────────╮ -│ │ -│ Addon │ -│ │ -│ Now, enter the repository run the code formatter with: │ -│ │ -│ make format │ -│ │ -│ start coding, and push to your organization. │ -│ │ -│ Sorry for the convenience, │ -│ The Plone Community. │ -│ │ -│ https://plone.org/ │ -╰────────────────────────────────────────────────────────────────────────────────────╯ -``` - - -## Install the project - -Change to your project directory. - -```shell -cd collective.addon -``` - -To install the project's dependencies, use the following command. - -```shell -make install -``` - -This will take a few minutes. -☕️ - -When the process completes successfully, it will exit with no message. - -```{include} /_inc/_install-pillow.md -``` - - -## Start Plone - -To start Plone, issue the following command. - -```shell -make start -``` - -The Plone backend server starts up and emits messages to the console. - -```console -2024-09-25 16:47:15,699 INFO [chameleon.config:39][MainThread] directory cache: //instance/var/cache. -2024-09-25 16:47:16,387 WARNING [ZODB.FileStorage:412][MainThread] Ignoring index for //instance/var/filestorage/Data.fs -2024-09-25 16:47:16,508 INFO [plone.restapi.patches:16][MainThread] PATCH: Disabled ZPublisher.HTTPRequest.ZopeFieldStorage.VALUE_LIMIT. This enables file uploads larger than 1MB. -2024-09-25 16:47:17,018 INFO [plone.volto:23][MainThread] Aliasing collective.folderish classes to plone.volto classes. -2024-09-25 16:47:17,760 INFO [Zope:42][MainThread] Ready to handle requests -Starting server in PID 20912. -2024-09-25 16:47:17,772 INFO [waitress:486][MainThread] Serving on http://[::1]:8080 -2024-09-25 16:47:17,772 INFO [waitress:486][MainThread] Serving on http://127.0.0.1:8080 -``` - -You can stop the site with {kbd}`ctrl-c`. - - -## Create Classic UI Plone site - -While the Plone backend server is running, open a browser and visit the following URL. - -http://localhost:8080 - -```{image} /_static/plone-classic-ui-landing-page.png -:class: figure -:alt: Plone Classic UI landing page -``` - -Click the button {guilabel}`Create Classic UI Plone site` to do exactly that. - -Use the username and password of `admin` to authenticate. -You will be redirected to the Create a Plone site page. - -```{image} /_static/plone-classic-ui-site-page.png -:class: figure -:alt: Plone Classic UI site page -``` - -Enter values for {guilabel}`Path identifier`, {guilabel}`Title`, {guilabel}`Language`, and {guilabel}`Default timezone`. -The default values are usually good. - -Click the button {guilabel}`Create Plone site`. - -You will be redirected to the Plone site you just created. diff --git a/docs/install/index.md b/docs/install/index.md index 1f8c95ce7..30ed2eaa6 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -1,59 +1,72 @@ --- myst: html_meta: - "description": "Install Plone 6" - "property=og:description": "Install Plone 6" - "property=og:title": "Install Plone 6" + "description": "Get started with Plone 6" + "property=og:description": "Get started with Plone 6" + "property=og:title": "Get started" "keywords": "Plone 6, install, overview" --- -(install-index-label)= +(get-started-label)= -# Install +# Get started -In this part of the documentation, you can find how to install Plone to either create a Plone project or contribute to a Plone package. -You can also {ref}`try a Plone demo `. +This part of the documentation helps you find the best way to get started with Plone, depending on what you want to do. +```{contents} I'd like to... +:local: true +``` + + +(get-started-try-plone-label)= + +## Try a Plone demo + +Choose a version to demo. + +- [Plone 6 with Volto frontend](https://demo.plone.org/) +- [Plone 6 with Classic UI](https://classic.demo.plone.org/login?came_from=/en) -(install-index-getting-started-label)= -## Get started +(get-started-install-label)= -Choose an option to get started with Plone. -If you are following a [Plone training](https://training.plone.org/), it should specify which option to choose. +## Install Plone -{doc}`create-project` -: This option is for developers who want to create a web application using the current **stable release** version of Plone with **Volto 17 or earlier** for the frontend. +First, choose a Plone frontend. [TODO: add link to explanation of how to choose] +(If you are following a [Plone training](https://training.plone.org/), it should specify which option to choose.) -{doc}`create-project-classic-ui` -: This option is for developers who want to create a web application using the current **stable release** version of Plone with **Classic UI** for the frontend. +{doc}`/admin-guide/install-cookieplone` +: This is the recommended way to install Plone for a new project with the Volto frontend. -{doc}`create-project-cookieplone` -: This option is for developers who want to create a web application using the latest **development release** version of Plone with **Volto 18 or later** for the frontend. - The "development" version also means "pre-release", and includes alpha and beta versions and release candidates. - It allows developers to work with the cutting edge of Plone. - A development version is not stable, and features may change with little notice. +{doc}`/admin-guide/install-buildout` +: This is one way to install Plone with the Classic UI. + Using Buildout will be the most familiar way for admins who have experience with Plone 3, 4, or 5. -{doc}`Contribute to a Plone package ` +{doc}`/admin-guide/install-pip` +: This is one way to install Plone with the Classic UI. + It provides a basic installation without many additional tools to help with development. + +{doc}`/admin-guide/install-plonestarter` +: This was the recommended way to install Plone 6.0 for a new project with the Volto frontend. + +{doc}`Install Plone as a contributor ` : This option is for developers who want to contribute to Plone and its packages. -(install-index-try-plone-label)= +(get-started-learn-more-label)= -## Try a Plone demo +## Learn more about Plone -Choose a version to demo. +The {doc}`/conceptual-guides/index` explain concepts to help you understand Plone. -- [Plone 6 with Volto frontend](https://demo.plone.org/) -- [Plone 6 with Classic UI](https://classic.demo.plone.org/login?came_from=/en) +The community has created a set of [Plone trainings](https://training.plone.org/) which are hosted separately from the documentation. -```{toctree} -:maxdepth: 2 -:hidden: true +(get-started-contribute-label)= -create-project -create-project-classic-ui -create-project-cookieplone -containers/index -``` +## Contribute to Plone + +See the {doc}`Contributor Guide ` to learn how to participate in the Plone community and contribute to our open source software. + + +(install-index-getting-started-label)= diff --git a/docs/manage/backend.md b/docs/manage/backend.md index 8f24599d2..a8a16d59d 100644 --- a/docs/manage/backend.md +++ b/docs/manage/backend.md @@ -12,7 +12,7 @@ myst: # Manage Plone backend This part of the documentation describes how to perform common management tasks in the Plone backend. -This chapter assumes you have previously followed {doc}`/install/create-project`. +This chapter assumes you have previously followed {doc}`/admin-guide/install-plonestarter`. ## Manage add-ons and packages From 25390993390056638d00548e8597b9c5a5b1203a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 26 Oct 2024 04:54:34 -0700 Subject: [PATCH 461/810] Update glossary to align with Volto (#1747) See https://github.com/plone/volto/pull/6433 --- docs/glossary.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/glossary.md b/docs/glossary.md index 2ad459d73..2554b3cab 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -706,12 +706,6 @@ Windows Subsystem for Linux pnpm [pnpm](https://pnpm.io/) is a fast, disk space efficient package manager. -Guillotina - [Guillotina](https://guillotina.io/) is a full-stack data framework built on [AsyncIO](https://docs.python.org/3/library/asyncio.html). - -Nick - [Nick](https://nickcms.org/) is a headless content management system {term}`CMS` built with {term}`Node.js`. - predicate predicates In programming, a predicate is a test which returns `true` or `false`. From 2603852183bed15299396ce4c523f2a83f5247a0 Mon Sep 17 00:00:00 2001 From: David Glick Date: Sun, 27 Oct 2024 15:14:41 -0700 Subject: [PATCH 462/810] Add run-plone to admin guide --- docs/admin-guide/index.md | 1 + docs/admin-guide/run-plone.md | 93 +++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 docs/admin-guide/run-plone.md diff --git a/docs/admin-guide/index.md b/docs/admin-guide/index.md index 0d701262e..92302425d 100644 --- a/docs/admin-guide/index.md +++ b/docs/admin-guide/index.md @@ -28,6 +28,7 @@ install-plonestarter :caption: Operate :maxdepth: 1 +run-plone upgrade ``` diff --git a/docs/admin-guide/run-plone.md b/docs/admin-guide/run-plone.md new file mode 100644 index 000000000..ca341af06 --- /dev/null +++ b/docs/admin-guide/run-plone.md @@ -0,0 +1,93 @@ +--- +myst: + html_meta: + "description": "Run Plone" + "property=og:description": "Run Plone" + "property=og:title": "Run Plone" + "keywords": "Plone 6, run, start, command" +--- + +(run-plone-label)= + +# Run Plone + +This chapter shows the commands to run Plone after it is installed. + +There are different commands to run Plone, depending on which method you used to install Plone. + +## Run Plone in foreground mode + +Running Plone in foreground mode will show output in the terminal. This is recommended while developing a Plone site. + +with Cookieplone: +: ```shell + make backend-start + ``` + +with Buildout: +: ```shell + bin/instance fg + ``` + +with pip: +: ```shell + bin/runwsgi instance/etc/zope.ini + ``` + +with `cookiecutter-plone-starter`: +: ```shell + make start-backend + ``` + +## Run Volto + +If you are using the Volto frontend, you need to run the frontend in a separate process. + +with Cookieplone: +: ```shell + make frontend-start + ``` + +with `cookiecutter-plone-starter`: +: ```shell + make start-frontend + ``` + +## Start Plone as a background service + +with Buildout: +: ```shell + bin/instance start + ``` + +## Stop Plone as a background service + +with Buildout: +: ```shell + bin/instance stop + ``` + +## Run a debug console + +The debug console gives you a Python prompt with the Plone site's configuration loaded. +Use this for troubleshooting. + +with Cookieplone: +: ```shell + make -C backend console + ``` + +with Buildout: +: ```shell + bin/instance debug + ``` + +with pip: +: ```shell + bin/zconsole debug instance/etc/zope.ini + ``` + +with `cookiecutter-plone-starter`: +: ```shell + make -C backend debug + ``` From 323429e1b54fb5fd4f5dab199000dbf23d99caf0 Mon Sep 17 00:00:00 2001 From: David Glick Date: Sun, 27 Oct 2024 15:17:15 -0700 Subject: [PATCH 463/810] Add info about how to stop --- docs/admin-guide/run-plone.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/admin-guide/run-plone.md b/docs/admin-guide/run-plone.md index ca341af06..728daaee6 100644 --- a/docs/admin-guide/run-plone.md +++ b/docs/admin-guide/run-plone.md @@ -39,6 +39,9 @@ with `cookiecutter-plone-starter`: make start-backend ``` +For any of these commands, press {kbd}`ctrl-c` to stop the process. + + ## Run Volto If you are using the Volto frontend, you need to run the frontend in a separate process. @@ -53,6 +56,9 @@ with `cookiecutter-plone-starter`: make start-frontend ``` +For any of these commands, press {kbd}`ctrl-c` to stop the process. + + ## Start Plone as a background service with Buildout: @@ -91,3 +97,5 @@ with `cookiecutter-plone-starter`: : ```shell make -C backend debug ``` + +For any of these commands, press {kbd}`ctrl-d` to stop the process. From 2645edd72fa9a3688c58f6f2414f279f7e873606 Mon Sep 17 00:00:00 2001 From: David Glick Date: Sun, 27 Oct 2024 16:08:31 -0700 Subject: [PATCH 464/810] Add chapter about backend add-ons to admin guide --- docs/admin-guide/add-ons.md | 200 ++++++++++++++++++++++++++++++++++++ docs/admin-guide/index.md | 1 + 2 files changed, 201 insertions(+) create mode 100644 docs/admin-guide/add-ons.md diff --git a/docs/admin-guide/add-ons.md b/docs/admin-guide/add-ons.md new file mode 100644 index 000000000..61d8b532a --- /dev/null +++ b/docs/admin-guide/add-ons.md @@ -0,0 +1,200 @@ +--- +myst: + html_meta: + "description": "Install Plone Add-ons" + "property=og:description": "Install Plone Add-ons" + "property=og:title": "Install Plone Add-ons" + "keywords": "Plone 6, addon, add-on, package, plugin, extension, install" +--- + +(install-plone-addons-label)= + +# Install Plone Add-ons + +This chapter explains how to install {term}`add-ons ` as Python packages to extend the functionality of the Plone backend or Classic UI. + +```{note} +The Volto frontend has its own system of add-ons using Node.js packages. See {doc}`/volto/addons/index`. +``` + +## with Cookieplone + +Use the following instructions if you installed Plone with Cookieplone or `cookiecutter-plone-starter`. + +### Install an add-on + +Add a line with the name of your add-on in `backend/requirements.txt`. +This example uses [`collective.easyform`](https://pypi.org/project/collective.easyform/). + +``` +collective.easyform==4.2.1 +``` + +```{tip} +Including the add-on version ensures that it won't accidentally get upgraded in the future. +``` + +Also add the add-on to `zcml_package_includes` in {file}`backend/instance.yaml` to make sure its configuration will be loaded: + +```yaml +default_context: + zcml_package_includes: project_title, collective.easyform +``` + +Stop the backend with {kbd}`ctrl-c`. + +To actually download and install the new add-on, run: + +```shell +make backend-build +``` + +```{note} +If you installed Plone using `cookiecutter-plone-starter`, run `make build-backend` instead.` +``` + +Now restart the backend. + +In your web browser, and assuming you are currently logged in as `admin`, visit the URL http://localhost:8080/Plone/prefs_install_products_form. + +Then click the {guilabel}`Install` button next to your add-on to complete installation of the add-on. + +Some add-ons have configuration options. +To configure such add-ons, return to the {guilabel}`Site Setup` control panel. +At the bottom of the page, you should see the heading {guilabel}`Add-on Configuration`, and a control panel to configure the add-on that you just installed. + + +### Install an add-on from source + +An add-on can be installed from a source control system such as GitHub. + +Add a line with the name of your add-on in `backend/requirements.txt`. +This example uses [`collective.easyform`](https://pypi.org/project/collective.easyform/). + +``` +collective.easyform +``` + +```{note} +When installing an add-on from source, it's best to not pin a version, to make sure we use the version that's currently available in the source control system. +``` + +Also add the add-on to `zcml_package_includes` in {file}`backend/instance.yaml` to make sure its configuration will be loaded: + +```yaml +default_context: + zcml_package_includes: project_title, collective.easyform +``` + +Finally, add the package's source to {file}`mx.ini`: + +```cfg +[collective.easyform] +url=git@github.com:collective/collective.easyform.git +branch=dev-branch-name +extras=test +``` + +```{seealso} +The {file}`mx.ini` file configures a tool called {term}`mxdev`. +See the [documentation of `mxdev` in its README.md](https://github.com/mxstack/mxdev/blob/main/README.md) for complete information. +``` + +Stop the backend with {kbd}`ctrl-c`. + +To actually download and install the new add-on, run: + +```shell +make backend-build +``` + +```{note} +If you installed Plone using `cookiecutter-plone-starter`, run `make build-backend` instead.` +``` + +Now restart the backend. + +In your web browser, and assuming you are currently logged in as `admin`, visit the URL http://localhost:8080/Plone/prefs_install_products_form. +An upgrade step might need to be performed in the Plone control panel. +Follow the upgrade information, if present. +Else click the {guilabel}`Install` button to complete installation of the add-on. + + +## with Buildout + +Use the following instructions if you installed Plone with Buildout. + +### Install an add-on + +Update {file}`buildout.cfg`. +This example uses [`collective.easyform`](https://pypi.org/project/collective.easyform/). + +```cfg +[buildout] +extends = + https://dist.plone.org/release/6-latest/versions.cfg + +parts = + instance + +[instance] +recipe = plone.recipe.zope2instance +user = admin:admin +http-address = 8080 +eggs = + Plone + collective.easyform + +[versions] +collective.easyform = 4.2.1 +``` + +```{tip} +Including the add-on version ensures that it won't accidentally get upgraded in the future. +``` + +To actually download and install the new add-on, run: + +```shell +bin/buildout +``` + +### Install an add-on from source + +An add-on can be installed from a source control system such as GitHub. + +Update {file}`buildout.cfg`. +This example uses [`collective.easyform`](https://pypi.org/project/collective.easyform/). + +```cfg +[buildout] +extends = + https://dist.plone.org/release/6-latest/versions.cfg +extensions = mr.developer +auto-checkout = + collective.easyform + +parts = + instance + +[instance] +recipe = plone.recipe.zope2instance +user = admin:admin +http-address = 8080 +eggs = + Plone + collective.easyform + +[sources] +collective.easyform = git https://github.com/collective/collective.easyform.git +``` + +To actually download and install the new add-on, run: + +```shell +bin/buildout +``` + +```{seealso} +This approach uses the [`mr.developer`](https://pypi.org/project/mr.developer/) Buildout extension. +``` diff --git a/docs/admin-guide/index.md b/docs/admin-guide/index.md index 92302425d..dbc026aac 100644 --- a/docs/admin-guide/index.md +++ b/docs/admin-guide/index.md @@ -29,6 +29,7 @@ install-plonestarter :maxdepth: 1 run-plone +add-ons upgrade ``` From af5ced1da17241d0f2556431141a166651e49f6d Mon Sep 17 00:00:00 2001 From: David Glick Date: Sun, 27 Oct 2024 16:43:09 -0700 Subject: [PATCH 465/810] Add overrides & zope config, remove old manage section --- docs/admin-guide/add-ons.md | 4 + docs/admin-guide/configure-zope.md | 33 ++++ docs/admin-guide/index.md | 6 +- docs/admin-guide/override-core.md | 167 ++++++++++++++++ docs/index.md | 1 - docs/manage/backend.md | 299 ----------------------------- docs/manage/frontend.md | 18 -- docs/manage/index.md | 20 -- 8 files changed, 206 insertions(+), 342 deletions(-) create mode 100644 docs/admin-guide/configure-zope.md create mode 100644 docs/admin-guide/override-core.md delete mode 100644 docs/manage/backend.md delete mode 100644 docs/manage/frontend.md delete mode 100644 docs/manage/index.md diff --git a/docs/admin-guide/add-ons.md b/docs/admin-guide/add-ons.md index 61d8b532a..c6c8e6fb3 100644 --- a/docs/admin-guide/add-ons.md +++ b/docs/admin-guide/add-ons.md @@ -159,6 +159,8 @@ To actually download and install the new add-on, run: bin/buildout ``` +Then restart your instance. + ### Install an add-on from source An add-on can be installed from a source control system such as GitHub. @@ -195,6 +197,8 @@ To actually download and install the new add-on, run: bin/buildout ``` +Then restart your instance. + ```{seealso} This approach uses the [`mr.developer`](https://pypi.org/project/mr.developer/) Buildout extension. ``` diff --git a/docs/admin-guide/configure-zope.md b/docs/admin-guide/configure-zope.md new file mode 100644 index 000000000..0f05786ca --- /dev/null +++ b/docs/admin-guide/configure-zope.md @@ -0,0 +1,33 @@ +--- +myst: + html_meta: + "description": "Configure Zope options" + "property=og:description": "Configure Zope options" + "property=og:title": "Configure Zope" + "keywords": "Plone 6, Zope, instance, app server, config, cookiecutter-zope-instance" +--- + +(configure-zope-label)= + +# Configure Zope + +Plone runs in an application server called {term}`Zope`. + +You can configure your Zope instance's options, including the following. + +* persistent storage: blobs, direct filestorage, relation database, ZEO, and so on +* ports +* threads +* cache +* logging +* debugging and profiling for development + +## with Cookieplone + +If you installed Plone using Cookieplone, `cookiecutter-plone-starter`, or pip, then Zope is configured using {term}`cookiecutter-zope-instance`. +For a complete list of features, usage, and options, read [`cookiecutter-zope-instance`'s README](https://github.com/plone/cookiecutter-zope-instance#readme). + +## with Buildout + +If you installed Plone using Buildout, then Zope is configured using `plone.recipe.zope2instance`. +For a complete list of features, usage, and options, read [`plone.recipe.zope2instance`'s README](https://pypi.org/project/plone.recipe.zope2instance/). diff --git a/docs/admin-guide/index.md b/docs/admin-guide/index.md index dbc026aac..3d19b17f3 100644 --- a/docs/admin-guide/index.md +++ b/docs/admin-guide/index.md @@ -29,7 +29,9 @@ install-plonestarter :maxdepth: 1 run-plone +configure-zope add-ons +override-core upgrade ``` @@ -39,7 +41,3 @@ upgrade containers/index ``` - - -To do: -- move and update Manage section diff --git a/docs/admin-guide/override-core.md b/docs/admin-guide/override-core.md new file mode 100644 index 000000000..38f80abd4 --- /dev/null +++ b/docs/admin-guide/override-core.md @@ -0,0 +1,167 @@ +--- +myst: + html_meta: + "description": "Override core Plone packages" + "property=og:description": "Override core Plone packages" + "property=og:title": "Override core Plone packages" + "keywords": "Plone 6, core, package, version, override" +--- + +(override-core-plone-packages-label)= + +# Override core Plone packages + +Plone includes a lot of Python packages. +Sometimes it is necessary to override one or more package versions in order to fix a bug. + + +## with Cookieplone + +Use the following instructions if you installed Plone with Cookieplone or `cookiecutter-plone-starter`. + +### Override a core Plone package + +Add a version override to {file}`mx.ini`. +This example uses `plone.api`. + +``` +[settings] +version-overrides = + plone.api==2.0.0a3 +``` + +```{seealso} +The {file}`mx.ini` file configures a tool called {term}`mxdev`. +For an explanation of why Plone uses `mxdev`, see {ref}`manage-backend-python-packages-label`. +``` + +Stop the backend with {kbd}`ctrl-c`. + +To actually download and install the new package version, run: + +```shell +make backend-build +``` + +```{note} +If you installed Plone using `cookiecutter-plone-starter`, run `make build-backend` instead.` +``` + +Now restart the backend. + + +### Install a core Plone package from source + +`mxdev` can also be used to install core Plone packages from a source control system such as GitHub. + +Add the Plone package you want to check out in {file}`mx.ini`. +This example uses `plone.restapi`. + +```cfg +[plone.restapi] +url = git@github.com:plone/plone.restapi.git +branch = main +extras = test +``` + +Stop the backend with {kbd}`ctrl-c`. + +To actually download and install the new package version, run: + +```shell +make backend-build +``` + +```{note} +If you installed Plone using `cookiecutter-plone-starter`, run `make build-backend` instead.` +``` + +Now restart the backend. + + +## with Buildout + +Use the following instructions if you installed Plone with Buildout. + +### Override a core Plone package + +Update {file}`buildout.cfg`. +This example uses `plone.api`. + +```cfg +[buildout] +extends = + https://dist.plone.org/release/6-latest/versions.cfg + +parts = + instance + +[instance] +recipe = plone.recipe.zope2instance +user = admin:admin +http-address = 8080 +eggs = + Plone + +[versions] +plone.api = 2.0.0a3 +``` + +```{note} +The version pins specified in the `[versions]` section will take precedence over the pins inherited from `https://dist.plone.org/release/6-latest/versions.cfg`. +``` + +To actually download and install the new package version, run: + +```shell +bin/buildout +``` + +Then restart your instance. + + +### Install a core Plone package from source + +A core Plone package can be installed from a source control system such as GitHub. + +Update {file}`buildout.cfg`. +This example uses `plone.restapi`. + +```cfg +[buildout] +extends = + https://dist.plone.org/release/6-latest/versions.cfg +extensions = mr.developer +auto-checkout = + plone.restapi + +parts = + instance + +[instance] +recipe = plone.recipe.zope2instance +user = admin:admin +http-address = 8080 +eggs = + Plone + +[sources] +plone.restapi = git https://github.com/plone/plone.restapi.git + +[versions] +plone.restapi = +``` + +```{tip} +Setting an empty version ensures that the copy of `plone.restapi` from source control will be used, instead of the version pin inherited from https://dist.plone.org/release/6-latest/versions.cfg. +``` + +To actually download and install the new add-on, run: + +```shell +bin/buildout +``` + +```{seealso} +This approach uses the [`mr.developer`](https://pypi.org/project/mr.developer/) Buildout extension. +``` diff --git a/docs/index.md b/docs/index.md index f76575d8a..9f4594162 100644 --- a/docs/index.md +++ b/docs/index.md @@ -33,7 +33,6 @@ Read the [documentation for the previous version, Plone 5](https://5.docs.plone. overview/index install/index admin-guide/index -manage/index deployment/index volto/index classic-ui/index diff --git a/docs/manage/backend.md b/docs/manage/backend.md deleted file mode 100644 index a8a16d59d..000000000 --- a/docs/manage/backend.md +++ /dev/null @@ -1,299 +0,0 @@ ---- -myst: - html_meta: - "description": "Manage Plone backend" - "property=og:description": "Manage Plone backend" - "property=og:title": "Manage Plone backend" - "keywords": "Plone 6, manage, backend, add-ons, packages, mxdev" ---- - -(manage-plone-backend-label)= - -# Manage Plone backend - -This part of the documentation describes how to perform common management tasks in the Plone backend. -This chapter assumes you have previously followed {doc}`/admin-guide/install-plonestarter`. - - -## Manage add-ons and packages - -Plone uses `mxdev` to manage packages and constraints. - -```{seealso} -For an explanation of why Plone uses `mxdev`, see {ref}`manage-backend-python-packages-label`. -``` - - -(mxdev-usage-overview-label)= - -### `mxdev` usage overview - -The default set of files for `mxdev` is shown below. -They are located in the `backend` directory of your project. - -{file}`requirements.txt` - -```ini --c constraints.txt --e src/project_title - -zope.testrunner - -# Add required add-ons -# collective.easyform -``` - -{file}`constraints.txt` - -```ini --c https://dist.plone.org/release/{PLONE_BACKEND_PATCH_VERSION}/constraints.txt -``` - -{file}`mx.ini` - -```ini -; This is a mxdev configuration file -; it can be used to override versions of packages already defined in the -; constraints files and to add new packages from VCS like git. -; to learn more about mxdev visit https://pypi.org/project/mxdev/ - -[settings] -; example how to override a package version -; version-overrides = -; example.package==2.1.0a2 - -; example section to use packages from git -; [example.contenttype] -; url = https://github.com/collective/example.contenttype.git -; pushurl = git@github.com:collective/example.contenttype.git -; extras = test -; branch = feature-7 -``` - -You can edit these three files in your project as you need. -Then you can generate package requirements and constraints files, and then install those packages, with one command. - -```shell -make build-backend -``` - -`make build-backend` invokes `mxdev`, which generates the files {file}`requirements-mxdev.txt` and {file}`constraints-mxdev.txt`. -It then invokes `pip` to install packages with the new requirements file. - -To reload the packages, stop your Plone site with {kbd}`ctrl-c`, and start it with the following command. - -```shell -make start-backend -``` - -```{seealso} -See the [documentation of `mxdev` in its README.md](https://github.com/mxstack/mxdev/blob/main/README.md) for complete information. -``` - - -(manage-add-an-add-on)= - -### Add an add-on - -Add a line with the name of your add-on in `requirements.txt`. -This example uses [`collective.easyform`](https://pypi.org/project/collective.easyform/). - -``` -collective.easyform -``` - -Add it to {file}`instance.yaml` to let Zope know that this add-on should be loaded: - -```yaml -default_context: - zcml_package_includes: project_title, collective.easyform -``` - -Stop the backend with {kbd}`ctrl-c`. -Then apply your changes and start the backend. -You do not need to stop the frontend. - -```shell -make build-backend -make start-backend -``` - -In your web browser, and assuming you are currently logged in as `admin`, visit the URL http://localhost:8080/Plone/prefs_install_products_form. - -Then click the {guilabel}`Install` button next to your add-on to complete installation of the add-on. - -Some add-ons have configuration options. -To configure such add-ons, return to the {guilabel}`Site Setup` control panel. -At the bottom of the page, you should see the heading {guilabel}`Add-on Configuration`, and a control panel to configure the add-on that you just installed. - - -(manage-pin-the-version-of-an-add-on)= - -### Pin the version of an add-on - -Pin the version in {file}`constraints.txt`. - -``` -collective.easyform==3.1.0 -``` - -Add the add-on to {file}`requirements.txt`: - -``` -collective.easyform -``` - -Add it to {file}`instance.yaml` to let Zope know that this add-on should be loaded: - -```yaml -default_context: - zcml_package_includes: project_title, collective.easyform -``` - -Stop the backend with {kbd}`ctrl-c`. -Then apply your changes and start the backend. - -```shell -make build-backend -make start-backend -``` - -In your web browser, and assuming you are currently logged in as `admin`, visit the URL http://localhost:8080/Plone/prefs_install_products_form. -An upgrade step might need to be performed in the Plone control panel. -Follow the upgrade information, if present. -Else click the {guilabel}`Install` button to complete installation of the add-on. - - -(manage-check-out-an-add-on)= - -### Check out an add-on - -Add the add-on in {file}`requirements.txt`: - -``` -collective.easyform -``` - -In {file}`mx.ini`, specify the information to check out the add-on: - -```ini -[collective.easyform] -url=git@github.com:collective/collective.easyform.git -branch=dev-branch-name -extras=test -``` - -Add it to {file}`instance.yaml` to let Zope know that this add-on should be loaded: - -```yaml -default_context: - zcml_package_includes: project_title, collective.easyform -``` - -Stop the backend with {kbd}`ctrl-c`. -Then apply your changes and start the backend. - -```shell -make build-backend -make start-backend -``` - -In your web browser, and assuming you are currently logged in as `admin`, visit the URL http://localhost:8080/Plone/prefs_install_products_form. -An upgrade step might need to be performed in the Plone control panel. -Follow the upgrade information, if present. -Else click the {guilabel}`Install` button to complete installation of the add-on. - - -(manage-pin-the-version-of-a-plone-package-against-constraints-label)= - -### Pin the version of a Plone package against constraints - -A version can **not** be pinned in `constraints.txt` when the package is mentioned in the constraints of Plone. -Any other package version could be pinned in `constraints.txt`. - -Pin the version of a Plone package in {file}`mx.ini`: - -```ini -[settings] -# constraints of Plone packages -version-overrides = - plone.api>=2.0.0a3 -``` - -Apply your changes and restart backend: - -```shell -make build-backend -make start-backend -``` - -In your web browser, and assuming you are currently logged in as `admin`, visit the URL http://localhost:8080/Plone/prefs_install_products_form. -An upgrade step might need to be performed in the Plone control panel. -Follow the upgrade information, if present. - - -(manage-checkout-a-plone-package-label)= - -### Check out a Plone package - -This section covers how to check out a Plone Core package for development. - -Add the Plone package you want to check out in {file}`mx.ini`. - -```ini -[plone.restapi] -url = git@github.com:plone/plone.restapi.git -branch = main -extras = test -``` - -Stop the backend with {kbd}`ctrl-c`. -Then apply your changes and start the backend. - -```shell -make build-backend -make start-backend -``` - -In your web browser, and assuming you are currently logged in as `admin`, visit the URL http://localhost:8080/Plone/prefs_install_products_form. -An upgrade step might need to be performed in the Plone control panel. -Follow the upgrade information, if present. - - -(manage-build-and-start-your-instance-label)= - -### Build and start your instance - -Whenever you make changes to your backend configuration—for example, install an add-on, or override a Plone core package—then a build and restart is needed. -First stop your Zope instance/Plone site with {kbd}`ctrl-c`. -Then build and run the Plone backend. - -```shell -make build-backend -make start-backend -``` - -In a web browser, visit http://localhost:8080/ to see that Plone is running. - -Your instance is running in the foreground. - -```{seealso} -For an explanation of the command `make build-backend`, see {doc}`/conceptual-guides/make-build-backend-walk-through`. -``` - - -(manage-configuration-with-cookiecutter-zope-instance-label)= - -## Configuration with `cookiecutter-zope-instance` - -You can configure your instance's options, including the following. - -- persistent storage: blobs, direct filestorage, relational database, ZEO, and so on -- ports -- threads -- cache -- debugging and profiling for development - -```{seealso} -For a complete list of features, usage, and options, read [`cookiecutter-zope-instance`'s `README.rst`](https://github.com/plone/cookiecutter-zope-instance#readme). -``` diff --git a/docs/manage/frontend.md b/docs/manage/frontend.md deleted file mode 100644 index 9d3c275c9..000000000 --- a/docs/manage/frontend.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -myst: - html_meta: - "description": "Manage Plone frontend" - "property=og:description": "Manage Plone frontend" - "property=og:title": "Manage Plone frontend" - "keywords": "Plone 6, manage, frontend, add-ons, packages" ---- - -(manage-plone-frontend-label)= - -# Manage Plone frontend - -This part of the documentation describes how to perform common management tasks in the Plone frontend. - -```{seealso} -{doc}`/volto/addons/index` -``` diff --git a/docs/manage/index.md b/docs/manage/index.md deleted file mode 100644 index 4e7fb946e..000000000 --- a/docs/manage/index.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -myst: - html_meta: - "description": "Manage add-ons, packages, and processes in Plone" - "property=og:description": "Manage add-ons, packages, and processes in Plone" - "property=og:title": "Manage add-ons, packages, and processes in Plone" - "keywords": "Plone 6, manage, backend, frontend, Volto, Classic UI, add-ons, packages, processes, cookiecutter, Zope" ---- - -# Manage Plone - -This part of the documentation describes how to perform common management tasks in Plone. - - -```{toctree} -:maxdepth: 2 - -backend -frontend -``` From 000c99803817279b2469a0f37aa9305bc7b4e57f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 28 Oct 2024 04:41:57 -0700 Subject: [PATCH 466/810] Add label for reference --- docs/install/create-project-cookieplone.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/install/create-project-cookieplone.md b/docs/install/create-project-cookieplone.md index 5f2122aff..47928c6d0 100644 --- a/docs/install/create-project-cookieplone.md +++ b/docs/install/create-project-cookieplone.md @@ -23,6 +23,8 @@ For other installation options, see {doc}`/install/index`. ``` +{create-project-cookieplone-system-requirements}= + ## System requirements Plone 6 has both hardware requirements and software prerequisites. From 4b688a79626dba325c4602575483ab95cff16aaf Mon Sep 17 00:00:00 2001 From: David Glick Date: Mon, 28 Oct 2024 17:31:49 -0700 Subject: [PATCH 467/810] move docs back to their old paths to avoid need for redirects --- docs/admin-guide/index.md | 8 ++++---- docs/conf.py | 6 +----- .../containers/examples/haproxy-plone-zeo.md | 0 .../{admin-guide => install}/containers/examples/index.md | 0 .../containers/examples/nginx-plone.md | 0 .../containers/examples/nginx-volto-plone-postgresql.md | 0 .../containers/examples/nginx-volto-plone-zeo.md | 0 .../containers/examples/nginx-volto-plone.md | 0 .../containers/examples/traefik-volto-plone-varnish.md | 0 .../{admin-guide => install}/containers/images/backend.md | 0 .../containers/images/frontend.md | 0 docs/{admin-guide => install}/containers/images/index.md | 0 docs/{admin-guide => install}/containers/images/zeo.md | 0 docs/{admin-guide => install}/containers/index.md | 0 .../create-project-cookieplone.md} | 0 .../install-plonestarter.md => install/create-project.md} | 0 docs/install/index.md | 4 ++-- docs/{admin-guide/upgrade.md => upgrade/index.md} | 0 18 files changed, 7 insertions(+), 11 deletions(-) rename docs/{admin-guide => install}/containers/examples/haproxy-plone-zeo.md (100%) rename docs/{admin-guide => install}/containers/examples/index.md (100%) rename docs/{admin-guide => install}/containers/examples/nginx-plone.md (100%) rename docs/{admin-guide => install}/containers/examples/nginx-volto-plone-postgresql.md (100%) rename docs/{admin-guide => install}/containers/examples/nginx-volto-plone-zeo.md (100%) rename docs/{admin-guide => install}/containers/examples/nginx-volto-plone.md (100%) rename docs/{admin-guide => install}/containers/examples/traefik-volto-plone-varnish.md (100%) rename docs/{admin-guide => install}/containers/images/backend.md (100%) rename docs/{admin-guide => install}/containers/images/frontend.md (100%) rename docs/{admin-guide => install}/containers/images/index.md (100%) rename docs/{admin-guide => install}/containers/images/zeo.md (100%) rename docs/{admin-guide => install}/containers/index.md (100%) rename docs/{admin-guide/install-cookieplone.md => install/create-project-cookieplone.md} (100%) rename docs/{admin-guide/install-plonestarter.md => install/create-project.md} (100%) rename docs/{admin-guide/upgrade.md => upgrade/index.md} (100%) diff --git a/docs/admin-guide/index.md b/docs/admin-guide/index.md index 3d19b17f3..8d8dd9907 100644 --- a/docs/admin-guide/index.md +++ b/docs/admin-guide/index.md @@ -18,10 +18,10 @@ In this part of the documentation, you can find how to install, operate, configu :caption: Install :maxdepth: 1 -install-cookieplone +/install/create-project-cookieplone install-buildout install-pip -install-plonestarter +/install/create-project ``` ```{toctree} @@ -32,12 +32,12 @@ run-plone configure-zope add-ons override-core -upgrade +/upgrade/index ``` ```{toctree} :maxdepth: 1 :caption: Deploy -containers/index +/install/containers/index ``` diff --git a/docs/conf.py b/docs/conf.py index ca61b9e21..43fd357ff 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -245,12 +245,8 @@ "contributing/plone-api": "/plone.api/contribute/index.html", "contributing/plone-restapi": "/plone.restapi/docs/source/contributing/index.html", "contributing/volto": "/volto/contributing/index.html", - "install/containers/index": "/admin-guide/containers/index.html", - "install/create-project-cookieplone": "/admin-guide/install-cookieplone.html", - "install/create-project": "/admin-guide/install-plonestarter.html", - "install/install-from-packages": "/admin-guide/install-cookieplone.html", + "install/install-from-packages": "/install/create-project.html", "manage/frontend": "/volto/addons/index.html", - "upgrade/index": "/admin-guide/upgrade.html", } diff --git a/docs/admin-guide/containers/examples/haproxy-plone-zeo.md b/docs/install/containers/examples/haproxy-plone-zeo.md similarity index 100% rename from docs/admin-guide/containers/examples/haproxy-plone-zeo.md rename to docs/install/containers/examples/haproxy-plone-zeo.md diff --git a/docs/admin-guide/containers/examples/index.md b/docs/install/containers/examples/index.md similarity index 100% rename from docs/admin-guide/containers/examples/index.md rename to docs/install/containers/examples/index.md diff --git a/docs/admin-guide/containers/examples/nginx-plone.md b/docs/install/containers/examples/nginx-plone.md similarity index 100% rename from docs/admin-guide/containers/examples/nginx-plone.md rename to docs/install/containers/examples/nginx-plone.md diff --git a/docs/admin-guide/containers/examples/nginx-volto-plone-postgresql.md b/docs/install/containers/examples/nginx-volto-plone-postgresql.md similarity index 100% rename from docs/admin-guide/containers/examples/nginx-volto-plone-postgresql.md rename to docs/install/containers/examples/nginx-volto-plone-postgresql.md diff --git a/docs/admin-guide/containers/examples/nginx-volto-plone-zeo.md b/docs/install/containers/examples/nginx-volto-plone-zeo.md similarity index 100% rename from docs/admin-guide/containers/examples/nginx-volto-plone-zeo.md rename to docs/install/containers/examples/nginx-volto-plone-zeo.md diff --git a/docs/admin-guide/containers/examples/nginx-volto-plone.md b/docs/install/containers/examples/nginx-volto-plone.md similarity index 100% rename from docs/admin-guide/containers/examples/nginx-volto-plone.md rename to docs/install/containers/examples/nginx-volto-plone.md diff --git a/docs/admin-guide/containers/examples/traefik-volto-plone-varnish.md b/docs/install/containers/examples/traefik-volto-plone-varnish.md similarity index 100% rename from docs/admin-guide/containers/examples/traefik-volto-plone-varnish.md rename to docs/install/containers/examples/traefik-volto-plone-varnish.md diff --git a/docs/admin-guide/containers/images/backend.md b/docs/install/containers/images/backend.md similarity index 100% rename from docs/admin-guide/containers/images/backend.md rename to docs/install/containers/images/backend.md diff --git a/docs/admin-guide/containers/images/frontend.md b/docs/install/containers/images/frontend.md similarity index 100% rename from docs/admin-guide/containers/images/frontend.md rename to docs/install/containers/images/frontend.md diff --git a/docs/admin-guide/containers/images/index.md b/docs/install/containers/images/index.md similarity index 100% rename from docs/admin-guide/containers/images/index.md rename to docs/install/containers/images/index.md diff --git a/docs/admin-guide/containers/images/zeo.md b/docs/install/containers/images/zeo.md similarity index 100% rename from docs/admin-guide/containers/images/zeo.md rename to docs/install/containers/images/zeo.md diff --git a/docs/admin-guide/containers/index.md b/docs/install/containers/index.md similarity index 100% rename from docs/admin-guide/containers/index.md rename to docs/install/containers/index.md diff --git a/docs/admin-guide/install-cookieplone.md b/docs/install/create-project-cookieplone.md similarity index 100% rename from docs/admin-guide/install-cookieplone.md rename to docs/install/create-project-cookieplone.md diff --git a/docs/admin-guide/install-plonestarter.md b/docs/install/create-project.md similarity index 100% rename from docs/admin-guide/install-plonestarter.md rename to docs/install/create-project.md diff --git a/docs/install/index.md b/docs/install/index.md index 30ed2eaa6..84c4707db 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -35,7 +35,7 @@ Choose a version to demo. First, choose a Plone frontend. [TODO: add link to explanation of how to choose] (If you are following a [Plone training](https://training.plone.org/), it should specify which option to choose.) -{doc}`/admin-guide/install-cookieplone` +{doc}`create-project-cookieplone` : This is the recommended way to install Plone for a new project with the Volto frontend. {doc}`/admin-guide/install-buildout` @@ -46,7 +46,7 @@ First, choose a Plone frontend. [TODO: add link to explanation of how to choose] : This is one way to install Plone with the Classic UI. It provides a basic installation without many additional tools to help with development. -{doc}`/admin-guide/install-plonestarter` +{doc}`create-project` : This was the recommended way to install Plone 6.0 for a new project with the Volto frontend. {doc}`Install Plone as a contributor ` diff --git a/docs/admin-guide/upgrade.md b/docs/upgrade/index.md similarity index 100% rename from docs/admin-guide/upgrade.md rename to docs/upgrade/index.md From 04a02f17bc66d3e40c5ff8b3a729b77687d61164 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 28 Oct 2024 23:06:20 -0700 Subject: [PATCH 468/810] One day I will remember the correct syntax for arbitrary labels --- docs/install/create-project-cookieplone.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install/create-project-cookieplone.md b/docs/install/create-project-cookieplone.md index 47928c6d0..022199b04 100644 --- a/docs/install/create-project-cookieplone.md +++ b/docs/install/create-project-cookieplone.md @@ -23,7 +23,7 @@ For other installation options, see {doc}`/install/index`. ``` -{create-project-cookieplone-system-requirements}= +(create-project-cookieplone-system-requirements)= ## System requirements From 61d76ce65604f5be0e4d527417fc7e74f6091eb2 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 30 Oct 2024 05:41:07 -0700 Subject: [PATCH 469/810] Add Cypress term --- docs/glossary.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/glossary.md b/docs/glossary.md index 2554b3cab..5d8b61ccf 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -739,6 +739,10 @@ Jest [Jest](https://jestjs.io/) is a JavaScript testing framework. Volto uses Jest for unit tests. +Cypress + [Cypress](https://www.cypress.io/) is a JavaScript testing framework that runs your app in the browser for visually debugging it. + Volto uses Cypress for acceptance tests. + Plone Plone is an open-source content management system (CMS) with over 20 years of stability and security wrapped in a modern, powerful, user-centric package. It continues to set the standard for content management systems by offering the most functionality and customization out of the box. From 39d03f43437ea6f184fee2756b9f05fdc3b801ad Mon Sep 17 00:00:00 2001 From: David Glick Date: Wed, 30 Oct 2024 15:45:09 -0700 Subject: [PATCH 470/810] start choose-user-interface chapter --- docs/_static/classic-ui.png | Bin 0 -> 293282 bytes docs/_static/volto-ui.png | Bin 0 -> 218233 bytes docs/classic-ui/index.md | 36 ++--------- .../choose-user-interface.md | 61 ++++++++++++++++++ docs/conceptual-guides/index.md | 1 + docs/glossary.md | 25 ++++--- docs/install/index.md | 4 +- 7 files changed, 84 insertions(+), 43 deletions(-) create mode 100644 docs/_static/classic-ui.png create mode 100644 docs/_static/volto-ui.png create mode 100644 docs/conceptual-guides/choose-user-interface.md diff --git a/docs/_static/classic-ui.png b/docs/_static/classic-ui.png new file mode 100644 index 0000000000000000000000000000000000000000..595d0b0fe313614f1112fa6f90fd8edaf17937cd GIT binary patch literal 293282 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 jiR1F(++;9BtxFd6kt~ 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 z�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 plE;_ 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 UIg|O{o@4+5Pgg&ebxsLQ0Puq5XaE2J literal 0 HcmV?d00001 diff --git a/docs/classic-ui/index.md b/docs/classic-ui/index.md index 8fd0f5a9c..9150d958e 100644 --- a/docs/classic-ui/index.md +++ b/docs/classic-ui/index.md @@ -11,40 +11,12 @@ myst: # Classic UI -```{todo} -Perhaps some of this introduction should be an include, so we don't have to repeat ourselves? -``` - -Plone 6 ships with two user interfaces or frontends. - -The default frontend of Plone 6 is Volto. -It is based on the React JavaScript framework. - -The other frontend is based on Twitter Bootstrap 5. -This frontend is now called {term}`Classic UI`. - - -## Which frontend? - -Choosing one frontend over another depends on several factors. - -Classic UI would be a better choice for the following situations. - -- Reason 1 -- Reason 2 -- Reason N - -The default frontend Volto would be a better choice for the following situations. - -- Reason 1 -- Reason 2 -- Reason N - - -## Contents - This chapter is a developer reference manual for working with Classic UI. +```{seealso} +Plone has two user interfaces, Volto and Classic UI. To understand the difference, see {doc}`/conceptual-guides/choose-user-interface`. +``` + ```{toctree} :maxdepth: 2 diff --git a/docs/conceptual-guides/choose-user-interface.md b/docs/conceptual-guides/choose-user-interface.md new file mode 100644 index 000000000..7096af64a --- /dev/null +++ b/docs/conceptual-guides/choose-user-interface.md @@ -0,0 +1,61 @@ +--- +myst: + html_meta: + "description": "Explanation of how to choose between Plone's user interfaces, Volto and Classic UI" + "property=og:description": "Explanation of how to choose between Plone's user interfaces, Volto and Classic UI" + "property=og:title": "Choose a user interface" + "keywords": "Plone 6, Conceptual guides, UI, frontend, Volto, Classic UI, distribution" +--- + +# Choose a user interface + +Plone 6 offers two different user interfaces: Volto and Classic UI. + +The choice of user interface has implications for editors, admins, and developers. + +::::{grid} 2 +:::{grid-item-card} Volto + +```{image} /_static/volto-ui.png +:alt: Plone homepage in Volto +``` + +For editors and other end users: + +* The user interface is a fast, modern single-page web application. +* Editors create a page by arranging blocks of different types into a layout. +* There is not a comprehensive User Manual yet. + +For developers and integrators: + +* The frontend is a {term}`React`-based application written in JavaScript and TypeScript. +* The backend is a Python process which provides a REST API for the frontend. +* Python skills are not required, but can be helpful for extending the backend. +* Content is stored as structured JSON. +* Customization of themes is well-documented and relatively easy for developers who have experience with React. + + +::: +:::{grid-item-card} Classic UI + +```{image} /_static/classic-ui.png +:alt: Plone homepage in Classic UI +``` + +For editors and other end users: + +* The user interface is similar to Plone 5. +* Editors create a page using a WYSIWYG editor (TinyMCE). +* Additional widgets can be added to predefined locations, using {term}`portlets`. +* There is a comprehensive User Manual for Plone 5, but it has not been updated for Plone 6. + +For developers and integrators: + +* The frontend and backend run in a single Python process, so hosting is a bit simpler. +* The frontend is implemented as server-side templates using the {term}`ZPT` language. +* Interactive functionality is implemented in JavaScript using {term}`Mockup`. +* Content is stored as HTML. +* Customization of themes is not well-documented. + +::: +:::: diff --git a/docs/conceptual-guides/index.md b/docs/conceptual-guides/index.md index 727810e41..de6081f2e 100644 --- a/docs/conceptual-guides/index.md +++ b/docs/conceptual-guides/index.md @@ -15,6 +15,7 @@ This part of the documentation provides explanation of concepts to deepen and br ```{toctree} :maxdepth: 2 +choose-user-interface package-management make-build-backend-walk-through ``` diff --git a/docs/glossary.md b/docs/glossary.md index 5d8b61ccf..9738f355b 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -168,8 +168,8 @@ Rapido application It contains the features you implement. It is a folder containing templates, Python code, and YAML files. -block - Blocks display a chunk of HTML which can be inserted in your Plone pages. +blocks + Blocks are the fundamental components of a page layout in {term}`Volto`. element Elements are the dynamic components of your blocks. @@ -411,18 +411,19 @@ Traefik Proxy Volto [Volto](https://github.com/plone/volto) is a React-based frontend for Plone. - It is the default user interface for Plone 6. + It is one of two supported user interfaces for Plone 6. - The other frontend is {term}`Classic UI`. + ````{seealso} + {doc}`/conceptual-guides/choose-user-interface` + ```` Classic UI - Classic UI is a secondary frontend for Plone 6. - It is integrated with [Products.CMFPlone](https://github.com/plone/Products.CMFPlone/). - Its theme is named [Barceloneta](https://github.com/plone/plonetheme.barceloneta/). - It is based on Twitter Bootstrap 5. - It uses {term}`Mockup` as its JavaScript stack. + Classic UI is a frontend for Plone 6 that is based on {term}`ZPT` and {term}`Mockup`. + It is one of two supported user interfaces for Plone 6. - The other frontend is {term}`Volto`. + ````{seealso} + {doc}`/conceptual-guides/choose-user-interface` + ```` Mockup [Mockup](https://github.com/plone/mockup/) is a package that, together with {term}`Patternslib`, builds the UI toolkit for {term}`Classic UI`, a frontend for Plone. @@ -792,4 +793,8 @@ lazy loaded reference implementation A reference implementation is a program that implements all requirements from a corresponding specification. The reference implementation often accompanies a technical standard, and demonstrates what should be considered the "correct" behavior of any other implementation of it. + +portlets + Portlets are widgets that can be inserted in predefined locations in {term}`Classic UI`. + Portlets are most commonly used to add sidebars to the left or right of the main page content. ``` diff --git a/docs/install/index.md b/docs/install/index.md index 1f8c95ce7..9022c883b 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -19,7 +19,9 @@ You can also {ref}`try a Plone demo `. ## Get started -Choose an option to get started with Plone. +First, read {doc}`/conceptual-guides/choose-user-interface` to choose between Volto and Classic UI. + +Then, choose one of the following install methods. If you are following a [Plone training](https://training.plone.org/), it should specify which option to choose. {doc}`create-project` From 87562cf93186ee049813fa4b8d639ea68931e1c4 Mon Sep 17 00:00:00 2001 From: David Glick Date: Wed, 30 Oct 2024 16:06:35 -0700 Subject: [PATCH 471/810] fixes --- docs/conceptual-guides/make-build-backend-walk-through.md | 4 ++-- docs/conceptual-guides/package-management.md | 2 +- docs/install/containers/index.md | 2 +- docs/install/create-project.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/conceptual-guides/make-build-backend-walk-through.md b/docs/conceptual-guides/make-build-backend-walk-through.md index 3c0ce4347..859852ac8 100644 --- a/docs/conceptual-guides/make-build-backend-walk-through.md +++ b/docs/conceptual-guides/make-build-backend-walk-through.md @@ -11,7 +11,7 @@ myst: # `make build-backend` details -This chapter assumes you have previously followed {doc}`/admin-guide/install-plonestarter`. +This chapter assumes you have previously followed {doc}`/install/create-project`. The `Makefile` at the root of your project invokes commands in `backend/Makefile`. Here are excerpts from `backend/Makefile` to show details of the `make build-backend` command. @@ -55,4 +55,4 @@ The command `make build-backend`: - This generates the `mxdev` files as described above in {ref}`mxdev-usage-overview-label`. - Installs Plone core packages and add-ons from the files generated by `mxdev`. -You can configure your Zope instance as described in the section {ref}`manage-configuration-with-cookiecutter-zope-instance-label`. +You can configure your Zope instance as described in the section {doc}`/admin-guide/configure-zope`. diff --git a/docs/conceptual-guides/package-management.md b/docs/conceptual-guides/package-management.md index 7e19bf175..baaef4a35 100644 --- a/docs/conceptual-guides/package-management.md +++ b/docs/conceptual-guides/package-management.md @@ -53,7 +53,7 @@ The generated files indicate from where the constraints were fetched, and commen You or your development tools, such as GNU Make, must perform that step. ```{seealso} -{doc}`/manage/backend` +{doc}`/admin-guide/add-ons` ``` diff --git a/docs/install/containers/index.md b/docs/install/containers/index.md index d5475b532..6c925d4a9 100644 --- a/docs/install/containers/index.md +++ b/docs/install/containers/index.md @@ -14,7 +14,7 @@ myst: The Plone 6 images have all the system requirements, prerequisites, and Plone 6 already installed, except those requirements needed for running the container engine itself. Using containers is the easiest way to deploy Plone 6. -Containers may also be used when {doc}`creating a Plone project `. +Containers may also be used when {doc}`creating a Plone project `. The Plone 6 container images are compliant with the [Open Container Initiative (OCI)](https://opencontainers.org/). They should work with any OCI-compliant container engine for developing, managing, and running Plone 6 images. diff --git a/docs/install/create-project.md b/docs/install/create-project.md index 7e8a25317..2d8a46500 100644 --- a/docs/install/create-project.md +++ b/docs/install/create-project.md @@ -14,7 +14,7 @@ myst: This chapter describes how you can create a web application using the {term}`cookiecutter-plone-starter` template. -```{deprecated} +```{deprecated} Plone 6.1 & Volto 18 This way of installing Plone is now deprecated. It was the recommended way to start a new Plone project with **Plone 6.0** and **Volto 17 or earlier**. For other installation options, see {ref}`get-started-install-label`. From b44b1fac97d216842b14b5a787c6018c71be9c99 Mon Sep 17 00:00:00 2001 From: David Glick Date: Wed, 30 Oct 2024 16:10:24 -0700 Subject: [PATCH 472/810] add note about bootstrap --- docs/conceptual-guides/choose-user-interface.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/conceptual-guides/choose-user-interface.md b/docs/conceptual-guides/choose-user-interface.md index 7096af64a..47b02f95c 100644 --- a/docs/conceptual-guides/choose-user-interface.md +++ b/docs/conceptual-guides/choose-user-interface.md @@ -54,6 +54,7 @@ For developers and integrators: * The frontend and backend run in a single Python process, so hosting is a bit simpler. * The frontend is implemented as server-side templates using the {term}`ZPT` language. * Interactive functionality is implemented in JavaScript using {term}`Mockup`. +* The visual design is based on the {term}`Barceloneta` theme from Plone 5, but updated to use Twitter Bootstrap 5. * Content is stored as HTML. * Customization of themes is not well-documented. From 36ca9b0a1e4f39d3fc820c1e428dfa4d457d78b1 Mon Sep 17 00:00:00 2001 From: David Glick Date: Thu, 31 Oct 2024 08:51:41 -0700 Subject: [PATCH 473/810] Twitter Bootstrap -> Bootstrap --- .../upgrading/version-specific-migration/upgrade-to-52.md | 2 +- .../upgrading/version-specific-migration/upgrade-to-60.md | 4 ++-- docs/classic-ui/icons.md | 2 +- docs/classic-ui/index.md | 6 +++--- docs/classic-ui/theming/through-the-web.md | 2 +- docs/classic-ui/whatsnew.md | 4 ++-- docs/conceptual-guides/choose-user-interface.md | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-52.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-52.md index 23fa88805..be670bb57 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-52.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-52.md @@ -81,7 +81,7 @@ This is [PLIP 1351](https://github.com/plone/Products.CMFPlone/issues/1351). #### For end users This has no changes for Editors. -Admins will notice that the ZMI has a new Twitter Bootstrap-based theme, and some control panels have moved. +Admins will notice that the ZMI has a new Bootstrap-based theme, and some control panels have moved. #### For developers diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md index 34ce02e2a..51651cf6a 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-60.md @@ -128,9 +128,9 @@ zodb-temporary-storage = off (v60-templates-bootstrap-5-label)= -## Changed templates to Twitter Bootstrap 5 markup +## Changed templates to Bootstrap 5 markup -All templates in core Plone have been updated to use Twitter Bootstrap 5 markup. +All templates in core Plone have been updated to use Bootstrap 5 markup. Add-on authors are encouraged to do the same. If you have customized a core template, you should check if your change is still needed, and update it to fit the new markup. Any CSS and JavaScript that relies on a specific structure, or certain IDs or classes, should be checked as well. diff --git a/docs/classic-ui/icons.md b/docs/classic-ui/icons.md index fdaf6feb6..269b455cf 100644 --- a/docs/classic-ui/icons.md +++ b/docs/classic-ui/icons.md @@ -23,7 +23,7 @@ Examples include the following. ## Bootstrap Icons -Twitter Bootstrap 5 is the default CSS framework in Plone 6. +Bootstrap 5 is the default CSS framework in Plone 6. Plone uses its icons. Check out all the available Bootstrap icons at [icons.getbootstrap.com](https://icons.getbootstrap.com/). diff --git a/docs/classic-ui/index.md b/docs/classic-ui/index.md index 9150d958e..dfc6949ce 100644 --- a/docs/classic-ui/index.md +++ b/docs/classic-ui/index.md @@ -1,10 +1,10 @@ --- myst: html_meta: - "description": "Classic UI is a secondary user interface for Plone, but updated to use Twitter Bootstrap 5. It is familiar to users of Plone 5." - "property=og:description": "Classic UI is a secondary user interface for Plone, but updated to use Twitter Bootstrap 5. It is familiar to users of Plone 5." + "description": "Classic UI is a secondary user interface for Plone, but updated to use Bootstrap 5. It is familiar to users of Plone 5." + "property=og:description": "Classic UI is a secondary user interface for Plone, but updated to use Bootstrap 5. It is familiar to users of Plone 5." "property=og:title": "Classic UI" - "keywords": "Plone 6, Classic UI, Twitter Bootstrap 5" + "keywords": "Plone 6, Classic UI, Bootstrap 5" --- (classic-ui-index-label)= diff --git a/docs/classic-ui/theming/through-the-web.md b/docs/classic-ui/theming/through-the-web.md index 2a9646bd6..99a519131 100644 --- a/docs/classic-ui/theming/through-the-web.md +++ b/docs/classic-ui/theming/through-the-web.md @@ -47,7 +47,7 @@ Add screenshots. ## CSS variables -Plone uses Twitter Bootstrap's CSS variables. +Plone uses Bootstrap's CSS variables. They are used to tweak colors, fonts, spacing, and other CSS attributes. ```{todo} diff --git a/docs/classic-ui/whatsnew.md b/docs/classic-ui/whatsnew.md index dee9a7195..675c6464b 100644 --- a/docs/classic-ui/whatsnew.md +++ b/docs/classic-ui/whatsnew.md @@ -11,8 +11,8 @@ myst: # What's new in Plone 6 Classic UI -- HTML markup is now based on [Twitter Bootstrap 5](https://getbootstrap.com/). -- Twitter Bootstrap 5 icons are now included. +- HTML markup is now based on [Bootstrap 5](https://getbootstrap.com/). +- Bootstrap 5 icons are now included. - Bootstrap JavaScript is available by default. - JavaScript has been modernized. - RequireJS has been removed. diff --git a/docs/conceptual-guides/choose-user-interface.md b/docs/conceptual-guides/choose-user-interface.md index 47b02f95c..9c9fe38cf 100644 --- a/docs/conceptual-guides/choose-user-interface.md +++ b/docs/conceptual-guides/choose-user-interface.md @@ -54,7 +54,7 @@ For developers and integrators: * The frontend and backend run in a single Python process, so hosting is a bit simpler. * The frontend is implemented as server-side templates using the {term}`ZPT` language. * Interactive functionality is implemented in JavaScript using {term}`Mockup`. -* The visual design is based on the {term}`Barceloneta` theme from Plone 5, but updated to use Twitter Bootstrap 5. +* The visual design is based on the {term}`Barceloneta` theme from Plone 5, but updated to use Bootstrap 5. * Content is stored as HTML. * Customization of themes is not well-documented. From af891259f6b65d577168617c2ac273f8b6453480 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 1 Nov 2024 01:52:37 -0700 Subject: [PATCH 474/810] Add glossary terms for language-features.md in Volto docs --- docs/glossary.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/glossary.md b/docs/glossary.md index 5d8b61ccf..412e3eccb 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -282,10 +282,18 @@ CommonJS Transpilation The transformation of JavaScript code that uses advanced language features, unavailable for some browsers, to code rewritten to support them. -ES6 - ECMAScript 6, a newer version of the JavaScript language. +ECMAScript + ECMAScript is a standard for scripting languages, including JavaScript, JScript, and ActionScript. + It is best known as a JavaScript standard intended to ensure the interoperability of web pages across different web browsers. + It is standardized by [Ecma International](https://ecma-international.org/) in the document [ECMA-262](https://ecma-international.org/publications-and-standards/standards/ecma-262/). + +TC39 + Ecma International's [TC39](https://tc39.es/) is a group of JavaScript developers, implementers, academics, and more, collaborating with the community to maintain and evolve the definition of JavaScript. + They established a [process](https://tc39.es/process-document/) where the proposals are discussed, developed, and eventually approved (or dropped). + The process has five Stages (0 to 4) where reaching the Stage 4 means the proposal is finished, and it becomes part of the JavaScript specification. mrs-developer +`mrs-developer` Also called "missdev", a tool similar to buildout's `mr.developer`. It automatically downloads and keeps up to date copies of software and add-ons under development based on definitions stored in `mrs.developer.json`. As a byproduct of its update operations, it also automatically adjusts `jsconfig.json`, which is used by Volto to configure webpack aliases. From 50873f107ca74d964399defee895b4ace7bdd223 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 1 Nov 2024 06:14:08 -0700 Subject: [PATCH 475/810] Fix duplicate glossary entry --- docs/glossary.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/glossary.md b/docs/glossary.md index 1a8c8a9a3..8baf0d4d1 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -296,7 +296,6 @@ TC39 They established a [process](https://tc39.es/process-document/) where the proposals are discussed, developed, and eventually approved (or dropped). The process has five Stages (0 to 4) where reaching the Stage 4 means the proposal is finished, and it becomes part of the JavaScript specification. -mrs-developer `mrs-developer` Also called "missdev", a tool similar to buildout's `mr.developer`. It automatically downloads and keeps up to date copies of software and add-ons under development based on definitions stored in `mrs.developer.json`. @@ -697,7 +696,6 @@ Content Delivery Network CDN A Content Delivery Network (CDN) is a network of servers located in various geographic regions that work together to deliver web content to users quickly and efficiently. - unique identifier UID UID is an acronym meaning "unique identifier". From ad103a9717e96ad36d224cbd94a9fa321ac54376 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 2 Nov 2024 03:45:10 -0700 Subject: [PATCH 476/810] Revise Admin guide, adding commented link to new Volto add-ons index. --- docs/admin-guide/index.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/admin-guide/index.md b/docs/admin-guide/index.md index 8d8dd9907..6e89c4d82 100644 --- a/docs/admin-guide/index.md +++ b/docs/admin-guide/index.md @@ -3,13 +3,13 @@ myst: html_meta: "description": "How to install, operate, configure, and deploy Plone 6" "property=og:description": "How to install, operate, configure, and deploy Plone 6" - "property=og:title": "Admin Guide" + "property=og:title": "Admin guide" "keywords": "Plone 6, admin, install, configuration, deploy" --- (admin-index-label)= -# Admin Guide +# Admin guide In this part of the documentation, you can find how to install, operate, configure, and deploy Plone. @@ -31,6 +31,9 @@ install-pip run-plone configure-zope add-ons +% TODO: uncomment the following link when https://github.com/plone/volto/pull/6397 is merged. +% https://volto--6397.org.readthedocs.build/development/add-ons/install-an-add-on.html +% /volto/development/add-ons/index override-core /upgrade/index ``` From 8ee93391e56240e3b92837ccc027cb65b90b836a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 2 Nov 2024 03:51:57 -0700 Subject: [PATCH 477/810] Comments not supported in toctree, move after it --- docs/admin-guide/index.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/admin-guide/index.md b/docs/admin-guide/index.md index 6e89c4d82..9ac48e4ed 100644 --- a/docs/admin-guide/index.md +++ b/docs/admin-guide/index.md @@ -31,12 +31,13 @@ install-pip run-plone configure-zope add-ons -% TODO: uncomment the following link when https://github.com/plone/volto/pull/6397 is merged. -% https://volto--6397.org.readthedocs.build/development/add-ons/install-an-add-on.html -% /volto/development/add-ons/index override-core /upgrade/index ``` +% TODO: uncomment and add the following link to the Operate toctree when https://github.com/plone/volto/pull/6397 is merged. +% https://volto--6397.org.readthedocs.build/development/add-ons/install-an-add-on.html +% /volto/development/add-ons/index + ```{toctree} :maxdepth: 1 From dda4f2f7f2073414f3420b9a33be2b7635be614f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 2 Nov 2024 04:06:06 -0700 Subject: [PATCH 478/810] Split SUPPORTED_PYTHON_VERSIONS into two replacement variables for Plone 6.0 and 6.1. --- docs/_inc/_install-python.md | 2 +- docs/admin-guide/install-buildout.md | 4 ++-- docs/conf.py | 3 ++- docs/contributing/core/index.md | 4 ++-- docs/contributing/documentation/setup-build.md | 4 ++-- docs/install/create-project-cookieplone.md | 2 +- docs/install/create-project.md | 2 +- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/_inc/_install-python.md b/docs/_inc/_install-python.md index 4f0add878..29bf96a84 100644 --- a/docs/_inc/_install-python.md +++ b/docs/_inc/_install-python.md @@ -1,6 +1,6 @@ Installing Python is beyond the scope of this documentation. However, it is recommended to use a Python version manager, {term}`pyenv`, that allows you to install multiple versions of Python on your development environment without destroying your system's Python. % TODO: uncomment this line after upgrading to plone-sphinx-theme and latest Sphinx which supports replacements inside includes. -% Plone requires Python version {SUPPORTED_PYTHON_VERSIONS}. +% Plone requires Python version {SUPPORTED_PYTHON_VERSIONS_PLONE60}. Plone requires Python version 3.8, 3.9, 3.10, 3.11, or 3.12. diff --git a/docs/admin-guide/install-buildout.md b/docs/admin-guide/install-buildout.md index dbf8a2b3b..d5ef7ca5e 100644 --- a/docs/admin-guide/install-buildout.md +++ b/docs/admin-guide/install-buildout.md @@ -4,7 +4,7 @@ myst: "description": "Install Plone with Buildout" "property=og:description": "Install Plone with Buildout" "property=og:title": "Install Plone with Buildout" - "keywords": "Plone 6, install, Classic UI, buildout" + "keywords": "Plone 6, install, Classic UI, Buildout" --- (install-buildout-label)= @@ -24,7 +24,7 @@ For other installation options, see {ref}`get-started-install-label`. ## Prerequisites -- Python 3.10 or greater +- Python (SUPPORTED_PYTHON_VERSIONS_PLONE61) On Debian-based Linux systems you can install Python with the following command: diff --git a/docs/conf.py b/docs/conf.py index 43fd357ff..8644bb392 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -359,7 +359,8 @@ def source_replace(app, docname, source): "{PLONE_BACKEND_MINOR_VERSION}": "6.0", "{PLONE_BACKEND_PATCH_VERSION}": "6.0.13", "{NVM_VERSION}": "0.39.5", - "{SUPPORTED_PYTHON_VERSIONS}": "3.8, 3.9, 3.10, 3.11, or 3.12", + "{SUPPORTED_PYTHON_VERSIONS_PLONE60}": "3.8, 3.9, 3.10, 3.11, or 3.12", + "{SUPPORTED_PYTHON_VERSIONS_PLONE61}": "3.10, 3.11, or 3.12", } diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index a8fea1426..5ea3833ca 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -40,7 +40,7 @@ However, the following links and sections below may be helpful. ```{include} ../../volto/contributing/install-operating-system.md ``` -- Python {SUPPORTED_PYTHON_VERSIONS} +- Python {SUPPORTED_PYTHON_VERSIONS_PLONE60} - {term}`GNU make` - {term}`Git` - A C compiler @@ -50,7 +50,7 @@ However, the following links and sections below may be helpful. Installing Python is beyond the scope of this documentation. However, it is recommended to use a Python version manager, {term}`pyenv` that allows you to install multiple versions of Python on your development environment without destroying your system's Python. -Plone requires Python version {SUPPORTED_PYTHON_VERSIONS}. +Plone requires Python version {SUPPORTED_PYTHON_VERSIONS_PLONE60}. ### Make diff --git a/docs/contributing/documentation/setup-build.md b/docs/contributing/documentation/setup-build.md index db25b73fe..eb9452579 100644 --- a/docs/contributing/documentation/setup-build.md +++ b/docs/contributing/documentation/setup-build.md @@ -22,7 +22,7 @@ Installation of Plone 6 Documentation includes prerequisites and the repository ```{include} ../../volto/contributing/install-operating-system.md ``` -- {ref}`setup-build-installation-python-label` {SUPPORTED_PYTHON_VERSIONS} +- {ref}`setup-build-installation-python-label` {SUPPORTED_PYTHON_VERSIONS_PLONE60} - {ref}`setup-build-installation-gnu-make-label` - {ref}`setup-build-installation-graphviz-label` @@ -33,7 +33,7 @@ Installation of Plone 6 Documentation includes prerequisites and the repository Installing Python is beyond the scope of this documentation. However, it is recommended to use a Python version manager, {term}`pyenv` that allows you to install multiple versions of Python on your development environment without destroying your system's Python. -Plone requires Python version {SUPPORTED_PYTHON_VERSIONS}. +Plone requires Python version {SUPPORTED_PYTHON_VERSIONS_PLONE60}. (setup-build-installation-gnu-make-label)= diff --git a/docs/install/create-project-cookieplone.md b/docs/install/create-project-cookieplone.md index 3fed3af77..29237e3d0 100644 --- a/docs/install/create-project-cookieplone.md +++ b/docs/install/create-project-cookieplone.md @@ -43,7 +43,7 @@ Plone 6 has both hardware requirements and software prerequisites. ```{include} ../volto/contributing/install-operating-system.md ``` -- Python {SUPPORTED_PYTHON_VERSIONS} +- Python {SUPPORTED_PYTHON_VERSIONS_PLONE61} - {term}`pipx` - {term}`nvm` - {term}`Node.js` LTS 20.x diff --git a/docs/install/create-project.md b/docs/install/create-project.md index 2d8a46500..e4b30d081 100644 --- a/docs/install/create-project.md +++ b/docs/install/create-project.md @@ -45,7 +45,7 @@ Plone 6 has both hardware requirements and software prerequisites. ```{include} ../volto/contributing/install-operating-system.md ``` -- Python {SUPPORTED_PYTHON_VERSIONS} +- Python {SUPPORTED_PYTHON_VERSIONS_PLONE60} - {term}`pipx` - {term}`nvm` - {term}`Node.js` LTS 20.x From 6a1211b3c419feaf735e53a4ac093e4beb2da964 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 2 Nov 2024 04:32:47 -0700 Subject: [PATCH 479/810] Add include for installing Python. Add install Buildout as a pre-requisite. --- docs/_inc/_install-python-plone61.md | 8 ++++++++ docs/admin-guide/install-buildout.md | 17 ++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 docs/_inc/_install-python-plone61.md diff --git a/docs/_inc/_install-python-plone61.md b/docs/_inc/_install-python-plone61.md new file mode 100644 index 000000000..ce7e2c497 --- /dev/null +++ b/docs/_inc/_install-python-plone61.md @@ -0,0 +1,8 @@ +Installing Python is beyond the scope of this documentation. +However, it is recommended to use a Python version manager, {term}`pyenv`, that allows you to install multiple versions of Python on your development environment without destroying your system's Python. +% TODO: uncomment this line after upgrading to plone-sphinx-theme and latest Sphinx which supports replacements inside includes. +% Plone requires Python version {SUPPORTED_PYTHON_VERSIONS_PLONE61}. + +Plone 6.0 requires Python version 3.8, 3.9, 3.10, 3.11, or 3.12. + +Plone 6.1 requires Python version 3.10, 3.11, or 3.12. diff --git a/docs/admin-guide/install-buildout.md b/docs/admin-guide/install-buildout.md index d5ef7ca5e..f3685eb7e 100644 --- a/docs/admin-guide/install-buildout.md +++ b/docs/admin-guide/install-buildout.md @@ -22,16 +22,23 @@ For other installation options, see {ref}`get-started-install-label`. (install-buildout-prerequisites)= -## Prerequisites +## Prerequisites for installation -- Python (SUPPORTED_PYTHON_VERSIONS_PLONE61) +- For Plone 6.0, Python {SUPPORTED_PYTHON_VERSIONS_PLONE60} +- For Plone 6.1, Python {SUPPORTED_PYTHON_VERSIONS_PLONE61} +- Buildout -On Debian-based Linux systems you can install Python with the following command: -```shell -sudo apt install python3.12 python3.12-dev python3.12-venv +### Python + +```{include} /_inc/_install-python-plone61.md ``` +### Buildout + +See [Getting started with Buildout](http://www.buildout.org/en/latest/getting-started.html). + + ## Installation Select a directory of your choice: From ee90925be1024cc7e9ab966adfee32ef8f223a60 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 2 Nov 2024 05:05:30 -0700 Subject: [PATCH 480/810] Update include for installing Python, to avoid repetition. Update after walk-through of process, adding missing bits and pieces. --- docs/_inc/_install-python-plone61.md | 4 --- docs/admin-guide/install-buildout.md | 46 +++++++++++++++++++--------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/docs/_inc/_install-python-plone61.md b/docs/_inc/_install-python-plone61.md index ce7e2c497..71ced9e9c 100644 --- a/docs/_inc/_install-python-plone61.md +++ b/docs/_inc/_install-python-plone61.md @@ -2,7 +2,3 @@ Installing Python is beyond the scope of this documentation. However, it is recommended to use a Python version manager, {term}`pyenv`, that allows you to install multiple versions of Python on your development environment without destroying your system's Python. % TODO: uncomment this line after upgrading to plone-sphinx-theme and latest Sphinx which supports replacements inside includes. % Plone requires Python version {SUPPORTED_PYTHON_VERSIONS_PLONE61}. - -Plone 6.0 requires Python version 3.8, 3.9, 3.10, 3.11, or 3.12. - -Plone 6.1 requires Python version 3.10, 3.11, or 3.12. diff --git a/docs/admin-guide/install-buildout.md b/docs/admin-guide/install-buildout.md index f3685eb7e..d6b56ee76 100644 --- a/docs/admin-guide/install-buildout.md +++ b/docs/admin-guide/install-buildout.md @@ -14,7 +14,7 @@ myst: This chapter describes how you can install Plone using {term}`Buildout`. This is one way to install Plone with the Classic UI. -Using Buildout will be the most familiar approach for admins who have experience with Plone 3, 4, or 5. +Using Buildout will be the most familiar approach for administrators who have experience with Plone 3, 4, or 5. ```{seealso} For other installation options, see {ref}`get-started-install-label`. @@ -26,7 +26,6 @@ For other installation options, see {ref}`get-started-install-label`. - For Plone 6.0, Python {SUPPORTED_PYTHON_VERSIONS_PLONE60} - For Plone 6.1, Python {SUPPORTED_PYTHON_VERSIONS_PLONE61} -- Buildout ### Python @@ -34,31 +33,33 @@ For other installation options, see {ref}`get-started-install-label`. ```{include} /_inc/_install-python-plone61.md ``` -### Buildout - -See [Getting started with Buildout](http://www.buildout.org/en/latest/getting-started.html). - ## Installation -Select a directory of your choice: +Select a directory of your choice. ```shell -mkdir -p /opt/plone && cd /opt/plone +mkdir -p /plone && cd /plone ``` -Create a Python virtual environment: +Create a Python virtual environment. ```shell python3 -m venv . ``` -Install the minimal Python packages needed in order to run Buildout: +Install the minimal Python packages needed in order to run Buildout. ```shell bin/pip install -r https://dist.plone.org/release/6-latest/requirements.txt ``` +Install Buildout into the Python virtual environment. + +```shell +bin/pip install zc.buildout +``` + Create a `buildout.cfg` file in your directory with the following contents: ```cfg @@ -77,12 +78,15 @@ eggs = Plone ``` -Run buildout: +Run Buildout. ```shell bin/buildout ``` +This may take a few minutes. + + ## Run Plone in foreground mode Start the instance for a quick test in foreground mode: @@ -91,21 +95,33 @@ Start the instance for a quick test in foreground mode: bin/instance fg ``` -Your instance starts in foreground mode, which is only advisable for troubleshooting or for local demonstration purposes. +Your instance starts in foreground mode. +This should be used only for troubleshooting or local demonstration purposes. + +Now you can visit `http://localhost:8080` in your browser. +Select {guilabel}`Create Classic UI Plone site`. + +Enter {guilabel}`username` of `admin`, and {guilabel}`password` of `admin`. + +Fill out the form as needed, and click {guilabel}`Create Plone Site`. + +You will be redirected to your new Plone instance. + +To stop the Plone instance in foreground mode, type {kbd}`CTRL-C`. -Now you can call the url `http://localhost:8080` in your browser and you can add a **Classic UI Plone site**. ## Start Plone as a background service -Start the instance: +Start the instance. ```shell bin/instance start ``` + ## Stop Plone as a background service -Stop the instance: +Stop the instance. ```shell bin/instance stop From a9163ca0d4a3c1482f72b4a0c35312d697576b20 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 2 Nov 2024 05:41:52 -0700 Subject: [PATCH 481/810] The buildout instructions install only Plone 6.0.x --- docs/admin-guide/install-buildout.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/admin-guide/install-buildout.md b/docs/admin-guide/install-buildout.md index d6b56ee76..826b6ec02 100644 --- a/docs/admin-guide/install-buildout.md +++ b/docs/admin-guide/install-buildout.md @@ -24,13 +24,14 @@ For other installation options, see {ref}`get-started-install-label`. ## Prerequisites for installation -- For Plone 6.0, Python {SUPPORTED_PYTHON_VERSIONS_PLONE60} -- For Plone 6.1, Python {SUPPORTED_PYTHON_VERSIONS_PLONE61} +- For Plone 6.0, Python {SUPPORTED_PYTHON_VERSIONS_PLONE60} +% TODO: These instructions install Plone 6.0.x. Uncomment next line and change the subsequent include when Plone 6.1 is released and "latest". +% - For Plone 6.1, Python {SUPPORTED_PYTHON_VERSIONS_PLONE61} ### Python -```{include} /_inc/_install-python-plone61.md +```{include} /_inc/_install-python-plone60.md ``` From f40a97390621167beb87979925814ff609f12000 Mon Sep 17 00:00:00 2001 From: David Glick Date: Sat, 2 Nov 2024 10:43:00 -0700 Subject: [PATCH 482/810] Remove redundant installation of buildout --- docs/admin-guide/install-buildout.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/admin-guide/install-buildout.md b/docs/admin-guide/install-buildout.md index 826b6ec02..2089e7096 100644 --- a/docs/admin-guide/install-buildout.md +++ b/docs/admin-guide/install-buildout.md @@ -55,12 +55,6 @@ Install the minimal Python packages needed in order to run Buildout. bin/pip install -r https://dist.plone.org/release/6-latest/requirements.txt ``` -Install Buildout into the Python virtual environment. - -```shell -bin/pip install zc.buildout -``` - Create a `buildout.cfg` file in your directory with the following contents: ```cfg From 0ce3e0679b35664f5008e5e79e2dbb1f801bc54e Mon Sep 17 00:00:00 2001 From: David Glick Date: Sat, 2 Nov 2024 10:51:51 -0700 Subject: [PATCH 483/810] Recommend Plone 6.1 Python versions for core development --- docs/contributing/core/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 5ea3833ca..b97749a44 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -40,7 +40,7 @@ However, the following links and sections below may be helpful. ```{include} ../../volto/contributing/install-operating-system.md ``` -- Python {SUPPORTED_PYTHON_VERSIONS_PLONE60} +- Python {SUPPORTED_PYTHON_VERSIONS_PLONE61} - {term}`GNU make` - {term}`Git` - A C compiler @@ -50,7 +50,7 @@ However, the following links and sections below may be helpful. Installing Python is beyond the scope of this documentation. However, it is recommended to use a Python version manager, {term}`pyenv` that allows you to install multiple versions of Python on your development environment without destroying your system's Python. -Plone requires Python version {SUPPORTED_PYTHON_VERSIONS_PLONE60}. +Plone requires Python version {SUPPORTED_PYTHON_VERSIONS_PLONE61}. ### Make From 242ba6f000a2dbe87cd38a781d402cedfbb23d57 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 3 Nov 2024 01:22:10 -0800 Subject: [PATCH 484/810] Make includes for Python version more consistent and explicit --- docs/_inc/{_install-python.md => _install-python-plone60.md} | 2 +- docs/_inc/_install-python-plone61.md | 2 ++ docs/install/create-project-cookieplone.md | 2 +- docs/install/create-project.md | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) rename docs/_inc/{_install-python.md => _install-python-plone60.md} (87%) diff --git a/docs/_inc/_install-python.md b/docs/_inc/_install-python-plone60.md similarity index 87% rename from docs/_inc/_install-python.md rename to docs/_inc/_install-python-plone60.md index 29bf96a84..4ecb3f935 100644 --- a/docs/_inc/_install-python.md +++ b/docs/_inc/_install-python-plone60.md @@ -3,4 +3,4 @@ However, it is recommended to use a Python version manager, {term}`pyenv`, that % TODO: uncomment this line after upgrading to plone-sphinx-theme and latest Sphinx which supports replacements inside includes. % Plone requires Python version {SUPPORTED_PYTHON_VERSIONS_PLONE60}. -Plone requires Python version 3.8, 3.9, 3.10, 3.11, or 3.12. +Plone 6.0 requires Python version 3.8, 3.9, 3.10, 3.11, or 3.12. diff --git a/docs/_inc/_install-python-plone61.md b/docs/_inc/_install-python-plone61.md index 71ced9e9c..9533139b3 100644 --- a/docs/_inc/_install-python-plone61.md +++ b/docs/_inc/_install-python-plone61.md @@ -2,3 +2,5 @@ Installing Python is beyond the scope of this documentation. However, it is recommended to use a Python version manager, {term}`pyenv`, that allows you to install multiple versions of Python on your development environment without destroying your system's Python. % TODO: uncomment this line after upgrading to plone-sphinx-theme and latest Sphinx which supports replacements inside includes. % Plone requires Python version {SUPPORTED_PYTHON_VERSIONS_PLONE61}. + +Plone 6.1 requires Python version 3.10, 3.11, or 3.12. diff --git a/docs/install/create-project-cookieplone.md b/docs/install/create-project-cookieplone.md index 29237e3d0..465bfbfdc 100644 --- a/docs/install/create-project-cookieplone.md +++ b/docs/install/create-project-cookieplone.md @@ -53,7 +53,7 @@ Plone 6 has both hardware requirements and software prerequisites. #### Python -```{include} /_inc/_install-python.md +```{include} /_inc/_install-python-plone61.md ``` diff --git a/docs/install/create-project.md b/docs/install/create-project.md index e4b30d081..473311032 100644 --- a/docs/install/create-project.md +++ b/docs/install/create-project.md @@ -60,7 +60,7 @@ Plone 6 has both hardware requirements and software prerequisites. #### Python -```{include} /_inc/_install-python.md +```{include} /_inc/_install-python-plone60.md ``` From cec89fe2ff6126bdb7ec8462f14e2ab3d8533eb9 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 3 Nov 2024 01:57:13 -0800 Subject: [PATCH 485/810] Use an include for creating a Classic UI instance in foreground mode --- docs/_inc/_create-classic-ui-instance.inc | 15 +++++++++ docs/admin-guide/install-buildout.md | 25 +++++--------- docs/admin-guide/install-pip.md | 40 +++++++++++++---------- docs/contributing/core/index.md | 15 ++------- 4 files changed, 48 insertions(+), 47 deletions(-) create mode 100644 docs/_inc/_create-classic-ui-instance.inc diff --git a/docs/_inc/_create-classic-ui-instance.inc b/docs/_inc/_create-classic-ui-instance.inc new file mode 100644 index 000000000..417e28cbb --- /dev/null +++ b/docs/_inc/_create-classic-ui-instance.inc @@ -0,0 +1,15 @@ + +Your instance starts in foreground mode. +This should be used only for troubleshooting or local demonstration purposes. + +Now you can visit `http://localhost:8080` in your browser. +Click the button {guilabel}`Create Classic UI Plone site`. + +Enter {guilabel}`username` of `admin`, and {guilabel}`password` of `admin`. + +Enter values in the form, and click the button {guilabel}`Create Plone Site`. + +You will be redirected to your new Classic UI Plone site. + +To stop the Plone instance in foreground mode, type {kbd}`CTRL-C`. + diff --git a/docs/admin-guide/install-buildout.md b/docs/admin-guide/install-buildout.md index 2089e7096..3e34244f9 100644 --- a/docs/admin-guide/install-buildout.md +++ b/docs/admin-guide/install-buildout.md @@ -37,10 +37,11 @@ For other installation options, see {ref}`get-started-install-label`. ## Installation -Select a directory of your choice. +Select a directory of your choice, and change it to your working directory. ```shell -mkdir -p /plone && cd /plone +mkdir -p /plone +cd /plone ``` Create a Python virtual environment. @@ -55,7 +56,7 @@ Install the minimal Python packages needed in order to run Buildout. bin/pip install -r https://dist.plone.org/release/6-latest/requirements.txt ``` -Create a `buildout.cfg` file in your directory with the following contents: +Create a {file}`buildout.cfg` file in your directory with the following contents. ```cfg [buildout] @@ -67,6 +68,7 @@ parts = [instance] recipe = plone.recipe.zope2instance +# user = username:password - Use a secure token in a production environment. user = admin:admin http-address = 8080 eggs = @@ -82,7 +84,7 @@ bin/buildout This may take a few minutes. -## Run Plone in foreground mode +## Start Plone in foreground mode Start the instance for a quick test in foreground mode: @@ -90,19 +92,8 @@ Start the instance for a quick test in foreground mode: bin/instance fg ``` -Your instance starts in foreground mode. -This should be used only for troubleshooting or local demonstration purposes. - -Now you can visit `http://localhost:8080` in your browser. -Select {guilabel}`Create Classic UI Plone site`. - -Enter {guilabel}`username` of `admin`, and {guilabel}`password` of `admin`. - -Fill out the form as needed, and click {guilabel}`Create Plone Site`. - -You will be redirected to your new Plone instance. - -To stop the Plone instance in foreground mode, type {kbd}`CTRL-C`. +```{include} /_inc/_create-classic-ui-instance.inc +``` ## Start Plone as a background service diff --git a/docs/admin-guide/install-pip.md b/docs/admin-guide/install-pip.md index 5dcb2ae4a..e6597a1d0 100644 --- a/docs/admin-guide/install-pip.md +++ b/docs/admin-guide/install-pip.md @@ -20,45 +20,51 @@ It provides a basic installation without many additional tools to help with deve For other installation options, see {ref}`get-started-install-label`. ``` -## Prerequisites +(install-pip-prerequisites)= -- Python 3.10 or greater +## Prerequisites for installation -On Debian-based systems you can install Python with following command: +- For Plone 6.0, Python {SUPPORTED_PYTHON_VERSIONS_PLONE60} +% TODO: These instructions install Plone 6.0.x. Uncomment next line and change the subsequent include when Plone 6.1 is released and "latest". +% - For Plone 6.1, Python {SUPPORTED_PYTHON_VERSIONS_PLONE61} -```shell -sudo apt install python3.12 python3.12-dev python3.12-venv + +### Python + +```{include} /_inc/_install-python-plone60.md ``` + ## Installation -Select a directory of your choice: +Select a directory of your choice, and change it to your working directory. ```shell -mkdir -p /opt/plone -cd /opt/plone +mkdir -p /plone +cd /plone ``` -Create a Python virtual environment: +Create a Python virtual environment. ```shell python3 -m venv . ``` -Install Plone and a helper package: +Install Plone and a helper package, {term}`pipx`. ```shell bin/pip install -c https://dist.plone.org/release/6.0-latest/constraints.txt Plone pipx ``` + ## Create a Zope instance -Create a file `instance.yaml` with the following contents: +Create a file {file}`instance.yaml` in your directory with the following contents. ```yaml -# please change the password to a secure token! default_context: initial_user_name: "admin" +# Use a secure token for the password in a production environment. initial_user_password: "admin" wsgi_listen: "localhost:8080" debug_mode: false @@ -69,20 +75,20 @@ default_context: } ``` -Now run the {term}`cookiecutter` tool to create configuration for a Zope instance: +Now run the {term}`cookiecutter` tool to create configuration for a Zope instance. ``` bin/pipx run cookiecutter -f --no-input --config-file instance.yaml gh:plone/cookiecutter-zope-instance ``` + ## Start Plone in foreground mode -Start the instance for a quick test: +Start the instance for a quick test. ```shell bin/runwsgi -v instance/etc/zope.ini ``` -Your instance starts in foreground mode, which is only advisable for troubleshooting or for local demonstration purposes. - -Now you can call the url `http://localhost:8080` in your browser and you can add a **Classic UI Plone site**. +```{include} /_inc/_create-classic-ui-instance.inc +``` diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index b97749a44..e5efe59f3 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -124,14 +124,8 @@ Once that's done, you can start an instance of Plone with the following command. ./bin/instance fg ``` -To visit your Plone instance, you can open the link http://0.0.0.0:8080 in a web browser. - -You will be presented with several options. -Click the button {guilabel}`Create Classic UI Plone site`. - -Enter values in the form, and click the button {guilabel}`Create Plone Site`. - -You will be redirected to your new Classic UI Plone site. +```{include} /_inc/_create-classic-ui-instance.inc +``` ```{warning} Ignore the warning about accessing the Plone backend through its Classic UI frontend. @@ -141,11 +135,6 @@ They will not work with buildout. To contribute to Volto, you will need to start over, and follow {doc}`../volto`. ``` -To login, the default credentials are the following. - -- username: `admin` -- password: `admin` - (contributing-core-work-with-git-label)= From 16285023d5bf0ef0ec297878257f9e43820bd49e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 3 Nov 2024 02:35:14 -0800 Subject: [PATCH 486/810] Update create-project.md, removing note about not documenting how to install Plone via buildout, and specifying Plone 6.0. --- docs/conf.py | 1 - docs/install/create-project.md | 24 +++++++++--------------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 8644bb392..d79793765 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -358,7 +358,6 @@ def source_replace(app, docname, source): source_replacements = { "{PLONE_BACKEND_MINOR_VERSION}": "6.0", "{PLONE_BACKEND_PATCH_VERSION}": "6.0.13", - "{NVM_VERSION}": "0.39.5", "{SUPPORTED_PYTHON_VERSIONS_PLONE60}": "3.8, 3.9, 3.10, 3.11, or 3.12", "{SUPPORTED_PYTHON_VERSIONS_PLONE61}": "3.10, 3.11, or 3.12", } diff --git a/docs/install/create-project.md b/docs/install/create-project.md index 473311032..57bf59213 100644 --- a/docs/install/create-project.md +++ b/docs/install/create-project.md @@ -10,16 +10,16 @@ myst: (create-a-project-label)= -# Install Plone with cookiecutter-plone-starter (deprecated) +# Install Plone with `cookiecutter-plone-starter` (deprecated) -This chapter describes how you can create a web application using the {term}`cookiecutter-plone-starter` template. - -```{deprecated} Plone 6.1 & Volto 18 -This way of installing Plone is now deprecated. -It was the recommended way to start a new Plone project with **Plone 6.0** and **Volto 17 or earlier**. +```{deprecated} Plone 6.1 and Volto 18 +This method to install Plone is now deprecated. +It was the recommended way to start a new Plone project with Plone 6.0 and Volto 17 or earlier. For other installation options, see {ref}`get-started-install-label`. ``` +This chapter describes how you can create a web application using the {term}`cookiecutter-plone-starter` template. + This template creates a web application using Plone with the Volto frontend, along with tools for development and deployment. @@ -27,7 +27,7 @@ This template creates a web application using Plone with the Volto frontend, alo ## System requirements -Plone 6 has both hardware requirements and software prerequisites. +Plone 6.0 has both hardware requirements and software prerequisites. (install-packages-hardware-requirements-label)= @@ -159,15 +159,9 @@ Now the instructions to install Yarn should work. (install-packages-install-label)= -## Install Plone 6 - -We install Plone 6 with {term}`pipx`, {term}`Cookiecutter`, {term}`mxdev`, {term}`make`, and other developer tools. +## Install Plone 6.0 -```{note} -We do not maintain documentation for installing Plone 6 or later with `buildout`. -For Plone 5, `buildout` was the preferred installation method. -You can read the [documentation of how to install Plone 5 with `buildout`](https://5.docs.plone.org/manage/installing/installation_minimal_buildout.html), and adapt it to your needs for Plone 6. -``` +We install Plone 6.0 with {term}`pipx`, {term}`Cookiecutter`, {term}`mxdev`, {term}`make`, and other developer tools. Create a new directory to hold your project, and make it your current directory. From b9e86b0f19fd14f1aa5537cf1867da92216c3f5e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 3 Nov 2024 02:38:33 -0800 Subject: [PATCH 487/810] Rename _create-classic-ui-instance.inc to .md --- ...e-classic-ui-instance.inc => _create-classic-ui-instance.md} | 0 docs/admin-guide/install-buildout.md | 2 +- docs/admin-guide/install-pip.md | 2 +- docs/contributing/core/index.md | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename docs/_inc/{_create-classic-ui-instance.inc => _create-classic-ui-instance.md} (100%) diff --git a/docs/_inc/_create-classic-ui-instance.inc b/docs/_inc/_create-classic-ui-instance.md similarity index 100% rename from docs/_inc/_create-classic-ui-instance.inc rename to docs/_inc/_create-classic-ui-instance.md diff --git a/docs/admin-guide/install-buildout.md b/docs/admin-guide/install-buildout.md index 3e34244f9..f0f87cc2e 100644 --- a/docs/admin-guide/install-buildout.md +++ b/docs/admin-guide/install-buildout.md @@ -92,7 +92,7 @@ Start the instance for a quick test in foreground mode: bin/instance fg ``` -```{include} /_inc/_create-classic-ui-instance.inc +```{include} /_inc/_create-classic-ui-instance.md ``` diff --git a/docs/admin-guide/install-pip.md b/docs/admin-guide/install-pip.md index e6597a1d0..62ede6906 100644 --- a/docs/admin-guide/install-pip.md +++ b/docs/admin-guide/install-pip.md @@ -90,5 +90,5 @@ Start the instance for a quick test. bin/runwsgi -v instance/etc/zope.ini ``` -```{include} /_inc/_create-classic-ui-instance.inc +```{include} /_inc/_create-classic-ui-instance.md ``` diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index e5efe59f3..565f405b0 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -124,7 +124,7 @@ Once that's done, you can start an instance of Plone with the following command. ./bin/instance fg ``` -```{include} /_inc/_create-classic-ui-instance.inc +```{include} /_inc/_create-classic-ui-instance.md ``` ```{warning} From bc07aa74b9be6a675bde31f2b1db7e66713622ed Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 3 Nov 2024 02:48:08 -0800 Subject: [PATCH 488/810] Tidy up run-plone.md, removing "with "s. Make casing of `ctrl-c` consistent. --- docs/_inc/_create-classic-ui-instance.md | 2 +- docs/admin-guide/run-plone.md | 31 ++++++++++++------------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/docs/_inc/_create-classic-ui-instance.md b/docs/_inc/_create-classic-ui-instance.md index 417e28cbb..2c768d90e 100644 --- a/docs/_inc/_create-classic-ui-instance.md +++ b/docs/_inc/_create-classic-ui-instance.md @@ -11,5 +11,5 @@ Enter values in the form, and click the button {guilabel}`Create Plone Site`. You will be redirected to your new Classic UI Plone site. -To stop the Plone instance in foreground mode, type {kbd}`CTRL-C`. +To stop the Plone instance in foreground mode, type {kbd}`ctrl-c`. diff --git a/docs/admin-guide/run-plone.md b/docs/admin-guide/run-plone.md index 728daaee6..d90e363be 100644 --- a/docs/admin-guide/run-plone.md +++ b/docs/admin-guide/run-plone.md @@ -4,7 +4,7 @@ myst: "description": "Run Plone" "property=og:description": "Run Plone" "property=og:title": "Run Plone" - "keywords": "Plone 6, run, start, command" + "keywords": "Plone 6, run, start, command, Cookieplone, Buildout, pip, cookiecutter-plone-starter" --- (run-plone-label)= @@ -17,24 +17,25 @@ There are different commands to run Plone, depending on which method you used to ## Run Plone in foreground mode -Running Plone in foreground mode will show output in the terminal. This is recommended while developing a Plone site. +Running Plone in foreground mode will show output in the terminal. +This is recommended while developing a Plone site. -with Cookieplone: +Cookieplone: : ```shell make backend-start ``` -with Buildout: +Buildout: : ```shell bin/instance fg ``` -with pip: +pip: : ```shell bin/runwsgi instance/etc/zope.ini ``` -with `cookiecutter-plone-starter`: +`cookiecutter-plone-starter`: : ```shell make start-backend ``` @@ -44,14 +45,14 @@ For any of these commands, press {kbd}`ctrl-c` to stop the process. ## Run Volto -If you are using the Volto frontend, you need to run the frontend in a separate process. +If you use the Volto frontend, you need to run the frontend in a separate process and terminal session. -with Cookieplone: +Cookieplone: : ```shell make frontend-start ``` -with `cookiecutter-plone-starter`: +`cookiecutter-plone-starter`: : ```shell make start-frontend ``` @@ -61,14 +62,14 @@ For any of these commands, press {kbd}`ctrl-c` to stop the process. ## Start Plone as a background service -with Buildout: +Buildout: : ```shell bin/instance start ``` ## Stop Plone as a background service -with Buildout: +Buildout: : ```shell bin/instance stop ``` @@ -78,22 +79,22 @@ with Buildout: The debug console gives you a Python prompt with the Plone site's configuration loaded. Use this for troubleshooting. -with Cookieplone: +Cookieplone: : ```shell make -C backend console ``` -with Buildout: +Buildout: : ```shell bin/instance debug ``` -with pip: +pip: : ```shell bin/zconsole debug instance/etc/zope.ini ``` -with `cookiecutter-plone-starter`: +`cookiecutter-plone-starter`: : ```shell make -C backend debug ``` From 72bfeee9528c66581af7a90f225f99b6222e5af6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 3 Nov 2024 03:05:24 -0800 Subject: [PATCH 489/810] Tidy up configure-zope.md --- docs/admin-guide/configure-zope.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/admin-guide/configure-zope.md b/docs/admin-guide/configure-zope.md index 0f05786ca..e703cd211 100644 --- a/docs/admin-guide/configure-zope.md +++ b/docs/admin-guide/configure-zope.md @@ -4,7 +4,7 @@ myst: "description": "Configure Zope options" "property=og:description": "Configure Zope options" "property=og:title": "Configure Zope" - "keywords": "Plone 6, Zope, instance, app server, config, cookiecutter-zope-instance" + "keywords": "Plone 6, Zope, instance, app server, config, Cookieplone, Buildout, pip, cookiecutter-plone-starter, cookiecutter-zope-instance, plone.recipe.zope2instance" --- (configure-zope-label)= @@ -15,19 +15,21 @@ Plone runs in an application server called {term}`Zope`. You can configure your Zope instance's options, including the following. -* persistent storage: blobs, direct filestorage, relation database, ZEO, and so on -* ports -* threads -* cache -* logging -* debugging and profiling for development +- persistent storage: blobs, direct file storage, relational database, ZEO, and other storage mechanisms +- ports +- threads +- cache +- logging +- debugging and profiling for development -## with Cookieplone + +## Via Cookieplone If you installed Plone using Cookieplone, `cookiecutter-plone-starter`, or pip, then Zope is configured using {term}`cookiecutter-zope-instance`. For a complete list of features, usage, and options, read [`cookiecutter-zope-instance`'s README](https://github.com/plone/cookiecutter-zope-instance#readme). -## with Buildout + +## Via Buildout If you installed Plone using Buildout, then Zope is configured using `plone.recipe.zope2instance`. For a complete list of features, usage, and options, read [`plone.recipe.zope2instance`'s README](https://pypi.org/project/plone.recipe.zope2instance/). From bc68a37f087174afc882f74443910ddcc280e4d7 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 3 Nov 2024 03:18:32 -0800 Subject: [PATCH 490/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index dcdb41bca..e63416968 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit dcdb41bcab60b4bc32fa5c685f146b40d88c33bd +Subproject commit e63416968eb390f42df50c1025395d1b3baf7f60 diff --git a/submodules/volto b/submodules/volto index bd591ca11..278ca6c38 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit bd591ca11e4a875864aa7ecf0a73f5f2f6e8153e +Subproject commit 278ca6c387ba60f98849a76dea2233113abda5ba From 8facc740134c5e9c2b99157478e6037ec15563dc Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 3 Nov 2024 03:24:59 -0800 Subject: [PATCH 491/810] Shorten headings --- docs/admin-guide/configure-zope.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/admin-guide/configure-zope.md b/docs/admin-guide/configure-zope.md index e703cd211..04b009522 100644 --- a/docs/admin-guide/configure-zope.md +++ b/docs/admin-guide/configure-zope.md @@ -23,13 +23,13 @@ You can configure your Zope instance's options, including the following. - debugging and profiling for development -## Via Cookieplone +## Cookieplone If you installed Plone using Cookieplone, `cookiecutter-plone-starter`, or pip, then Zope is configured using {term}`cookiecutter-zope-instance`. For a complete list of features, usage, and options, read [`cookiecutter-zope-instance`'s README](https://github.com/plone/cookiecutter-zope-instance#readme). -## Via Buildout +## Buildout If you installed Plone using Buildout, then Zope is configured using `plone.recipe.zope2instance`. For a complete list of features, usage, and options, read [`plone.recipe.zope2instance`'s README](https://pypi.org/project/plone.recipe.zope2instance/). From 7f7ba8c51d0435f527b69f767933231f2b8e6524 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 3 Nov 2024 03:40:06 -0800 Subject: [PATCH 492/810] Tidy up add-ons.md --- docs/admin-guide/add-ons.md | 80 +++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 29 deletions(-) diff --git a/docs/admin-guide/add-ons.md b/docs/admin-guide/add-ons.md index c6c8e6fb3..e8b631e61 100644 --- a/docs/admin-guide/add-ons.md +++ b/docs/admin-guide/add-ons.md @@ -1,29 +1,33 @@ --- myst: html_meta: - "description": "Install Plone Add-ons" - "property=og:description": "Install Plone Add-ons" - "property=og:title": "Install Plone Add-ons" - "keywords": "Plone 6, addon, add-on, package, plugin, extension, install" + "description": "Install Plone add-ons" + "property=og:description": "Install Plone add-ons" + "property=og:title": "Install Plone add-ons" + "keywords": "Plone 6, add-on, package, plugin, extension, install" --- -(install-plone-addons-label)= +(install-plone-add-ons-label)= -# Install Plone Add-ons +# Install Plone add-ons -This chapter explains how to install {term}`add-ons ` as Python packages to extend the functionality of the Plone backend or Classic UI. +This chapter explains how to install {term}`add-ons ` as Python packages to extend the functionality of the Plone backend or Classic UI. ```{note} -The Volto frontend has its own system of add-ons using Node.js packages. See {doc}`/volto/addons/index`. +The Volto frontend has its own system of add-ons using Node.js packages. +% TODO: update the following link after https://github.com/plone/volto/pull/6397 is merged to point to `/development/add-ons/index`. +See {doc}`/volto/addons/index`. ``` -## with Cookieplone -Use the following instructions if you installed Plone with Cookieplone or `cookiecutter-plone-starter`. +## Cookieplone + +Use the following instructions if you installed Plone with either Cookieplone or `cookiecutter-plone-starter`. + ### Install an add-on -Add a line with the name of your add-on in `backend/requirements.txt`. +Add a line with the name of your add-on in the file {file}`backend/requirements.txt`. This example uses [`collective.easyform`](https://pypi.org/project/collective.easyform/). ``` @@ -31,10 +35,10 @@ collective.easyform==4.2.1 ``` ```{tip} -Including the add-on version ensures that it won't accidentally get upgraded in the future. +Including the add-on version, or "pinning a version", ensures that it won't unintentionally get upgraded in the future. ``` -Also add the add-on to `zcml_package_includes` in {file}`backend/instance.yaml` to make sure its configuration will be loaded: +Also add the add-on to `zcml_package_includes` in the file {file}`backend/instance.yaml` to make sure its configuration will be loaded. ```yaml default_context: @@ -43,19 +47,23 @@ default_context: Stop the backend with {kbd}`ctrl-c`. -To actually download and install the new add-on, run: +To actually download and install the new add-on, run the following command. ```shell make backend-build ``` ```{note} -If you installed Plone using `cookiecutter-plone-starter`, run `make build-backend` instead.` +If you installed Plone using `cookiecutter-plone-starter`, run `make build-backend` instead. ``` Now restart the backend. -In your web browser, and assuming you are currently logged in as `admin`, visit the URL http://localhost:8080/Plone/prefs_install_products_form. +```{seealso} +{doc}`run-plone` +``` + +In your web browser, and assuming you are currently logged in as an administrator, visit the URL http://localhost:8080/Plone/prefs_install_products_form. Then click the {guilabel}`Install` button next to your add-on to complete installation of the add-on. @@ -68,7 +76,7 @@ At the bottom of the page, you should see the heading {guilabel}`Add-on Configur An add-on can be installed from a source control system such as GitHub. -Add a line with the name of your add-on in `backend/requirements.txt`. +Add a line with the name of your add-on in the file {file}`backend/requirements.txt`. This example uses [`collective.easyform`](https://pypi.org/project/collective.easyform/). ``` @@ -76,17 +84,18 @@ collective.easyform ``` ```{note} -When installing an add-on from source, it's best to not pin a version, to make sure we use the version that's currently available in the source control system. +When installing an add-on from source, it's best not to pin a version. +This way you always get the version that's currently available in the source control system. ``` -Also add the add-on to `zcml_package_includes` in {file}`backend/instance.yaml` to make sure its configuration will be loaded: +Next add the add-on to `zcml_package_includes` in the file {file}`backend/instance.yaml` so that its configuration will load. ```yaml default_context: zcml_package_includes: project_title, collective.easyform ``` -Finally, add the package's source to {file}`mx.ini`: +Finally, add the package's source to the file {file}`mx.ini`. ```cfg [collective.easyform] @@ -102,19 +111,23 @@ See the [documentation of `mxdev` in its README.md](https://github.com/mxstack/m Stop the backend with {kbd}`ctrl-c`. -To actually download and install the new add-on, run: +To actually download and install the new add-on, run the following command. ```shell make backend-build ``` ```{note} -If you installed Plone using `cookiecutter-plone-starter`, run `make build-backend` instead.` +If you installed Plone using `cookiecutter-plone-starter`, run `make build-backend` instead. ``` Now restart the backend. -In your web browser, and assuming you are currently logged in as `admin`, visit the URL http://localhost:8080/Plone/prefs_install_products_form. +```{seealso} +{doc}`run-plone` +``` + +In your web browser, and assuming you are currently logged in as an administrator, visit the URL http://localhost:8080/Plone/prefs_install_products_form. An upgrade step might need to be performed in the Plone control panel. Follow the upgrade information, if present. Else click the {guilabel}`Install` button to complete installation of the add-on. @@ -126,7 +139,7 @@ Use the following instructions if you installed Plone with Buildout. ### Install an add-on -Update {file}`buildout.cfg`. +Update the file {file}`buildout.cfg`. This example uses [`collective.easyform`](https://pypi.org/project/collective.easyform/). ```cfg @@ -150,10 +163,10 @@ collective.easyform = 4.2.1 ``` ```{tip} -Including the add-on version ensures that it won't accidentally get upgraded in the future. +Including the add-on version, or "pinning a version", ensures that it won't unintentionally get upgraded in the future. ``` -To actually download and install the new add-on, run: +To actually download and install the new add-on, run the following command. ```shell bin/buildout @@ -161,11 +174,16 @@ bin/buildout Then restart your instance. +```{seealso} +{doc}`run-plone` +``` + + ### Install an add-on from source -An add-on can be installed from a source control system such as GitHub. +You can install an add-on from a source control system such as GitHub. -Update {file}`buildout.cfg`. +Update the file {file}`buildout.cfg`. This example uses [`collective.easyform`](https://pypi.org/project/collective.easyform/). ```cfg @@ -191,7 +209,7 @@ eggs = collective.easyform = git https://github.com/collective/collective.easyform.git ``` -To actually download and install the new add-on, run: +To actually download and install the new add-on, run the following command. ```shell bin/buildout @@ -199,6 +217,10 @@ bin/buildout Then restart your instance. +```{seealso} +{doc}`run-plone` +``` + ```{seealso} This approach uses the [`mr.developer`](https://pypi.org/project/mr.developer/) Buildout extension. ``` From d8900d0a22f46465bbfa8e21165b721ca7f55cad Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 3 Nov 2024 03:58:06 -0800 Subject: [PATCH 493/810] Tidy up override-core.md --- docs/admin-guide/override-core.md | 49 +++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/docs/admin-guide/override-core.md b/docs/admin-guide/override-core.md index 38f80abd4..0723576be 100644 --- a/docs/admin-guide/override-core.md +++ b/docs/admin-guide/override-core.md @@ -4,24 +4,25 @@ myst: "description": "Override core Plone packages" "property=og:description": "Override core Plone packages" "property=og:title": "Override core Plone packages" - "keywords": "Plone 6, core, package, version, override" + "keywords": "Plone 6, core, package, version, override, Cookieplone, cookiecutter-plone-starter, Buildout" --- (override-core-plone-packages-label)= # Override core Plone packages -Plone includes a lot of Python packages. -Sometimes it is necessary to override one or more package versions in order to fix a bug. +Plone includes a few hundred Python packages. +Sometimes you will need to override one or more package versions to fix a bug. -## with Cookieplone +## Cookieplone Use the following instructions if you installed Plone with Cookieplone or `cookiecutter-plone-starter`. + ### Override a core Plone package -Add a version override to {file}`mx.ini`. +Add a version override to the file {file}`mx.ini`. This example uses `plone.api`. ``` @@ -37,24 +38,28 @@ For an explanation of why Plone uses `mxdev`, see {ref}`manage-backend-python-pa Stop the backend with {kbd}`ctrl-c`. -To actually download and install the new package version, run: +To actually download and install the new package version, run the following command. ```shell make backend-build ``` ```{note} -If you installed Plone using `cookiecutter-plone-starter`, run `make build-backend` instead.` +If you installed Plone using `cookiecutter-plone-starter`, run `make build-backend` instead. ``` Now restart the backend. +```{seealso} +{doc}`run-plone` +``` + ### Install a core Plone package from source -`mxdev` can also be used to install core Plone packages from a source control system such as GitHub. +You can also use `mxdev` to install core Plone packages from a source control system such as GitHub. -Add the Plone package you want to check out in {file}`mx.ini`. +Add the Plone package you want to check out in the file {file}`mx.ini`. This example uses `plone.restapi`. ```cfg @@ -66,7 +71,7 @@ extras = test Stop the backend with {kbd}`ctrl-c`. -To actually download and install the new package version, run: +To actually download and install the new package version, run the following command. ```shell make backend-build @@ -78,14 +83,18 @@ If you installed Plone using `cookiecutter-plone-starter`, run `make build-backe Now restart the backend. +```{seealso} +{doc}`run-plone` +``` + -## with Buildout +## Buildout Use the following instructions if you installed Plone with Buildout. ### Override a core Plone package -Update {file}`buildout.cfg`. +Update the file {file}`buildout.cfg`. This example uses `plone.api`. ```cfg @@ -111,7 +120,7 @@ plone.api = 2.0.0a3 The version pins specified in the `[versions]` section will take precedence over the pins inherited from `https://dist.plone.org/release/6-latest/versions.cfg`. ``` -To actually download and install the new package version, run: +To actually download and install the new package version, run the following command. ```shell bin/buildout @@ -119,12 +128,16 @@ bin/buildout Then restart your instance. +```{seealso} +{doc}`run-plone` +``` + ### Install a core Plone package from source A core Plone package can be installed from a source control system such as GitHub. -Update {file}`buildout.cfg`. +Update the file {file}`buildout.cfg`. This example uses `plone.restapi`. ```cfg @@ -156,12 +169,18 @@ plone.restapi = Setting an empty version ensures that the copy of `plone.restapi` from source control will be used, instead of the version pin inherited from https://dist.plone.org/release/6-latest/versions.cfg. ``` -To actually download and install the new add-on, run: +To actually download and install the new add-on, run the following command. ```shell bin/buildout ``` +Then restart your instance. + +```{seealso} +{doc}`run-plone` +``` + ```{seealso} This approach uses the [`mr.developer`](https://pypi.org/project/mr.developer/) Buildout extension. ``` From e2f617cca90690cef22980b51a16cb105a5873ff Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 3 Nov 2024 04:06:34 -0800 Subject: [PATCH 494/810] Change passive to active voice --- docs/install/containers/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install/containers/index.md b/docs/install/containers/index.md index 6c925d4a9..0d75813d8 100644 --- a/docs/install/containers/index.md +++ b/docs/install/containers/index.md @@ -14,7 +14,7 @@ myst: The Plone 6 images have all the system requirements, prerequisites, and Plone 6 already installed, except those requirements needed for running the container engine itself. Using containers is the easiest way to deploy Plone 6. -Containers may also be used when {doc}`creating a Plone project `. +You may also use containers when {doc}`creating a Plone project `. The Plone 6 container images are compliant with the [Open Container Initiative (OCI)](https://opencontainers.org/). They should work with any OCI-compliant container engine for developing, managing, and running Plone 6 images. From 0675809af3218b72cb43e1479b9834943734010b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 3 Nov 2024 04:24:09 -0800 Subject: [PATCH 495/810] Tidy up docs/install/index.md by reformatting Try a Plone demo section, improving parity between Volto and Classic UI as frontends in Plone 6, and adding mention of PloneConf. --- docs/install/index.md | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/docs/install/index.md b/docs/install/index.md index 84c4707db..890ae545e 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -4,7 +4,7 @@ myst: "description": "Get started with Plone 6" "property=og:description": "Get started with Plone 6" "property=og:title": "Get started" - "keywords": "Plone 6, install, overview" + "keywords": "Plone 6, install" --- (get-started-label)= @@ -24,30 +24,41 @@ This part of the documentation helps you find the best way to get started with P Choose a version to demo. -- [Plone 6 with Volto frontend](https://demo.plone.org/) -- [Plone 6 with Classic UI](https://classic.demo.plone.org/login?came_from=/en) +https://volto.demo.plone.org/ +: Plone 6 with Volto frontend + +https://demo.plone.org/ +: Plone 6 with Volto frontend and some add-ons, including Volto Light Theme, with content that demonstrates all the content types of Plone and blocks in Volto + +[https://classic.demo.plone.org/](https://classic.demo.plone.org/login?came_from=/en) +: Plone 6 with Classic UI frontend (get-started-install-label)= ## Install Plone -First, choose a Plone frontend. [TODO: add link to explanation of how to choose] -(If you are following a [Plone training](https://training.plone.org/), it should specify which option to choose.) +First, choose a Plone user interface, or frontend. + +```{TODO} +Add link to explanation of how to choose a frontend. +``` + +If you are following a [Plone training](https://training.plone.org/), it should specify which option to choose. {doc}`create-project-cookieplone` : This is the recommended way to install Plone for a new project with the Volto frontend. {doc}`/admin-guide/install-buildout` -: This is one way to install Plone with the Classic UI. +: This is one way to install Plone with the Classic UI frontend. Using Buildout will be the most familiar way for admins who have experience with Plone 3, 4, or 5. {doc}`/admin-guide/install-pip` -: This is one way to install Plone with the Classic UI. +: This is one way to install Plone with the Classic UI frontend. It provides a basic installation without many additional tools to help with development. {doc}`create-project` -: This was the recommended way to install Plone 6.0 for a new project with the Volto frontend. +: Installing Plone 6.0 with `cookiecutter-plone-starter` was the recommended way to install for a new project with the Volto frontend, but it is now deprecated in Plone 6.1. {doc}`Install Plone as a contributor ` : This option is for developers who want to contribute to Plone and its packages. @@ -60,6 +71,7 @@ First, choose a Plone frontend. [TODO: add link to explanation of how to choose] The {doc}`/conceptual-guides/index` explain concepts to help you understand Plone. The community has created a set of [Plone trainings](https://training.plone.org/) which are hosted separately from the documentation. +Plone trainings take place at every annual Plone Conference. (get-started-contribute-label)= @@ -67,6 +79,3 @@ The community has created a set of [Plone trainings](https://training.plone.org/ ## Contribute to Plone See the {doc}`Contributor Guide ` to learn how to participate in the Plone community and contribute to our open source software. - - -(install-index-getting-started-label)= From c4954cf23fbe9c9476648962d625bc9a08485f66 Mon Sep 17 00:00:00 2001 From: David Glick Date: Sun, 3 Nov 2024 14:23:37 -0800 Subject: [PATCH 496/810] Use include for Python section of docs setup --- docs/contributing/documentation/setup-build.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/contributing/documentation/setup-build.md b/docs/contributing/documentation/setup-build.md index eb9452579..d6d663426 100644 --- a/docs/contributing/documentation/setup-build.md +++ b/docs/contributing/documentation/setup-build.md @@ -31,10 +31,8 @@ Installation of Plone 6 Documentation includes prerequisites and the repository ### Python -Installing Python is beyond the scope of this documentation. -However, it is recommended to use a Python version manager, {term}`pyenv` that allows you to install multiple versions of Python on your development environment without destroying your system's Python. -Plone requires Python version {SUPPORTED_PYTHON_VERSIONS_PLONE60}. - +```{include} /_inc/_install-python-plone60.md +``` (setup-build-installation-gnu-make-label)= From 52e2cd948567e6b8d6ddf2cdeac6a53a18818d47 Mon Sep 17 00:00:00 2001 From: David Glick Date: Sun, 3 Nov 2024 14:27:00 -0800 Subject: [PATCH 497/810] Use a myst-parser comment for TODO in /install/index.md --- docs/install/index.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/install/index.md b/docs/install/index.md index 890ae545e..c82a8db06 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -39,10 +39,7 @@ https://demo.plone.org/ ## Install Plone First, choose a Plone user interface, or frontend. - -```{TODO} -Add link to explanation of how to choose a frontend. -``` +% TODO: once https://github.com/plone/documentation/pull/1749 is merged, link to it If you are following a [Plone training](https://training.plone.org/), it should specify which option to choose. From 97301306ed78484f3ddbf242c4e25ddb9f96e7e1 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 4 Nov 2024 02:11:44 -0800 Subject: [PATCH 498/810] Minor tweaks to glossary.md, with a cross-reference from element to blocks. --- docs/glossary.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/glossary.md b/docs/glossary.md index f1200cb14..5dce1384a 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -172,7 +172,7 @@ blocks Blocks are the fundamental components of a page layout in {term}`Volto`. element - Elements are the dynamic components of your blocks. + Elements are the dynamic components of your {term}`blocks`. They can be input fields, buttons, or computed HTML. They can also return JSON if you call them from a JavaScript app. @@ -419,7 +419,7 @@ Traefik Proxy Volto [Volto](https://github.com/plone/volto) is a React-based frontend for Plone. - It is one of two supported user interfaces for Plone 6. + It is one of two supported user interfaces, or frontends, for Plone 6. ````{seealso} {doc}`/conceptual-guides/choose-user-interface` @@ -427,7 +427,7 @@ Volto Classic UI Classic UI is a frontend for Plone 6 that is based on {term}`ZPT` and {term}`Mockup`. - It is one of two supported user interfaces for Plone 6. + It is one of two supported user interfaces, or frontends, for Plone 6. ````{seealso} {doc}`/conceptual-guides/choose-user-interface` @@ -803,6 +803,6 @@ reference implementation The reference implementation often accompanies a technical standard, and demonstrates what should be considered the "correct" behavior of any other implementation of it. portlets - Portlets are widgets that can be inserted in predefined locations in {term}`Classic UI`. + Portlets are widgets that can be inserted in predefined locations in pages in {term}`Classic UI`. Portlets are most commonly used to add sidebars to the left or right of the main page content. ``` From d241fe5bd6dcf2779bd1aa689136f9ce78d0480b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 4 Nov 2024 02:17:32 -0800 Subject: [PATCH 499/810] Rephrase the first sentence. --- docs/install/index.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/install/index.md b/docs/install/index.md index 9022c883b..b9729b834 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -19,9 +19,10 @@ You can also {ref}`try a Plone demo `. ## Get started -First, read {doc}`/conceptual-guides/choose-user-interface` to choose between Volto and Classic UI. +First choose a user interface for your Plone project. +You can read {doc}`/conceptual-guides/choose-user-interface` to help inform your choice between Volto and Classic UI. -Then, choose one of the following install methods. +Then choose one of the following installation methods. If you are following a [Plone training](https://training.plone.org/), it should specify which option to choose. {doc}`create-project` From 033e16039918857c0c2223dd8dd84a571d0fedc4 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 4 Nov 2024 02:19:39 -0800 Subject: [PATCH 500/810] Polish up classic-ui/index.md --- docs/classic-ui/index.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/classic-ui/index.md b/docs/classic-ui/index.md index dfc6949ce..b42ccd08e 100644 --- a/docs/classic-ui/index.md +++ b/docs/classic-ui/index.md @@ -11,10 +11,11 @@ myst: # Classic UI -This chapter is a developer reference manual for working with Classic UI. +This chapter is a developer reference manual for working with {term}`Classic UI`. ```{seealso} -Plone has two user interfaces, Volto and Classic UI. To understand the difference, see {doc}`/conceptual-guides/choose-user-interface`. +Plone has two user interfaces, Volto and Classic UI. +To understand their differences, see {doc}`/conceptual-guides/choose-user-interface`. ``` ```{toctree} From 7b6505195288616cefa8bcd3e9d7a8f7dc331012 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 4 Nov 2024 03:00:59 -0800 Subject: [PATCH 501/810] Added some spit and polish around the excellent content that we have needed for over two years. Thank you, and amen, @davisagli! - Add note about migration between UIs. - Explain purpose of this document. - Switch MyST markup from colon to backtick to support colon-based options. - Eliminated spacing around and between the two columns. - Set breakpoints to display columns side-by-side on only widest displays, else it gets smooshed up into an illegible mess. - Added a target to make the images clickable so they can be viewed in all their glory. - Update Glossary with missing terms and add references. --- .../choose-user-interface.md | 67 ++++++++++--------- docs/glossary.md | 16 +++-- 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/docs/conceptual-guides/choose-user-interface.md b/docs/conceptual-guides/choose-user-interface.md index 9c9fe38cf..d06b2e855 100644 --- a/docs/conceptual-guides/choose-user-interface.md +++ b/docs/conceptual-guides/choose-user-interface.md @@ -1,62 +1,67 @@ --- myst: html_meta: - "description": "Explanation of how to choose between Plone's user interfaces, Volto and Classic UI" - "property=og:description": "Explanation of how to choose between Plone's user interfaces, Volto and Classic UI" + "description": "Explanation of how to choose between Plone's two user interfaces, Volto and Classic UI" + "property=og:description": "Explanation of how to choose between Plone's two user interfaces, Volto and Classic UI" "property=og:title": "Choose a user interface" - "keywords": "Plone 6, Conceptual guides, UI, frontend, Volto, Classic UI, distribution" + "keywords": "Plone 6, Conceptual guides, UI, user interface, frontend, Volto, Classic UI, distribution" --- # Choose a user interface -Plone 6 offers two different user interfaces: Volto and Classic UI. +This guide explains the differences between Plone's two user interfaces, Volto and Classic UI, to help inform you to choose one when developing your new project in Plone, or whether to migrate from Classic UI to Volto. +There is no migration path available from Volto to Classic UI. The choice of user interface has implications for editors, admins, and developers. -::::{grid} 2 -:::{grid-item-card} Volto +`````{grid} 1 1 1 2 +:gutter: 1 +:margin: 0 +:padding: 0 +````{grid-item-card} Volto ```{image} /_static/volto-ui.png -:alt: Plone homepage in Volto +:alt: Plone home page in Volto +:target: /_static/volto-ui.png ``` For editors and other end users: -* The user interface is a fast, modern single-page web application. -* Editors create a page by arranging blocks of different types into a layout. -* There is not a comprehensive User Manual yet. +- The user interface is a fast, modern, single-page web application. +- Editors create a page by arranging {term}`blocks` of different types into a layout. +- There is not a comprehensive {doc}`/volto/user-manual/index` yet, and only a few pages exist. For developers and integrators: -* The frontend is a {term}`React`-based application written in JavaScript and TypeScript. -* The backend is a Python process which provides a REST API for the frontend. -* Python skills are not required, but can be helpful for extending the backend. -* Content is stored as structured JSON. -* Customization of themes is well-documented and relatively easy for developers who have experience with React. +- The frontend is a {term}`React`-based application written in JavaScript and TypeScript. +- The backend is a Python process which provides a {term}`REST API` for the frontend. +- Python skills are not required, but can be helpful for extending the backend. +- Content is stored as structured JSON. +- Customization of themes is well-documented and relatively easy for developers who have experience with React. +```` -::: -:::{grid-item-card} Classic UI - +````{grid-item-card} Classic UI ```{image} /_static/classic-ui.png -:alt: Plone homepage in Classic UI +:alt: Plone home page in Classic UI +:target: /_static/classic-ui.png ``` For editors and other end users: -* The user interface is similar to Plone 5. -* Editors create a page using a WYSIWYG editor (TinyMCE). -* Additional widgets can be added to predefined locations, using {term}`portlets`. -* There is a comprehensive User Manual for Plone 5, but it has not been updated for Plone 6. +- The user interface is similar to Plone 5. +- Editors create a page using a {term}`WYSIWYG` editor, {term}`TinyMCE`. +- Additional widgets can be added to predefined locations, using {term}`portlets`. +- There is a comprehensive [User Manual for Plone 5](https://5.docs.plone.org/working-with-content/index.html), but it has not been updated for Plone 6. For developers and integrators: -* The frontend and backend run in a single Python process, so hosting is a bit simpler. -* The frontend is implemented as server-side templates using the {term}`ZPT` language. -* Interactive functionality is implemented in JavaScript using {term}`Mockup`. -* The visual design is based on the {term}`Barceloneta` theme from Plone 5, but updated to use Bootstrap 5. -* Content is stored as HTML. -* Customization of themes is not well-documented. +- The frontend and backend run in a single Python process, so hosting is a bit simpler. +- The frontend is implemented as server-side templates using the {term}`ZPT` language. +- Interactive functionality is implemented in JavaScript using {term}`Mockup`. +- The visual design is based on the {term}`Barceloneta` theme from Plone 5, but updated to use Bootstrap 5. +- Content is stored as HTML. +- Customization of themes is not well-documented. -::: -:::: +```` +````` diff --git a/docs/glossary.md b/docs/glossary.md index 5dce1384a..bdf58b60b 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -104,9 +104,9 @@ pm2 [PM2](https://pm2.keymetrics.io/) is a daemon process manager. REST API - ```{todo} - REST API in general. REST API of Plone. - ``` + A REST API (also called a RESTful API or RESTful web API) is an application programming interface (API) that conforms to the design principles of the representational state transfer (REST) architectural style. + REST APIs provide a flexible, lightweight way to integrate applications and to connect components in microservices architectures. + Plone uses [`plone.restapi`](https://github.com/plone/plone.restapi/) for its REST API. S3 [Amazon Web Services S3](https://aws.amazon.com/s3/). @@ -445,11 +445,17 @@ Patternslib Accessibility, SEO, and well-structured HTML are core values of Patterns. Slate - [Slate.js](https://docs.slatejs.org/) is a highly customizable platform for creating rich-text editors, also known as `WYSIWYG` editors. + [Slate.js](https://docs.slatejs.org/) is a highly customizable platform for creating rich-text editors, also known as {term}`WYSIWYG` editors. It enables you to create powerful, intuitive editors similar to those you've probably used in Medium, Dropbox Paper, or Google Docs. `volto-slate` - `volto-slate` is an interactive default text editor for Volto, developed on top of {term}`Slate`, offering enhanced WYSIWYG functionality and behavior. + `volto-slate` is an interactive default text editor for Volto, developed on top of {term}`Slate`, offering enhanced {term}`WYSIWYG` functionality and behavior. + +WYSIWYG + WYSIWYG is an acronym for "what you see is what you get", referring to software that allows content to be edited in a form that resembles its appearance when printed or displayed as a finished product. + +TinyMCE + The rich text {term}`WYSIWYG` editor used in {term}`Classic UI`. elementEditor A generic {term}`volto-slate` plugin architecture that can be used to create other editor interactions that follow the pattern of having a button that toggles a format (an inline element). From 6130a994d4850c21d149683d44fbdb4daf04ee70 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 4 Nov 2024 03:01:34 -0800 Subject: [PATCH 502/810] One too many spaces on the indent --- docs/glossary.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/glossary.md b/docs/glossary.md index bdf58b60b..618398f6e 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -104,9 +104,9 @@ pm2 [PM2](https://pm2.keymetrics.io/) is a daemon process manager. REST API - A REST API (also called a RESTful API or RESTful web API) is an application programming interface (API) that conforms to the design principles of the representational state transfer (REST) architectural style. - REST APIs provide a flexible, lightweight way to integrate applications and to connect components in microservices architectures. - Plone uses [`plone.restapi`](https://github.com/plone/plone.restapi/) for its REST API. + A REST API (also called a RESTful API or RESTful web API) is an application programming interface (API) that conforms to the design principles of the representational state transfer (REST) architectural style. + REST APIs provide a flexible, lightweight way to integrate applications and to connect components in microservices architectures. + Plone uses [`plone.restapi`](https://github.com/plone/plone.restapi/) for its REST API. S3 [Amazon Web Services S3](https://aws.amazon.com/s3/). From cf0b656dadca6941b0aad78b382c8d30bfadfaf0 Mon Sep 17 00:00:00 2001 From: David Glick Date: Mon, 4 Nov 2024 15:50:20 -0800 Subject: [PATCH 503/810] fix merge --- docs/install/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/install/index.md b/docs/install/index.md index f4e2f8369..f3218e913 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -41,6 +41,7 @@ https://demo.plone.org/ First, choose a Plone user interface, or frontend. You can read {doc}`/conceptual-guides/choose-user-interface` to help inform your choice between Volto and Classic UI. +Then choose one of the following installation methods. If you are following a [Plone training](https://training.plone.org/), it should specify which option to choose. {doc}`create-project-cookieplone` From 8f2cec82100d47d9c9b50bddc1b437d2be4ee9f5 Mon Sep 17 00:00:00 2001 From: David Glick Date: Mon, 4 Nov 2024 15:58:17 -0800 Subject: [PATCH 504/810] Clarify the distinction in layout capabilities --- docs/conceptual-guides/choose-user-interface.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conceptual-guides/choose-user-interface.md b/docs/conceptual-guides/choose-user-interface.md index d06b2e855..084fef5cb 100644 --- a/docs/conceptual-guides/choose-user-interface.md +++ b/docs/conceptual-guides/choose-user-interface.md @@ -28,7 +28,7 @@ The choice of user interface has implications for editors, admins, and developer For editors and other end users: - The user interface is a fast, modern, single-page web application. -- Editors create a page by arranging {term}`blocks` of different types into a layout. +- Editors can create sophisticated page layouts by arranging {term}`blocks` of different types. - There is not a comprehensive {doc}`/volto/user-manual/index` yet, and only a few pages exist. For developers and integrators: @@ -51,7 +51,7 @@ For editors and other end users: - The user interface is similar to Plone 5. - Editors create a page using a {term}`WYSIWYG` editor, {term}`TinyMCE`. -- Additional widgets can be added to predefined locations, using {term}`portlets`. +- Additional widgets can be added to predefined locations, using {term}`portlets`. More sophisticated page layout requires the use of add-ons. - There is a comprehensive [User Manual for Plone 5](https://5.docs.plone.org/working-with-content/index.html), but it has not been updated for Plone 6. For developers and integrators: From 71eaab9b8b20435ca01556319aa4321f90be2f15 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 4 Nov 2024 17:29:14 -0800 Subject: [PATCH 505/810] Update docs/conceptual-guides/choose-user-interface.md --- docs/conceptual-guides/choose-user-interface.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/conceptual-guides/choose-user-interface.md b/docs/conceptual-guides/choose-user-interface.md index 084fef5cb..3a99f2b31 100644 --- a/docs/conceptual-guides/choose-user-interface.md +++ b/docs/conceptual-guides/choose-user-interface.md @@ -51,7 +51,8 @@ For editors and other end users: - The user interface is similar to Plone 5. - Editors create a page using a {term}`WYSIWYG` editor, {term}`TinyMCE`. -- Additional widgets can be added to predefined locations, using {term}`portlets`. More sophisticated page layout requires the use of add-ons. +- Additional widgets can be added to predefined locations, using {term}`portlets`. + More sophisticated page layout requires the use of add-ons. - There is a comprehensive [User Manual for Plone 5](https://5.docs.plone.org/working-with-content/index.html), but it has not been updated for Plone 6. For developers and integrators: From c80bab5be285bb7da9d31b95587d201c187e4f66 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 4 Nov 2024 20:44:53 -0800 Subject: [PATCH 506/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 278ca6c38..ac52b6bc7 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 278ca6c387ba60f98849a76dea2233113abda5ba +Subproject commit ac52b6bc748d75e81ace38b8007bc2ed1a32d92a From a0b6e183cc9add9ec87ff82d7bec8f7c61f52850 Mon Sep 17 00:00:00 2001 From: Peter Mathis Date: Tue, 5 Nov 2024 11:14:16 +0100 Subject: [PATCH 507/810] Add Plone 6.1 upgrade notes for `plone.app.z3cform` and `mockup` (#1750) Thank you @petschki! This is awesome. * Add upgrading notes for `plone.app.z3cform` and `mockup` * Tidy up upgrade items for `z3c.form` and `plone.app.z3cform` and `mockup` new pattern `pat-contentbrowser` --------- Co-authored-by: Steve Piercy --- .../upgrade-to-61.md | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md index 47655a1aa..d670b719a 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md @@ -64,16 +64,35 @@ To upgrade your plugin implementation to TinyMCE 7, see the [upgrade guides](htt ## `z3c.form` and `plone.app.z3cform` -````{todo} -This is a placeholder. +[`plone.app.z3cform`](https://github.com/plone/plone.app.z3cform) is the form widget integration package for [`z3c.form`](https://github.com/zopefoundation/z3c.form) in Plone. +This adds [Bootstrap 5](https://getbootstrap.com/) styling and mockup pattern options to all widgets. -- Update deprecated imports -- New widget templates +In Plone 6.1 all Classic UI widget classes were moved to the module `plone.app.z3cform.widgets`. +The previous paths are marked as deprecated and will be removed in Plone 7. -```{seealso} -https://github.com/plone/plone.app.z3cform/pull/181 -``` -```` +The `BaseWidget` for patterns is refactored to the new `z3c.form` extendable attributes introduced in version 5.1 and doesn't use LXML anymore. +See https://github.com/zopefoundation/z3c.form/pull/116. +If you have customizations in your base pattern widget class, see the new implementation at https://github.com/plone/plone.app.z3cform/blob/e9d1ebf478e663d2da259cb9435927f7ad1ddb92/plone/app/z3cform/widgets/base.py. + +`RelatedItemsWidget` is marked as deprecated. +The implementation for selecting related items, internal links and images in TinyMCE, or internal paths for collection criteria is now done with the new `ContentBrowserWidget`. +This introduces a new pattern `pat-contentbrowser` from mockup. +See the next section for details. + + +## `mockup` new pattern `pat-contentbrowser` + +A new content browsing pattern [`pat-contentbrowser`](https://plone.github.io/mockup/pat/contenbrowser/) for Classic UI is now available. + +This is a [Miller column browser](https://en.wikipedia.org/wiki/Miller_columns) implementation which replaces [`pat-relateditems`](https://plone.github.io/mockup/pat/relateditems/) seamlessly. +All basic options from `pat-relateditems` are implemented and behave the same as before. + +Additionally `pat-contentbrowser` comes with some new features. + +- Keyboard navigation. +- Multi-selection of items with {kbd}`Shift/Ctrl/CMD + click` combination. + This comes in handy for selecting multiple related items in one step. +- Uploading items to the current path. ## `plone.app.multilingual` is a core add-on From 472d9bd6c1f1d6e193da318f819fe7ca10d1e8e6 Mon Sep 17 00:00:00 2001 From: Peter Mathis Date: Tue, 5 Nov 2024 12:35:58 +0100 Subject: [PATCH 508/810] Explain how to create a custom pattern (#1748) * Explain how to create a custom pattern * Tidy up mockup.md. - Add more glossary terms and references. * Provide clarification of HTML tag * update info for pattern demo browser view * Apply suggestions from code review --------- Co-authored-by: Steve Piercy --- docs/classic-ui/mockup.md | 84 ++++++++++++++++++++++++++++++++++++++- docs/glossary.md | 11 +++++ 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/docs/classic-ui/mockup.md b/docs/classic-ui/mockup.md index a68167cd3..1ec463f1a 100644 --- a/docs/classic-ui/mockup.md +++ b/docs/classic-ui/mockup.md @@ -30,7 +30,7 @@ pip install plonecli --user Create an add-on package with `plonecli`. ```shell -plonecli add project.addon +plonecli create addon project.addon ``` This will create a package `project.addon`, which you can install in your Plone site. @@ -52,6 +52,88 @@ You can check the full list of available features using the `-l` parameter: plonecli -l ``` +## Create a custom pattern + +To create a custom {term}`pattern` in your add-on, use the `mockup_pattern` {term}`bobtemplate`. + +```shell +cd project.addon +plonecli add mockup_pattern +``` + +Next, enter your pattern name without the `pat-` prefix +In the following example, its name is `testpattern`. + +```shell +--> Pattern name (without “pat-” prefix) [my-pattern]: testpattern +``` + +This creates the necessary JavaScript resources and webpack configuration for you, as shown in the following file system tree diagram. + +```text +... +├── resources +| ├── pat-testpattern +| | ├── documentation.md +| | ├── testpattern.js +| | ├── testpattern.scss +| | ├── testpattern.test.js +│ ├── bundle.js +│ ├── index.html +│ ├── index.js +├── package.json +├── webpack.config.js +... +``` + +All your pattern JavaScript code goes into {file}`resources/pat-testpattern/testpattern.js`. +SCSS files can be imported, too, since webpack provides the `sass-loader` module. + +Next, install the npm packages using {term}`yarn`. + +```shell +yarn install +``` + +When you finish writing your JavaScript code, you have to build the bundle with the following command. + +```shell +yarn build +``` + +This creates the webpack chunks, the JavaScript bundle files, and a demo browser view in your add-on package. + +```text +... +├── src +| ├── project +| | ├── addon +| | | ├── browser +| | | | ├── static +| | | | | ├── bundles +| | | | | | ├── chunks +| | | | | | ├── addon-remote.min.js +| | | | | | ├── addon-remote.min.js.map +| | | | | | ├── addon.min.js +| | | | | | ├── addon.min.js.map +| | | | ├── pattern-demo.pt +``` + +There is also an XML file in {file}`src/project/addon/profiles/default/registry/bundles.xml` which registers the {file}`addon-remote.min.js` in the resources registry. + +```{important} +You must re-import your profile with an upgrade step if you installed your add-on in Plone before adding the pattern. +Uninstall, then re-install, the add-on in the control panel. +Alternatively you can write a GenericSetup upgrade step. +``` + +You can access the demo browser view in your browser with `http://localhost:8080/Plone/@@addon-pattern-demo`. +Alternatively you can implement it in your own templates by adding the CSS class `pat-testpattern` to an HTML tag, such as an `img` tag. + +```html + +``` + ## References diff --git a/docs/glossary.md b/docs/glossary.md index c9b714d04..4c8cccdfd 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -441,6 +441,17 @@ Mockup Mockup provides the JavaScript stack for Classic UI. [View Mockup's patterns](https://plone.github.io/mockup/), based on Patternslib. +bobtemplate +bobtemplates +bobtemplates.plone + `bobtemplates.plone` provides {term}`mr.bob` templates to generate packages for Plone projects. + The {term}`plonecli` command line client provides a developer-friendly interface to `bobtemplates.plone`. + +mr.bob + [`mr.bob`](https://mrbob.readthedocs.io/en/latest/) is a tool that takes a directory skeleton, copies over its directory structure to a target folder, and can use the Jinja2 (or some other) templating engine to dynamically generate the files. + Additionally, it can ask you questions needed to render the structure, or provide a configuration file to answer them. + +Pattern Patterns Patternslib [Patterns](https://patternslib.com/), or Patternslib, is a toolkit that enables designers to build rich interactive prototypes without the need for writing any JavaScript. From 55c44839fc2f1ee752f700bed3528868ebfd981c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 5 Nov 2024 15:18:25 -0800 Subject: [PATCH 509/810] Update tip submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- submodules/volto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index e63416968..9f0feffad 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit e63416968eb390f42df50c1025395d1b3baf7f60 +Subproject commit 9f0feffad288f18e5fa3d3f63094614971d1d164 diff --git a/submodules/volto b/submodules/volto index ac52b6bc7..5d08348bf 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit ac52b6bc748d75e81ace38b8007bc2ed1a32d92a +Subproject commit 5d08348bf443a67241a995e6c917eadf6d81b1fc From 16f3bb42fc6ced30957d1a35d499913fa99500c4 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Wed, 6 Nov 2024 00:36:20 +0100 Subject: [PATCH 510/810] Document distributions in the 6.1 upgrade guide. (#1733) * Document distributions in the 6.1 upgrade guide. See https://github.com/plone/Products.CMFPlone/issues/3854 * Review of Distributions documentation * Align term definition with upgrade guide docs, avoiding circular reference. * Fix admonition syntax * Add link to repo * Enhance screenshot with card syntax * plone.exportimport is not for upgrading Plone. If you need an export/import for upgrading Plone you would still use collective.exportimport. Upgrading is not a use case that plone.exportimport covers. * Here we do not start a new project, I just mean: start Plone. * These are not 'frontend distributions'. * Creating a 6.1 CMFPlone site differs from 6.0, that is the main point here. * Don't mention installing add-ons here, activating is enough. Sure, the Python package of an add-on must be installed before you can activate it, but the same is true for a distribution. The plone.classicui distribution has basically the same Python package dependencies as CMFPlone, although it activates a few extra ones automatically if they are available (say plone.app.caching). * reorganize distribution docs * Apply suggestions from code review * Update conceptual guide for distributions, where the significant changes are: - Use the actual package names of the built-in distributions - Move the comparison to other CMSs to the end of the page, putting Plone-only content first. * Create an entry in `index.md` to include a new `developer-guide/index.md` and the new `developer-guide/create-a-distribution.md` * Update glossary reference to other distribution material * Add cross-reference * Add JSON Schema to Glossary * Tidy up create-a-distribution.md. - Rewrite passive voice to active. - Enhance code blocks with `emphasize-lines`. - Use definition lists as appropriate for terms and inline literals. - Add links and terms where helpful. * Revert distribution names and enhance `ALLOWED_DISTRIBUTIONS` usage. * Tidy up add-site.md, mostly docs style guide stuff, and a rewording of the final admonition. Add plural `distributions` to Glossary. * Tidy up distributions section in upgrade-to-61.md * Update docs/backend/upgrading/version-specific-migration/upgrade-to-61.md Co-authored-by: David Glick * Move add-site into Admin Guide. Move Admin Guide before Developer Guide in main navigation * Remove stray characters from bad merge * Resolve TODOs by moving file and adding link to new choose-user-interface. * Update glossary with Zope instance and cross-references to Zope itself. * Fix cross-references * Fix link * Ignore link to static images * Ignore searches on GitHub as it rate limits and times out. * Update docs/developer-guide/index.md Co-authored-by: David Glick --------- Co-authored-by: Steve Piercy Co-authored-by: Maik Derstappen Co-authored-by: David Glick --- docs/admin-guide/add-site.md | 73 ++++ docs/admin-guide/index.md | 1 + .../images/distribution-chooser.png | Bin 0 -> 108786 bytes .../upgrade-to-61.md | 41 +++ docs/conceptual-guides/distributions.md | 89 +++++ docs/conceptual-guides/index.md | 1 + .../make-build-backend-walk-through.md | 2 +- docs/conf.py | 5 +- docs/developer-guide/create-a-distribution.md | 323 ++++++++++++++++++ docs/developer-guide/index.md | 25 ++ docs/glossary.md | 32 +- docs/index.md | 1 + 12 files changed, 584 insertions(+), 9 deletions(-) create mode 100644 docs/admin-guide/add-site.md create mode 100644 docs/backend/upgrading/version-specific-migration/images/distribution-chooser.png create mode 100644 docs/conceptual-guides/distributions.md create mode 100644 docs/developer-guide/create-a-distribution.md create mode 100644 docs/developer-guide/index.md diff --git a/docs/admin-guide/add-site.md b/docs/admin-guide/add-site.md new file mode 100644 index 000000000..0fd93872d --- /dev/null +++ b/docs/admin-guide/add-site.md @@ -0,0 +1,73 @@ +--- +myst: + html_meta: + "description": "How to add a Plone site to an existing Zope instance" + "property=og:description": "How to add a Plone site to an existing Zope instance" + "property=og:title": "Add a Plone site" + "keywords": "Plone 6, create, add, factory, distributions" +--- + +(add-a-plone-site-label)= + +# Add a Plone site + +This section explains how to add a Plone site to an existing Zope instance. +It assumes that you have already {doc}`installed ` and started Plone. + +Some installation methods create a Plone site for you already. +Follow these instructions if you used an installation method that did not do this, or if you need a second Plone site in the same instance for some reason. + +```{versionadded} Plone 6.1 +The user interface for creating a new Plone site was changed in Plone 6.1. +You can access it the same way in Plone 6.0, but the appearance and options are different. +``` + +Visit the Plone backend in a web browser. +Usually it is running at http://localhost:8080/. + +The launch screen prompts you to choose one of the available {term}`distributions` to create a new site. +You can read {doc}`/conceptual-guides/choose-user-interface` to help inform your choice between Volto and Classic UI. + +````{card} +```{image} /backend/upgrading/version-specific-migration/images/distribution-chooser.png +:alt: Launch screen for choosing a distribution +:target: /_images/distribution-chooser.png +``` ++++ +_Launch screen for choosing a distribution_ +```` + +Hover over your choice and click the {guilabel}`Create` button. + +Now complete the form with initial configuration for your site. +You can configure the following settings. + +Path Identifier +: The ID of the site. + This ends up as part of the URL unless hidden by an upstream web server. + +Title +: The name of the site in the HTML `title` element. + This will be shown as part of the title of the browser tab on each page. + +Site Description +: A brief description that will be served in an HTML `meta` tag. + +Site Logo +: Upload an image as the main site logo. + +Language +: The main language of the site. + +Timezone +: The default timezone setting of the portal. + +Finally, click the {guilabel}`Submit` button. + +Have fun with your new Plone site! + +```{important} +The launch screen for adding a site is hosted by the Plone backend server. +Regardless of the frontend you select, you will be redirected to the backend's user interface after you create the site. +If you select the Volto frontend, you can switch to it by changing the port number in the URL, usually `3000`, and visiting it at http://localhost:3000, for example. +``` diff --git a/docs/admin-guide/index.md b/docs/admin-guide/index.md index 9ac48e4ed..cf15440e2 100644 --- a/docs/admin-guide/index.md +++ b/docs/admin-guide/index.md @@ -29,6 +29,7 @@ install-pip :maxdepth: 1 run-plone +add-site configure-zope add-ons override-core diff --git a/docs/backend/upgrading/version-specific-migration/images/distribution-chooser.png b/docs/backend/upgrading/version-specific-migration/images/distribution-chooser.png new file mode 100644 index 0000000000000000000000000000000000000000..afe6172273fda55b6a8824c1c592a98e2895664c GIT binary patch literal 108786 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

Q*F9lDMU17p*^wx{WijAecGUM(gjgh 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 literal 0 HcmV?d00001 diff --git a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md index d670b719a..eae0f196b 100644 --- a/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md +++ b/docs/backend/upgrading/version-specific-migration/upgrade-to-61.md @@ -136,3 +136,44 @@ If you have an existing Plone 5.2 or 6.0 site and you migrate to 6.1, then migra - If the `plone.app.discussion` Python package is _not_ in your setup, but the site has existing comments (discussions), then the migration code stops with an error. Apparently you _were_ using comments in your site. Add the `plone.app.discussion` package to your dependencies, and run the migration again. + + +## Distributions + +Plone 6.1 introduces the concept of a Plone {term}`distribution`. +A Plone distribution is a Python package that defines specific features, themes, add-ons, and configurations that get activated when creating a Plone site. +Now it is available in core Plone as the recommended way for {doc}`creating a new Plone site `. + +```{seealso} +For more information about distribution concepts, see {doc}`/conceptual-guides/distributions`. +``` + +Distributions are optional. +If your project only uses the `Products.CMFPlone` Python package, you can still create a Plone site in the old way. +Consider, however, that doing so you will have the following differences when compared to using distributions. + +- The configuration form is simpler and shorter. +- The created site has no content, and therefore no {guilabel}`News` or {guilabel}`Events` folders. +- You must activate add-ons through the {guilabel}`Add-ons` control panel. + +There are a few things you should consider when upgrading a project to, or making an add-on compatible with, Plone 6.1. + +- In general, you don't need to change anything. + Your existing site will keep working. + But adding a new site may change in the ways described earlier. +- Do you want to use the `Products.CMFPlone` package (no distributions), either `plone.volto` or `plone.classicui` (one distribution), or `Plone` (two distributions)? +- If your site uses Volto for the frontend, you will already have `plone.volto` as a dependency. + This can stay the same. +- If your site depends on the `Products.CMFPlone` package without the `Plone` or `plone.volto` packages, then the frontend is Classic UI. + This can stay the same, but you may want to depend on `plone.classicui`. + With that package you can still create a new site and have the same content as before. +- If your site uses the `Plone` package, you will have the two new distributions available. + This is fine. + If you know you only need `plone.volto` or only need `plone.classicui`, you can switch to only one or the other. + You can also limit the options for selecting a distribution by setting the environment variable `ALLOWED_DISTRIBUTIONS` with fewer options. + Set `ALLOWED_DISTRIBUTIONS=default` for the distribution targeting the Volto frontend (`plone.volto`). + Set `ALLOWED_DISTRIBUTIONS=classic` for the distribution with the Classic UI frontend (`plone.classicui`). +- If you switch from `Plone` to `plone.volto` or `plone.classicui`, you might want to install extra core add-ons, for example `plone.app.upgrade` or `plone.app.caching`. +- If your add-on is only for Volto, you might want to add `plone.volto` as a dependency. +- If your add-on is only for Classic UI, you might want to add `plone.classicui` as a dependency. + Note though that `plone.classicui` is not available for Plone 6.0. diff --git a/docs/conceptual-guides/distributions.md b/docs/conceptual-guides/distributions.md new file mode 100644 index 000000000..ed1d6d76f --- /dev/null +++ b/docs/conceptual-guides/distributions.md @@ -0,0 +1,89 @@ +--- +myst: + html_meta: + "description": "A Plone distribution is a pre-packaged version of Plone that includes specific features, themes, modules, and configurations." + "property=og:description": "A Plone distribution is a pre-packaged version of Plone that includes specific features, themes, modules, and configurations." + "property=og:title": "Plone distributions" + "keywords": "Plone 6, distribution, plone.distribution" +--- + +(plone-distributions-label)= + +# Plone distributions + +```{versionadded} Plone 6.1 +``` + +A Plone {term}`distribution` is a pre-packaged version of Plone that includes specific features, themes, modules, and configurations. +It is a convenient way to get a specific type of website up and running quickly, as the distribution includes everything needed to run that type of site. + +```{seealso} +To create your own distribution, see {doc}`/developer-guide/create-a-distribution`. +``` + + +## Built-in distributions + +Plone comes with two built-in distributions, which correspond to the two Plone user interfaces. + +[`plone.volto`](https://github.com/plone/plone.volto) +: Create a Plone site with the Volto frontend. + +[`plone.classicui`](https://github.com/plone/plone.classicui) +: Create a Plone site with the Classic UI frontend. + + +## Third-party distributions + +You can create your own distributions to suit your needs. + +```{seealso} +For a how-to guide, see {doc}`/developer-guide/create-a-distribution`. +``` + +For example, a Plone consulting agency can create a distribution demonstrating its favorite setup for Plone. +This would contain the add-ons that they usually add in each project, including example content. +With this, the agency can create a fully configured Plone site filled with content for a potential client. + +Alternatively, an agency or implementer can create a distribution for specific project. +This could create a site with all add-ons activated and configured for this project, including example content, and optionally users and groups. +During the development phase of a new project, all developers would use this to create a fresh site locally so that everyone has the same configuration and content. + +Custom Plone distributions can be distributions for use by others. +Examples of third-party Plone distributions include: + +- [SENAITE](https://www.senaite.com) +- [Quaive](https://quaive.com/) +- [Portal Modelo](https://www.interlegis.leg.br/produtos-servicos/portal-modelo/) +- [Portal Padrão](https://identidade-digital-de-governo-plone.readthedocs.io/en/latest/) + + +## Related packages + +The implementation of distributions in the Plone codebase is found in the following Python packages. + +- [`plone.distribution`](https://github.com/plone/plone.distribution) provides the framework for defining distributions. +- [`plone.exportimport`](https://github.com/plone/plone.exportimport) imports and exports content, users, and other objects between Plone sites. + `plone.distribution` uses it. +- [`plone.volto`](https://github.com/plone/plone.volto) is the distribution to create a Plone site with the Volto frontend. +- [`plone.classicui`](https://github.com/plone/plone.classicui) is the distribution to create a Plone site with the Classic UI frontend. + +```{note} +For Plone 7, the [Plone roadmap](https://plone.org/why-plone/roadmap) guides development toward a clearer separation between the Classic UI frontend and the core `Products.CMFPlone` backend. +This means that in Plone 7, `Products.CMFPlone` will have less code and pull in fewer dependencies, whereas `plone.classicui` may have more code and pull in more dependencies. +This is the direction in which the backend is heading, and the introduction of the `plone.classicui` distribution package is an important step along this path. +``` + +## Comparison with other CMSs + +Drupal +: Drupal has distributions for blogs, e-commerce sites, and intranet portals. + +WordPress +: WordPress has a similar concept in the form of "WordPress Multisite," which allows users to run multiple websites from a single installation of WordPress. + +Joomla +: Joomla has a similar concept in the form of "Joomla Templates," which are pre-designed templates for Joomla websites. + +TYPO3 +: TYPO3 has a similar concept in the form of "TYPO3 Distributions," which are pre-configured installations of TYPO3 for specific types of websites. diff --git a/docs/conceptual-guides/index.md b/docs/conceptual-guides/index.md index de6081f2e..bab21a65f 100644 --- a/docs/conceptual-guides/index.md +++ b/docs/conceptual-guides/index.md @@ -16,6 +16,7 @@ This part of the documentation provides explanation of concepts to deepen and br :maxdepth: 2 choose-user-interface +distributions package-management make-build-backend-walk-through ``` diff --git a/docs/conceptual-guides/make-build-backend-walk-through.md b/docs/conceptual-guides/make-build-backend-walk-through.md index 859852ac8..9f4e9c2f9 100644 --- a/docs/conceptual-guides/make-build-backend-walk-through.md +++ b/docs/conceptual-guides/make-build-backend-walk-through.md @@ -52,7 +52,7 @@ The command `make build-backend`: - Returning to the target `build-dev`: - - This generates the `mxdev` files as described above in {ref}`mxdev-usage-overview-label`. + - This generates the `mxdev` files as described above in {ref}`manage-backend-python-packages-label`. - Installs Plone core packages and add-ons from the files generated by `mxdev`. You can configure your Zope instance as described in the section {doc}`/admin-guide/configure-zope`. diff --git a/docs/conf.py b/docs/conf.py index d79793765..c253b8d93 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -82,8 +82,9 @@ r"http://127.0.0.1", r"http://localhost", r"http://yoursite", - # Ignore file downloads + # Ignore static file downloads r"^/_static/", + r"^/_images/", # Ignore pages that require authentication r"https://github.com/orgs/plone/teams/", # requires auth r"https://github.com/plone/documentation/issues/new/choose", # requires auth @@ -91,6 +92,8 @@ r"https://opensource.org/", # requires auth # Ignore github.com pages with anchors r"https://github.com/.*#.*", + # Ignore github.com searches + r"https://github.com/search", # Ignore other specific anchors r"https://coveralls.io/repos/github/plone/plone.restapi/badge.svg\?branch=main", # plone.restapi r"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors#Identifying_the_issue", diff --git a/docs/developer-guide/create-a-distribution.md b/docs/developer-guide/create-a-distribution.md new file mode 100644 index 000000000..d58e4f3bd --- /dev/null +++ b/docs/developer-guide/create-a-distribution.md @@ -0,0 +1,323 @@ +--- +myst: + html_meta: + "description": "How to create a custom Plone distribution" + "property=og:description": "How to create a custom Plone distribution" + "property=og:title": "Create a Plone distribution" + "keywords": "Plone 6, distribution, plone.distribution" +--- + +(create-a-plone-distribution-label)= + +# Create a Plone distribution + +This section explains how a developer can create a custom Plone {term}`distribution`. +A Plone distribution is a pre-packaged version of Plone that includes specific features, themes, modules, and configurations. + +```{seealso} +For a conceptual guide, see {doc}`/conceptual-guides/distributions`. +``` + + +## Create a backend add-on + +These instructions assume that you already have created a Plone backend add-on package, +and now you want to add a distribution to it. + +A Plone distribution exists inside a Python package that can be installed by `pip`. + + +## Update `setup.py` + +Your package should follow conventions that make it discoverable by other developers. + +In your {file}`setup.py` file, always add the correct [Python Trove classifiers](https://pypi.org/classifiers/). + +```python +"Framework :: Plone", +"Framework :: Plone :: 6.1", +"Framework :: Plone :: Distribution", +``` + +Add `plone.distribution` to your `install_requires` stanza in your {file}`setup.py` file. + +```{code-block} python +:emphasize-lines: 4 + +install_requires=[ + "Products.CMFPlone", + "setuptools", + "plone.distribution", +], +``` + + +## Update `configure.zcml` + +In your main {file}`configure.zcml` file, add the `plone` XML namespace with the following declaration. + +```{code-block} xml +:emphasize-lines: 3 + + +``` + +Register `plone.distribution` as a package to include with the following `` directive. + +```xml + +``` + +Then declare the distributions you want to include in your package. + +```xml + +``` + +The above example registers a distribution that will configure a personal blog with some default content. + + +## Add distribution handlers + +When registering a distribution, you can provide a `pre_handler`, a `handler`, and a `post_handler`, each of which must be a function with their respective signature, as shown in the following example. + +```python +def pre_handler(answers: dict) -> dict: + return answers + +def handler(distribution: Distribution, site, answers: dict): + return site + +def post_handler(distribution: Distribution, site, answers: dict): + return site +``` + +Each of those handlers will be called as follows. + +`pre_handler` +: Processes the answers to prepare the distribution before creating the site. + +`handler` +: Runs after creating the bare Plone site instead of the default handler. + It installs the required GenericSetup profiles and creates the content. + +`post_handler` +: Runs after the site is set up. + +To add extra configuration to your Plone site, and assuming you added extra inputs to the Plone site creation form, then you can add your own handler, registering it as shown in the following example. + +```{code-block} xml +:emphasize-lines: 6 + + +``` + + +## Add a distribution folder + +To organize your distribution configuration, you can follow the convention to use the {file}`distributions/` folder in the root of your package. +In that folder, you need to provide the items described in the following sections. + + +### `image.png` + +A 1080 pixels wide by 768 pixels tall image in PNG format representing your distribution. +It could be the default page of a new site, your logo, or any other way of representing your distribution. + + +### `profiles.json` + +A file {file}`profiles.json` containing the GenericSetup profiles that your distribution uses during installation. + +This file needs to contain two keys. + +`base` +: List of profiles to install in every new site using this distribution. + +`content` +: List of profiles to install when the user decides to create a site with example content. + +As an example, the configuration for a new Plone site with Volto as its frontend would be the following. + +```json +{ + "base": [ + "plone.app.contenttypes:default", + "plone.app.caching:default", + "plonetheme.barceloneta:default", + "plone.volto:default" + ], + "content": [ + "plone.volto:default-homepage" + ] +} +``` + + +### `schema.json` + +If you require additional input from the user during site creation, you can customize the form using the {file}`schema.json` file. + +The file should contain two keys. + +`schema` +: A {term}`JSON Schema` definition. + +`uischema` +: A [`react-jsonschema-form`](https://rjsf-team.github.io/react-jsonschema-form/docs/) configuration to modify the display of the form. + +The `schema` should have at least the following keys. + +- `site_id` +- `title` +- `description` +- `default_language` +- `portal_timezone` +- `setup_content` + +The following code example is the content of the {file}`schema.json` file for creating the site. + +```json +{ + "schema": { + "title": "Create a Plone site", + "description": "Adds a new Plone content management system site to the underlying application server.", + "type": "object", + "required": [ + "site_id", + "title" + ], + "properties": { + "site_id": { + "type": "string", + "title": "Path Identifier", + "default": "Plone", + "description": "The ID of the site. No special characters or spaces are allowed. This ends up as part of the URL unless hidden by an upstream web server." + }, + "title": { + "type": "string", + "title": "Title", + "default": "Site", + "description": "A short title for the site. This will be shown as part of the title of the browser window on each page." + }, + "description": { + "type": "string", + "title": "Site Description", + "default": "A Plone Site" + }, + "default_language": {"$ref": "#/definitions/languages"}, + "portal_timezone": {"$ref": "#/definitions/timezones"}, + "setup_content": { + "type": "boolean", + "title": "Create Content", + "description": "Should example content be added during site creation?", + "default": false + } + } + }, + "uischema": { + } +} +``` + +````{note} +You may have noticed the entries for both `default_language` and `portal_timezone`. + +```json + "default_language": {"$ref": "#/definitions/languages"}, + "portal_timezone": {"$ref": "#/definitions/timezones"}, +``` + +`plone.distribution` adds both definitions at runtime, providing a list of languages and timezones available on the installation. +```` + +## Add a dependency on an add-on + +If you want to add a Plone backend add-on to your Plone distribution, then you must perform the following steps. + +Add your add-on, such as `collective.person`, to your {file}`setup.py` file's `install_requires` stanza. + +```{code-block} python +:emphasize-lines: 6 + +install_requires=[ + "setuptools", + "Plone", + "plone.distribution>=1.0.0b2", + "plone.api", + "collective.person", +], +``` + +Then add it to your {file}`dependencies.zcml` file. + +```{code-block} xml +:emphasize-lines: 5 + + + + + + + + +``` + +Finally, add it to your {file}`profiles.json` file. + +```{code-block} json +:emphasize-lines: 6 + +"base": [ + "plone.app.contenttypes:default", + "plone.app.caching:default", + "plone.restapi:default", + "plone.volto:default", + "collective.person:default", + "plonetheme.barceloneta:default" +], +``` + + +## Add example content + +The distribution loads its content from JSON data in the `content` folder. + +To export content from a site into this folder, use the `bin/export-distribution` script. + +```shell +bin/export-distribution path/to/zope.conf Plone +``` + +In the example above, `Plone` is the ID of the Plone site to export. + + +## Limit available distributions + +By default, Plone 6.1 ships with two ready-to-use distributions. + +`default` +: Create a Plone site with the Volto frontend. + +`classic` +: Create a Plone site with the Classic UI frontend. + +If you want to limit the choice of distributions when creating a new site, you can set the environment variable `ALLOWED_DISTRIBUTIONS` to a comma-separated sting of only those distributions' names. + +```shell +ALLOWED_DISTRIBUTIONS=default +``` diff --git a/docs/developer-guide/index.md b/docs/developer-guide/index.md new file mode 100644 index 000000000..797edd0d7 --- /dev/null +++ b/docs/developer-guide/index.md @@ -0,0 +1,25 @@ +--- +myst: + html_meta: + "description": "Plone developer guide" + "property=og:description": "Plone developer guide" + "property=og:title": "Developer guide" + "keywords": "Plone 6, developer guide, development" +--- + +# Developer guide + +This part of the documentation provides information for how to develop in Plone. + +```{note} +This part of the documentation is under construction. +You can find documentation for development in various locations through the [search feature](https://6.docs.plone.org/search.html?q=development). +You can help consolidate all of development documentation here, even if it is to let us know what is missing, by [creating an issue](https://github.com/plone/documentation/issues/new?assignees=&labels=&projects=&template=new-issue-form.yml). +``` + + +```{toctree} +:maxdepth: 2 + +create-a-distribution +``` diff --git a/docs/glossary.md b/docs/glossary.md index 4c8cccdfd..ed4b20897 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -54,10 +54,10 @@ plone/generator-volto cookiecutter-plone-starter [cookiecutter-plone-starter](https://github.com/collective/cookiecutter-plone-starter/) creates a Plone project that you can install using {term}`Make`. It generates files for installing and configuring both the frontend and backend. - For the backend, it uses {term}`cookiecutter-zope-instance` to generate configuration files for a Zope WSGI instance. + For the backend, it uses {term}`cookiecutter-zope-instance` to generate configuration files for a {term}`Zope instance`. cookiecutter-zope-instance - [cookiecutter-zope-instance](https://github.com/plone/cookiecutter-zope-instance) is a cookiecutter template to create a full and complex configuration of a Zope WSGI instance. + [cookiecutter-zope-instance](https://github.com/plone/cookiecutter-zope-instance) is a cookiecutter template to create a full and complex configuration of a {term}`Zope instance`. CSRF Cross-Site Request Forgery @@ -144,13 +144,13 @@ Diazo Dexterity [Dexterity](https://github.com/plone/plone.dexterity) is the base framework for building content types, both through-the-web and as filesystem code. - It is aimed at Plone, although this package should work with plain Zope + CMF systems. + It is aimed at Plone, although this package should work with plain {term}`Zope` + CMF systems. Dublin Core The Dublin Core Schema is a small set of vocabulary terms that can be used to describe web resources (video, images, web pages, etc.), as well as physical resources such as books or CDs, and objects like artworks. ZMI - The Zope Management Interface. + The {term}`Zope` Management Interface. The ZMI is a direct interface into the backend software stack of Plone. While it can still serve as a valuable tool for Plone specialists to fix problems or accomplish certain tasks, it is not recommended as a regular tool for Plone maintenance. @@ -210,7 +210,7 @@ Configuration registry It is accessible from the Volto project by importing the module `@plone/volto/config` with `import registry from '@plone/volto/config'`. It contains the configuration of the Volto app. - In Plone core, [`plone.app.registry`](https://pypi.org/project/plone.app.registry/) provides Plone UI and `GenericSetup` integration for [`plone.registry`](https://pypi.org/project/plone.registry/), which in turn implements a configuration registry for Zope applications. + In Plone core, [`plone.app.registry`](https://pypi.org/project/plone.app.registry/) provides Plone UI and `GenericSetup` integration for [`plone.registry`](https://pypi.org/project/plone.registry/), which in turn implements a configuration registry for {term}`Zope` applications. component shadowing shadowing @@ -566,6 +566,10 @@ ZODB Zope [Zope](https://zope.readthedocs.io/en/latest/) is a Python-based application server for building secure and highly scalable web applications. +Zope instance + A Zope instance is a particular set of configuration for running {term}`Zope`. + A new Zope instance can be created using {term}`cookiecutter-zope-instance`. + ZPT Zope Page Template is a template language for Python. @@ -576,7 +580,7 @@ ZCA Zope Component Architecture Zope Component Architecture (ZCA) is a Python framework for supporting component based design and programming. It is very well suited to developing large Python software systems. - The ZCA is not specific to the Zope web application server. + The ZCA is not specific to the {term}`Zope` web application server. It can be used for developing any Python application. Maybe it should be called Python Component Architecture. ```{seealso} @@ -803,7 +807,7 @@ Load balancer CI continuous integration Continuous integration (CI) is the practice of integrating all your code changes into the main branch of a shared source code repository early and often, automatically testing each change when you commit or merge them, and automatically kicking off a build. - + Read about Plone's {doc}`/contributing/core/continuous-integration`. CD @@ -821,7 +825,21 @@ reference implementation A reference implementation is a program that implements all requirements from a corresponding specification. The reference implementation often accompanies a technical standard, and demonstrates what should be considered the "correct" behavior of any other implementation of it. +distribution +distributions + A Plone distribution is a pre-packaged version of Plone that includes specific features, themes, modules, and configurations. + It is a convenient way to get a specific type of website up and running quickly, as the distribution includes everything needed to run that type of site. + + ```{seealso} + - {doc}`/conceptual-guides/distributions` + - {doc}`/developer-guide/create-a-distribution` + ``` + +JSON Schema + [JSON Schema](https://json-schema.org/) is the vocabulary that enables JSON data consistency, validity, and interoperability at scale. + portlets Portlets are widgets that can be inserted in predefined locations in pages in {term}`Classic UI`. Portlets are most commonly used to add sidebars to the left or right of the main page content. + ``` diff --git a/docs/index.md b/docs/index.md index 9f4594162..38587e3b6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -33,6 +33,7 @@ Read the [documentation for the previous version, Plone 5](https://5.docs.plone. overview/index install/index admin-guide/index +developer-guide/index deployment/index volto/index classic-ui/index From b919f15a61c401b16879874e42c60c010707ed24 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 5 Nov 2024 15:41:25 -0800 Subject: [PATCH 511/810] Add link to new "Develop Volto add-ons" section (#1755) * Add link to new "Develop Volto add-ons" section * Fix heading --- docs/admin-guide/add-ons.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/admin-guide/add-ons.md b/docs/admin-guide/add-ons.md index e8b631e61..338aad9da 100644 --- a/docs/admin-guide/add-ons.md +++ b/docs/admin-guide/add-ons.md @@ -15,8 +15,7 @@ This chapter explains how to install {term}`add-ons ` as Python packages ```{note} The Volto frontend has its own system of add-ons using Node.js packages. -% TODO: update the following link after https://github.com/plone/volto/pull/6397 is merged to point to `/development/add-ons/index`. -See {doc}`/volto/addons/index`. +See {doc}`/volto/development/add-ons/index`. ``` @@ -133,7 +132,7 @@ Follow the upgrade information, if present. Else click the {guilabel}`Install` button to complete installation of the add-on. -## with Buildout +## Buildout Use the following instructions if you installed Plone with Buildout. From e46ff14f4436724c94cef9cc83467fb250aa0e9d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 5 Nov 2024 16:38:20 -0800 Subject: [PATCH 512/810] Exclude all create new issues for Volto and Documentation (#1756) --- docs/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index c253b8d93..8d7dee55a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -87,8 +87,8 @@ r"^/_images/", # Ignore pages that require authentication r"https://github.com/orgs/plone/teams/", # requires auth - r"https://github.com/plone/documentation/issues/new/choose", # requires auth - r"https://github.com/plone/volto/issues/new/choose", # requires auth + r"https://github.com/plone/documentation/issues/new", # requires auth + r"https://github.com/plone/volto/issues/new", # requires auth r"https://opensource.org/", # requires auth # Ignore github.com pages with anchors r"https://github.com/.*#.*", From 8142b968a75133aca0bf0a958135b7604418cfb5 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 6 Nov 2024 00:42:34 -0800 Subject: [PATCH 513/810] Add Create a backend add-on section in the Developer guide. Ping @petschki - Enhance the Development Guide index - Update the term Buildout in the Glossary to point to dusty old, yet useful, docs in Plone 4. --- .../create-a-backend-add-on.md | 21 +++++ docs/developer-guide/create-a-distribution.md | 5 +- docs/developer-guide/index.md | 85 +++++++++++++++++-- docs/glossary.md | 4 + docs/i18n-l10n/translating-text-strings.md | 4 +- 5 files changed, 106 insertions(+), 13 deletions(-) create mode 100644 docs/developer-guide/create-a-backend-add-on.md diff --git a/docs/developer-guide/create-a-backend-add-on.md b/docs/developer-guide/create-a-backend-add-on.md new file mode 100644 index 000000000..f5249080f --- /dev/null +++ b/docs/developer-guide/create-a-backend-add-on.md @@ -0,0 +1,21 @@ +--- +myst: + html_meta: + "description": "How to create a custom Plone distribution" + "property=og:description": "How to create a custom Plone distribution" + "property=og:title": "Create a Plone distribution" + "keywords": "Plone 6, distribution, plone.distribution" +--- + +(create-a-backend-add-on-label)= + +# Create a backend add-on + +This section explains how a developer can create an {term}`add-on` for the Plone backend. +You will use a framework called {term}`GenericSetup`. + +```{note} +This section for Plone 6 is in the process of being written. +Until it is complete, Plone 5 documentation is the authoritative source. +{doc}`plone5:develop/addons/components/genericsetup` (Plone 5) +``` diff --git a/docs/developer-guide/create-a-distribution.md b/docs/developer-guide/create-a-distribution.md index d58e4f3bd..b1b7cafa6 100644 --- a/docs/developer-guide/create-a-distribution.md +++ b/docs/developer-guide/create-a-distribution.md @@ -19,10 +19,9 @@ For a conceptual guide, see {doc}`/conceptual-guides/distributions`. ``` -## Create a backend add-on +## Use a backend add-on -These instructions assume that you already have created a Plone backend add-on package, -and now you want to add a distribution to it. +These instructions assume that you have already {doc}`created a Plone backend add-on package `, and now you want to add a distribution to it. A Plone distribution exists inside a Python package that can be installed by `pip`. diff --git a/docs/developer-guide/index.md b/docs/developer-guide/index.md index 797edd0d7..08497c838 100644 --- a/docs/developer-guide/index.md +++ b/docs/developer-guide/index.md @@ -1,25 +1,94 @@ --- myst: html_meta: - "description": "Plone developer guide" - "property=og:description": "Plone developer guide" - "property=og:title": "Developer guide" - "keywords": "Plone 6, developer guide, development" + "description": "Plone development guide" + "property=og:description": "Plone development guide" + "property=og:title": "Development guide" + "keywords": "Plone 6, development guide, developer, development" --- -# Developer guide +# Development guide + +```{note} +This part of the documentation is under revision, consolidating documentation for development from its various locations into in one section. +Until then, you can use the [search feature](https://6.docs.plone.org/search.html?q=development). +You can also help with this effort, even if it is to report that something is missing, by [creating an issue](https://github.com/plone/documentation/issues/new?assignees=&labels=&projects=&template=new-issue-form.yml). +``` This part of the documentation provides information for how to develop in Plone. +This development guide points you, as a developer, to the appropriate resource. + + +## Tests + +Tests ensure that your project functions as expected, and that changes to the code base during development don't break anything. + + +### Volto + +- {doc}`Volto acceptance tests ` +- {doc}`Volto unit tests ` +- {ref}`testing-the-add-on-label` + + +### Classic UI ```{note} -This part of the documentation is under construction. -You can find documentation for development in various locations through the [search feature](https://6.docs.plone.org/search.html?q=development). -You can help consolidate all of development documentation here, even if it is to let us know what is missing, by [creating an issue](https://github.com/plone/documentation/issues/new?assignees=&labels=&projects=&template=new-issue-form.yml). +Classic UI testing for Plone 6 is in the process of being written. ``` +### Backend + +```{note} +Backend testing for Plone 6 is in the process of being written. +Until it is complete, Plone 5 documentation is the authoritative source for writing tests for the Plone backend. +``` + +- {doc}`Backend tests ` (Plone 5) + + +## Create an add-on + +- {doc}`create-a-backend-add-on` +- {doc}`/volto/development/add-ons/create-an-add-on-18` + + +## Create a Plone distribution + +{doc}`create-a-distribution` + + +## Create content types + +- {doc}`/backend/content-types/creating-content-types` +- {doc}`plone5:develop/plone/content/index` (Plone 5) + + +## Register views + +{doc}`plone5:develop/plone/views/index` (Plone 5) + + +## Register API services + +{doc}`backend/configuration-registry` + + +## {term}`ZCA` +% TODO: This is a mixture of conceptual and how-to guides. Move its parts where they belong and rewrite. +{doc}`plone5:develop/addons/components/index` (Plone 5) + + +## {term}`ZCML` +% TODO: This is a mixture of conceptual and how-to guides. Move its parts where they belong and rewrite. +{doc}`plone5:develop/addons/components/zcml` (Plone 5) + + ```{toctree} :maxdepth: 2 +:hidden: +create-a-backend-add-on create-a-distribution ``` diff --git a/docs/glossary.md b/docs/glossary.md index ed4b20897..58c64ed39 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -25,6 +25,10 @@ Buildout [Buildout](https://github.com/buildout/buildout/) is a Python-based tool for building and assembling applications from multiple parts, based on a configuration file. It was the most common way of installing Plone 3, 4, and 5, and can still be used with Plone 6. + Usage of Buildout in Plone appears in various places in this documentation. + For a history and extended usage of Buildout, you can refer to the Plone 4 Documentation's section on [Buildout](https://4.docs.plone.org/old-reference-manuals/buildout/). + The Plone community authored this reference manual, as Buildout's own documentation is suboptimal. + CMS Content Management System diff --git a/docs/i18n-l10n/translating-text-strings.md b/docs/i18n-l10n/translating-text-strings.md index 22d307e88..d69c4ec15 100644 --- a/docs/i18n-l10n/translating-text-strings.md +++ b/docs/i18n-l10n/translating-text-strings.md @@ -56,7 +56,7 @@ Information in the PO file headers is ignored. [`i18ndude`](https://pypi.org/project/i18ndude/) should be used to create a script which searches particular packages for translation strings. -If you have created your add-on using [bobtemplates.plone](https://pypi.org/project/bobtemplates.plone/), then you will already have a script `update.sh` inside your package and a script `update_locale` in your buildout to extract the messages from your code. +If you have created your add-on using [bobtemplates.plone](https://pypi.org/project/bobtemplates.plone/), then you will already have a script `update.sh` inside your package and a script `update_locale` in your {term}`buildout` to extract the messages from your code. After running that script, a new `domain.pot` file will be created in your `locales` directory where all the messages will be saved. @@ -273,7 +273,7 @@ This script hooks into the release process and builds the MO files for you. ### Installing i18ndude -The recommended method is to have {term}`i18ndude` installed via your [buildout](https://www.buildout.org/en/latest/). +The recommended method is to have {term}`i18ndude` installed via your buildout. Add the following to your `buildout.cfg`: From 8dd933b2680ba2350c679e56e3b58a698900b55d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 6 Nov 2024 00:44:36 -0800 Subject: [PATCH 514/810] Revert "Add Create a backend add-on section in the Developer guide." This reverts commit 8142b968a75133aca0bf0a958135b7604418cfb5. --- .../create-a-backend-add-on.md | 21 ----- docs/developer-guide/create-a-distribution.md | 5 +- docs/developer-guide/index.md | 85 ++----------------- docs/glossary.md | 4 - docs/i18n-l10n/translating-text-strings.md | 4 +- 5 files changed, 13 insertions(+), 106 deletions(-) delete mode 100644 docs/developer-guide/create-a-backend-add-on.md diff --git a/docs/developer-guide/create-a-backend-add-on.md b/docs/developer-guide/create-a-backend-add-on.md deleted file mode 100644 index f5249080f..000000000 --- a/docs/developer-guide/create-a-backend-add-on.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -myst: - html_meta: - "description": "How to create a custom Plone distribution" - "property=og:description": "How to create a custom Plone distribution" - "property=og:title": "Create a Plone distribution" - "keywords": "Plone 6, distribution, plone.distribution" ---- - -(create-a-backend-add-on-label)= - -# Create a backend add-on - -This section explains how a developer can create an {term}`add-on` for the Plone backend. -You will use a framework called {term}`GenericSetup`. - -```{note} -This section for Plone 6 is in the process of being written. -Until it is complete, Plone 5 documentation is the authoritative source. -{doc}`plone5:develop/addons/components/genericsetup` (Plone 5) -``` diff --git a/docs/developer-guide/create-a-distribution.md b/docs/developer-guide/create-a-distribution.md index b1b7cafa6..d58e4f3bd 100644 --- a/docs/developer-guide/create-a-distribution.md +++ b/docs/developer-guide/create-a-distribution.md @@ -19,9 +19,10 @@ For a conceptual guide, see {doc}`/conceptual-guides/distributions`. ``` -## Use a backend add-on +## Create a backend add-on -These instructions assume that you have already {doc}`created a Plone backend add-on package `, and now you want to add a distribution to it. +These instructions assume that you already have created a Plone backend add-on package, +and now you want to add a distribution to it. A Plone distribution exists inside a Python package that can be installed by `pip`. diff --git a/docs/developer-guide/index.md b/docs/developer-guide/index.md index 08497c838..797edd0d7 100644 --- a/docs/developer-guide/index.md +++ b/docs/developer-guide/index.md @@ -1,94 +1,25 @@ --- myst: html_meta: - "description": "Plone development guide" - "property=og:description": "Plone development guide" - "property=og:title": "Development guide" - "keywords": "Plone 6, development guide, developer, development" + "description": "Plone developer guide" + "property=og:description": "Plone developer guide" + "property=og:title": "Developer guide" + "keywords": "Plone 6, developer guide, development" --- -# Development guide - -```{note} -This part of the documentation is under revision, consolidating documentation for development from its various locations into in one section. -Until then, you can use the [search feature](https://6.docs.plone.org/search.html?q=development). -You can also help with this effort, even if it is to report that something is missing, by [creating an issue](https://github.com/plone/documentation/issues/new?assignees=&labels=&projects=&template=new-issue-form.yml). -``` +# Developer guide This part of the documentation provides information for how to develop in Plone. -This development guide points you, as a developer, to the appropriate resource. - - -## Tests - -Tests ensure that your project functions as expected, and that changes to the code base during development don't break anything. - - -### Volto - -- {doc}`Volto acceptance tests ` -- {doc}`Volto unit tests ` -- {ref}`testing-the-add-on-label` - - -### Classic UI ```{note} -Classic UI testing for Plone 6 is in the process of being written. +This part of the documentation is under construction. +You can find documentation for development in various locations through the [search feature](https://6.docs.plone.org/search.html?q=development). +You can help consolidate all of development documentation here, even if it is to let us know what is missing, by [creating an issue](https://github.com/plone/documentation/issues/new?assignees=&labels=&projects=&template=new-issue-form.yml). ``` -### Backend - -```{note} -Backend testing for Plone 6 is in the process of being written. -Until it is complete, Plone 5 documentation is the authoritative source for writing tests for the Plone backend. -``` - -- {doc}`Backend tests ` (Plone 5) - - -## Create an add-on - -- {doc}`create-a-backend-add-on` -- {doc}`/volto/development/add-ons/create-an-add-on-18` - - -## Create a Plone distribution - -{doc}`create-a-distribution` - - -## Create content types - -- {doc}`/backend/content-types/creating-content-types` -- {doc}`plone5:develop/plone/content/index` (Plone 5) - - -## Register views - -{doc}`plone5:develop/plone/views/index` (Plone 5) - - -## Register API services - -{doc}`backend/configuration-registry` - - -## {term}`ZCA` -% TODO: This is a mixture of conceptual and how-to guides. Move its parts where they belong and rewrite. -{doc}`plone5:develop/addons/components/index` (Plone 5) - - -## {term}`ZCML` -% TODO: This is a mixture of conceptual and how-to guides. Move its parts where they belong and rewrite. -{doc}`plone5:develop/addons/components/zcml` (Plone 5) - - ```{toctree} :maxdepth: 2 -:hidden: -create-a-backend-add-on create-a-distribution ``` diff --git a/docs/glossary.md b/docs/glossary.md index 58c64ed39..ed4b20897 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -25,10 +25,6 @@ Buildout [Buildout](https://github.com/buildout/buildout/) is a Python-based tool for building and assembling applications from multiple parts, based on a configuration file. It was the most common way of installing Plone 3, 4, and 5, and can still be used with Plone 6. - Usage of Buildout in Plone appears in various places in this documentation. - For a history and extended usage of Buildout, you can refer to the Plone 4 Documentation's section on [Buildout](https://4.docs.plone.org/old-reference-manuals/buildout/). - The Plone community authored this reference manual, as Buildout's own documentation is suboptimal. - CMS Content Management System diff --git a/docs/i18n-l10n/translating-text-strings.md b/docs/i18n-l10n/translating-text-strings.md index d69c4ec15..22d307e88 100644 --- a/docs/i18n-l10n/translating-text-strings.md +++ b/docs/i18n-l10n/translating-text-strings.md @@ -56,7 +56,7 @@ Information in the PO file headers is ignored. [`i18ndude`](https://pypi.org/project/i18ndude/) should be used to create a script which searches particular packages for translation strings. -If you have created your add-on using [bobtemplates.plone](https://pypi.org/project/bobtemplates.plone/), then you will already have a script `update.sh` inside your package and a script `update_locale` in your {term}`buildout` to extract the messages from your code. +If you have created your add-on using [bobtemplates.plone](https://pypi.org/project/bobtemplates.plone/), then you will already have a script `update.sh` inside your package and a script `update_locale` in your buildout to extract the messages from your code. After running that script, a new `domain.pot` file will be created in your `locales` directory where all the messages will be saved. @@ -273,7 +273,7 @@ This script hooks into the release process and builds the MO files for you. ### Installing i18ndude -The recommended method is to have {term}`i18ndude` installed via your buildout. +The recommended method is to have {term}`i18ndude` installed via your [buildout](https://www.buildout.org/en/latest/). Add the following to your `buildout.cfg`: From 4daa66cdbc0bc2e3ae2bbcf264814ea3500550ed Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 6 Nov 2024 18:25:24 -0800 Subject: [PATCH 515/810] Simplify the introductory container installation docs (#1729) It's a best practice to run Volto in seamless mode, where the API is served at the same domain with the /++api++ prefix. This avoids complications with browser cross-origin restrictions when the browser accesses the backend directly at a different domain. So, we should show this best practice here. The current example sets RAZZLE_API_PATH, because the default is http://localhost:8080/Plone which does not work inside a container. But, setting RAZZLE_API_PATH also stops using the best practice of seamless mode. We can avoid this by setting RAZZLE_DEV_PROXY_API_PATH instead. (Future improvement: make Volto recognize when it is running in a container, so that it can use http://host.docker.internal:8080/Plone as the default API path instead of localhost. Then it would not be necessary to set RAZZLE_DEV_PROXY_API_PATH here.) Co-authored-by: David Glick --- docs/install/containers/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/install/containers/index.md b/docs/install/containers/index.md index 0d75813d8..6edf7bcb0 100644 --- a/docs/install/containers/index.md +++ b/docs/install/containers/index.md @@ -66,13 +66,13 @@ Docker Desktop includes all Docker tools. First start the Plone Backend, naming it `plone6-backend` and creating a site with its default configuration, using the following command. ```shell -docker run --name plone6-backend -e SITE=Plone -e CORS_ALLOW_ORIGIN='*' -d -p 8080:8080 plone/plone-backend:{PLONE_BACKEND_MINOR_VERSION} +docker run --name plone6-backend -e SITE=Plone -d -p 8080:8080 plone/plone-backend:{PLONE_BACKEND_MINOR_VERSION} ``` Now start the Plone Frontend, linking it to the `plone6-backend`: ```shell -docker run --name plone6-frontend --link plone6-backend:backend -e RAZZLE_API_PATH=http://localhost:8080/Plone -e RAZZLE_INTERNAL_API_PATH=http://backend:8080/Plone -d -p 3000:3000 plone/plone-frontend:latest +docker run --name plone6-frontend --link plone6-backend:backend -e RAZZLE_DEV_PROXY_API_PATH=http://backend:8080/Plone -d -p 3000:3000 plone/plone-frontend:latest ``` From cdd32bac106d4c588c71c3fe2a2fc49678221645 Mon Sep 17 00:00:00 2001 From: Maik Derstappen Date: Thu, 7 Nov 2024 05:54:51 +0200 Subject: [PATCH 516/810] Improve install docs (#1760) * rm deployment from admin guide description, as deployment has it's own chapter * correct venv creation, never mix venv and other configation files * Update docs/admin-guide/run-plone.md Co-authored-by: David Glick * Apply suggestions from code review --------- Co-authored-by: David Glick Co-authored-by: Steve Piercy --- docs/admin-guide/index.md | 2 +- docs/admin-guide/install-buildout.md | 15 ++++++++++++--- docs/admin-guide/install-pip.md | 6 +++--- docs/admin-guide/run-plone.md | 1 + 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/docs/admin-guide/index.md b/docs/admin-guide/index.md index cf15440e2..cfd1fd152 100644 --- a/docs/admin-guide/index.md +++ b/docs/admin-guide/index.md @@ -11,7 +11,7 @@ myst: # Admin guide -In this part of the documentation, you can find how to install, operate, configure, and deploy Plone. +In this part of the documentation, you can find how to install, operate, and configure Plone. ```{toctree} diff --git a/docs/admin-guide/install-buildout.md b/docs/admin-guide/install-buildout.md index f0f87cc2e..2cd5c586f 100644 --- a/docs/admin-guide/install-buildout.md +++ b/docs/admin-guide/install-buildout.md @@ -25,7 +25,7 @@ For other installation options, see {ref}`get-started-install-label`. ## Prerequisites for installation - For Plone 6.0, Python {SUPPORTED_PYTHON_VERSIONS_PLONE60} -% TODO: These instructions install Plone 6.0.x. Uncomment next line and change the subsequent include when Plone 6.1 is released and "latest". +% TODO: These instructions install Plone 6.0.x. Uncomment next line and change the subsequent include when Plone 6.1 is released and "latest". % - For Plone 6.1, Python {SUPPORTED_PYTHON_VERSIONS_PLONE61} @@ -47,15 +47,17 @@ cd /plone Create a Python virtual environment. ```shell -python3 -m venv . +python3 -m venv venv ``` Install the minimal Python packages needed in order to run Buildout. ```shell -bin/pip install -r https://dist.plone.org/release/6-latest/requirements.txt +venv/bin/pip install -r https://dist.plone.org/release/6-latest/requirements.txt ``` + + Create a {file}`buildout.cfg` file in your directory with the following contents. ```cfg @@ -75,6 +77,12 @@ eggs = Plone ``` +Use Buildout's [`bootstrap` command](https://www.buildout.org/en/latest/topics/bootstrapping.html) to install a local `buildout` script in the {file}`bin` directory. + +```shell +venv/bin/buildout bootstrap +``` + Run Buildout. ```shell @@ -83,6 +91,7 @@ bin/buildout This may take a few minutes. +Whenever you change the Buildout configuration, run `./bin/buildout` again. ## Start Plone in foreground mode diff --git a/docs/admin-guide/install-pip.md b/docs/admin-guide/install-pip.md index 62ede6906..cb8aad8de 100644 --- a/docs/admin-guide/install-pip.md +++ b/docs/admin-guide/install-pip.md @@ -25,7 +25,7 @@ For other installation options, see {ref}`get-started-install-label`. ## Prerequisites for installation - For Plone 6.0, Python {SUPPORTED_PYTHON_VERSIONS_PLONE60} -% TODO: These instructions install Plone 6.0.x. Uncomment next line and change the subsequent include when Plone 6.1 is released and "latest". +% TODO: These instructions install Plone 6.0.x. Uncomment next line and change the subsequent include when Plone 6.1 is released and "latest". % - For Plone 6.1, Python {SUPPORTED_PYTHON_VERSIONS_PLONE61} @@ -47,13 +47,13 @@ cd /plone Create a Python virtual environment. ```shell -python3 -m venv . +python3 -m venv venv ``` Install Plone and a helper package, {term}`pipx`. ```shell -bin/pip install -c https://dist.plone.org/release/6.0-latest/constraints.txt Plone pipx +venv/bin/pip install -c https://dist.plone.org/release/6.0-latest/constraints.txt Plone pipx ``` diff --git a/docs/admin-guide/run-plone.md b/docs/admin-guide/run-plone.md index d90e363be..66eb6ed30 100644 --- a/docs/admin-guide/run-plone.md +++ b/docs/admin-guide/run-plone.md @@ -19,6 +19,7 @@ There are different commands to run Plone, depending on which method you used to Running Plone in foreground mode will show output in the terminal. This is recommended while developing a Plone site. +The command you use depends on the installation method you used. Cookieplone: : ```shell From e7751efd26c8d6146a4f7089fc8284cde2de7ac2 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 6 Nov 2024 21:44:58 -0800 Subject: [PATCH 517/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 5d08348bf..5c0dd143f 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 5d08348bf443a67241a995e6c917eadf6d81b1fc +Subproject commit 5c0dd143fca3b0c6be46e384eefbda12be06b536 From 063673af3f02a6427fbb0895e08d82a559a7b736 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 7 Nov 2024 00:09:14 -0800 Subject: [PATCH 518/810] Add anchors for linking from Training via Intersphinx (#1762) Ping @nileshgulia1 --- docs/install/create-project-cookieplone.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/install/create-project-cookieplone.md b/docs/install/create-project-cookieplone.md index 465bfbfdc..db864f1ba 100644 --- a/docs/install/create-project-cookieplone.md +++ b/docs/install/create-project-cookieplone.md @@ -33,11 +33,16 @@ For other installation options, see {ref}`get-started-install-label`. Plone 6 has both hardware requirements and software prerequisites. +(create-project-cookieplone-hardware-requirements-label)= + ### Hardware requirements ```{include} /_inc/_hardware-requirements.md ``` + +(create-project-cookieplone-prerequisites-for-installation-label)= + ### Prerequisites for installation ```{include} ../volto/contributing/install-operating-system.md From 4c6f65d0da8410f1af0122c200ac42fadafed410 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 7 Nov 2024 00:59:01 -0800 Subject: [PATCH 519/810] Add anchors for linking from Training via Intersphinx (#1763) Ping @nileshgulia1 --- docs/install/create-project-cookieplone.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/install/create-project-cookieplone.md b/docs/install/create-project-cookieplone.md index db864f1ba..306412a8e 100644 --- a/docs/install/create-project-cookieplone.md +++ b/docs/install/create-project-cookieplone.md @@ -101,6 +101,8 @@ pip install pipx ``` +(create-project-cookieplone-generate-the-project-label)= + ## Generate the project After satisfying the prerequisites and having activated an LTS version of Node, From a0993fefba3b1d16ad4042d56bfaa512fee0cd01 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 7 Nov 2024 03:32:46 -0800 Subject: [PATCH 520/810] Fix Docker Desktop install link redirects (#1765) --- docs/install/containers/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/install/containers/index.md b/docs/install/containers/index.md index 6edf7bcb0..52aa0d809 100644 --- a/docs/install/containers/index.md +++ b/docs/install/containers/index.md @@ -45,9 +45,9 @@ Although there are many container engine tools for developing, managing, and run The system requirements include those required by Docker itself. -- [Linux](https://docs.docker.com/desktop/install/linux/) -- [macOS](https://docs.docker.com/desktop/install/mac-install/) -- [Windows](https://docs.docker.com/desktop/install/windows-install/) +- [Linux](https://docs.docker.com/desktop/setup/install/linux/) +- [macOS](https://docs.docker.com/desktop/setup/install/mac-install/) +- [Windows](https://docs.docker.com/desktop/setup/install/windows-install/) Plone 6 itself requires memory and disk space in addition to those of Docker alone. See its {ref}`install-packages-hardware-requirements-label`. From 1b5a9dc975e8343ba0bd76e56b957205c1747a24 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 7 Nov 2024 04:39:31 -0800 Subject: [PATCH 521/810] Add content for Backend > Search (#1764) Closes #281 @gforcada @jensens --- docs/backend/search.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/docs/backend/search.md b/docs/backend/search.md index 318453e55..dbe73570d 100644 --- a/docs/backend/search.md +++ b/docs/backend/search.md @@ -1,16 +1,30 @@ --- myst: html_meta: - "description": "" - "property=og:description": "" - "property=og:title": "" - "keywords": "" + "description": "How to index and search content in Plone" + "property=og:description": "How to index and search content in Plone" + "property=og:title": "Search" + "keywords": "Plone, search, index, querystring, catalog" --- (backend-search-label)= # Search +To index and search content in Plone, see the Plone 5 documentation {doc}`/develop/plone/searching_and_indexing/index`. + +Alternatively, you can integrate any open source search engine with your Plone site. + +- [Solr](https://solr.apache.org/) - See the add-on [`collective.solr`](https://github.com/collective/collective.solr) and its [documentation](https://collectivesolr.readthedocs.io/en/latest/). +- [`collective.elasticsearch`](https://github.com/collective/collective.elasticsearch) +- [`collective.elastic.plone`](https://github.com/collective/collective.elastic.plone) + +You can find a comprehensive list of search options in [Awesome Plone - Searching and Categorizing](https://github.com/collective/awesome-plone?tab=readme-ov-file#searching-and-categorizing) + + +```{todo} +Help us [Migrate content from v5 "Queries, Search And Indexing" #1730](https://github.com/plone/documentation/issues/1730). +``` (backend-search-catalog-label)= From 5f09714b5749d55b2935858a0599c8776a9b882f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 8 Nov 2024 03:51:51 -0800 Subject: [PATCH 522/810] Fix reference to Plone 5 docs (#1767) --- docs/backend/search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend/search.md b/docs/backend/search.md index dbe73570d..5e25aadc2 100644 --- a/docs/backend/search.md +++ b/docs/backend/search.md @@ -11,7 +11,7 @@ myst: # Search -To index and search content in Plone, see the Plone 5 documentation {doc}`/develop/plone/searching_and_indexing/index`. +To index and search content in Plone, see the Plone 5 documentation {doc}`plone5:develop/plone/searching_and_indexing/index`. Alternatively, you can integrate any open source search engine with your Plone site. From 4812700c18bd16a478c387f0917a2d96ee92bfbd Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 8 Nov 2024 03:53:09 -0800 Subject: [PATCH 523/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 5c0dd143f..4aecd1c86 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 5c0dd143fca3b0c6be46e384eefbda12be06b536 +Subproject commit 4aecd1c862f9a2ff42261f3dcc656f287953cedd From 50e4c5fe7a04beb9b4c7896188cf35da29c1ab34 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 9 Nov 2024 01:29:02 -0800 Subject: [PATCH 524/810] Update tips submodules/plone.restapi submodules/volto --- submodules/plone.restapi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/plone.restapi b/submodules/plone.restapi index 9f0feffad..4f3bb4f1c 160000 --- a/submodules/plone.restapi +++ b/submodules/plone.restapi @@ -1 +1 @@ -Subproject commit 9f0feffad288f18e5fa3d3f63094614971d1d164 +Subproject commit 4f3bb4f1c656295f609a9aaea4540325d1b55b8e From 13caea4667e8e7ab64ce908aaf1101c6d0b99ad6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 9 Nov 2024 03:53:58 -0800 Subject: [PATCH 525/810] Move Python virtual environment into venv from root (#1769) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move Python virtual environment into venv from root `--clear` is the recommended way to wipe and recreate a clean virtual environment. `python3 -m venv venv --clear` will purge files and directories, such as `.git` and `.my_special_config`, from the current directory. This would be Very Bad™. - Enhance `make distclean` such that it cleans both the docs directory and the virtual environment, then recreates the virtual environment and installs requirements into it. This is useful when your project gets confused about what exactly is in your virtual environment - Update internal Makefile command. No change to user commands. Credit to @mrtango * Add to .gitignore --- .gitignore | 6 +----- Makefile | 32 +++++++++++++++++++------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 82863e71d..7944bc77e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,7 @@ # Dependencies -/bin -/include -/lib -/lib64 +/venv # Generated files -pyvenv.cfg /_build /styles/Microsoft /share diff --git a/Makefile b/Makefile index 98e33474b..6d54cdb42 100644 --- a/Makefile +++ b/Makefile @@ -5,10 +5,11 @@ SHELL = bash # You can set these variables from the command line. SPHINXOPTS ?= PAPER ?= +VALEOPTS ?= # Internal variables. -SPHINXBUILD = "$(realpath bin/sphinx-build)" -SPHINXAUTOBUILD = "$(realpath bin/sphinx-autobuild)" +SPHINXBUILD = "$(realpath venv/bin/sphinx-build)" +SPHINXAUTOBUILD = "$(realpath venv/bin/sphinx-autobuild)" DOCS_DIR = ./docs/ BUILDDIR = ../_build PAPEROPT_a4 = -D latex_paper_size=a4 @@ -29,20 +30,25 @@ clean: ## Clean docs build directory cd $(DOCS_DIR) && rm -rf $(BUILDDIR)/ .PHONY: distclean -distclean: ## Clean docs build directory and Python virtual environment +distclean: ## Clean docs build directory and Python virtual environment, then install requirements cd $(DOCS_DIR) && rm -rf $(BUILDDIR)/ - rm -rf ./bin/ ./lib/ ./lib64 ./include ./pyvenv.cfg - + python3 -m venv venv --clear + venv/bin/pip install -r requirements-initial.txt + venv/bin/pip install -r requirements.txt + @echo + @echo "Installation of requirements completed." -bin/python: - python3 -m venv . - bin/pip install -r requirements-initial.txt - bin/pip install -r requirements.txt +venv/bin/python: ## Setup up Python virtual environment and install requirements + python3 -m venv venv + venv/bin/pip install -r requirements-initial.txt + venv/bin/pip install -r requirements.txt + @echo + @echo "Installation of requirements completed." docs/plone.api: git submodule init; \ git submodule update; \ - bin/pip install -e submodules/plone.api/"[test]"; \ + venv/bin/pip install -e submodules/plone.api/"[test]"; \ ln -s ../submodules/plone.api/docs ./docs/plone.api @echo @echo "Documentation of plone.api initialized." @@ -62,7 +68,7 @@ docs/volto: @echo "Documentation of volto initialized." .PHONY: deps -deps: bin/python docs/volto docs/plone.restapi docs/plone.api ## Create Python virtual environment, install requirements, initialize or update the volto, plone.restapi, and plone.api submodules, and finally create symlinks to the source files. +deps: venv/bin/python docs/volto docs/plone.restapi docs/plone.api ## Create Python virtual environment, install requirements, initialize or update the volto, plone.restapi, and plone.api submodules, and finally create symlinks to the source files. .PHONY: html @@ -196,8 +202,8 @@ linkcheckbroken: deps ## Run linkcheck and show only broken links .PHONY: vale vale: deps ## Run Vale style, grammar, and spell checks - bin/vale sync - bin/vale --no-wrap $(VALEFILES) + venv/bin/vale sync + venv/bin/vale --no-wrap $(VALEOPTS) $(VALEFILES) @echo @echo "Vale is finished; look for any errors in the above output." From 7f75e8bbd4564b912bbbf13529df8b96b7188849 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 13 Nov 2024 01:16:37 -0800 Subject: [PATCH 526/810] Add comparison between Buildout and pip installation tools for Classic UI (#1766) --- .../conceptual-guides/compare-buildout-pip.md | 38 +++++++++++++++++++ docs/glossary.md | 3 ++ docs/install/index.md | 2 + 3 files changed, 43 insertions(+) create mode 100644 docs/conceptual-guides/compare-buildout-pip.md diff --git a/docs/conceptual-guides/compare-buildout-pip.md b/docs/conceptual-guides/compare-buildout-pip.md new file mode 100644 index 000000000..af770a706 --- /dev/null +++ b/docs/conceptual-guides/compare-buildout-pip.md @@ -0,0 +1,38 @@ +--- +myst: + html_meta: + "description": "Compare Plone Classic UI's installation tools, Buildout and pip" + "property=og:description": "Compare Plone Classic UI's installation tools, Buildout and pip" + "property=og:title": "Compare Buildout and pip" + "keywords": "Plone 6, Conceptual guides, Classic UI, Buildout, pip, install" +--- + +# Compare Buildout and pip + +This guide explains the differences between two tools, {term}`Buildout` and {term}`pip`, to install Plone and its Classic UI user interface, helping to inform your choice when developing your new project in Plone. + +The choice of installation tool has implications for admins and developers. + +````{grid} 1 1 1 2 +:gutter: 1 +:margin: 0 +:padding: 0 + +```{grid-item-card} Buildout +- You can create recipes to automate development and production installations. +- Maintained and used primarily by the small Plone community. +- May have problems resolving dependencies when a new pip or setuptools version is released. +- Source checkouts managed through {term}`mr.developer`. +``` + +```{grid-item-card} pip +- Installs or uninstalls packages only. +- Maintained and used by the large Python community. +- Changes in dependency resolution are well-documented. +- Source checkouts managed through {term}`mxdev`. +``` +```` + +```{seealso} +[Proposal: Use pip constraints as canonical version location #3670](https://github.com/plone/Products.CMFPlone/issues/3670) +``` \ No newline at end of file diff --git a/docs/glossary.md b/docs/glossary.md index ed4b20897..83da720e1 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -296,6 +296,9 @@ TC39 They established a [process](https://tc39.es/process-document/) where the proposals are discussed, developed, and eventually approved (or dropped). The process has five Stages (0 to 4) where reaching the Stage 4 means the proposal is finished, and it becomes part of the JavaScript specification. +`mr.developer` + [`mr.developer`](https://pypi.org/project/mr.developer/) is a {term}`Buildout` extension that makes it easy to work with buildouts containing lots of packages, where you only want to develop a few of them. + `mrs-developer` Also called "missdev", a tool similar to buildout's `mr.developer`. It automatically downloads and keeps up to date copies of software and add-ons under development based on definitions stored in `mrs.developer.json`. diff --git a/docs/install/index.md b/docs/install/index.md index f3218e913..817999afd 100644 --- a/docs/install/index.md +++ b/docs/install/index.md @@ -41,6 +41,8 @@ https://demo.plone.org/ First, choose a Plone user interface, or frontend. You can read {doc}`/conceptual-guides/choose-user-interface` to help inform your choice between Volto and Classic UI. +If you choose Classic UI, then you can read {doc}`/conceptual-guides/compare-buildout-pip` to help inform your choice between Buildout and pip for an installation method. + Then choose one of the following installation methods. If you are following a [Plone training](https://training.plone.org/), it should specify which option to choose. From 646b8480c39cb8dbd6f8266256d56f52edc416b4 Mon Sep 17 00:00:00 2001 From: Peter Mathis Date: Wed, 13 Nov 2024 10:48:47 +0100 Subject: [PATCH 527/810] Mention playwright robottest browser setup for local testing (#1772) * mention playwright robottest browser setup * Apply suggestions from code review --------- Co-authored-by: Steve Piercy --- docs/contributing/core/index.md | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/docs/contributing/core/index.md b/docs/contributing/core/index.md index 565f405b0..187e4af14 100644 --- a/docs/contributing/core/index.md +++ b/docs/contributing/core/index.md @@ -248,12 +248,29 @@ It takes 5-10 minutes to run the full unit test suite. If you run acceptance tests with the `--all` option, it will run tests in a real browser. This takes 30-40 minutes to run. This may repeatedly launch and close browser windows that gain focus, disrupting you from doing any other work. -If this happens, you can install the `chromedriver` OS package. -See https://developer.chrome.com/docs/chromedriver. -Then run `export ROBOT_BROWSER="headlesschrome"` and again run `bin/test --all`. +If this happens, you can use `headlesschrome` as the test browser. +First set an environment variable. + +```shell +export ROBOT_BROWSER="headlesschrome" +``` + +Then run all tests again. + +```shell +bin/test --all +``` + +Plone uses [Playwright](https://playwright.dev/) to run robot tests. +`plone.app.robotframework` provides a script to install Playwrite browsers. + +```shell +./bin/rfbrowser init +``` + +After the script downloads and initalizes browser resources, you can run the acceptance tests. ```shell -# Run acceptance tests ./bin/test --all ``` From 34bcec3dc49babd098094d117669381fc461e305 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 13 Nov 2024 02:07:23 -0800 Subject: [PATCH 528/810] Update tip submodules/volto --- submodules/volto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/volto b/submodules/volto index 4aecd1c86..157df05e5 160000 --- a/submodules/volto +++ b/submodules/volto @@ -1 +1 @@ -Subproject commit 4aecd1c862f9a2ff42261f3dcc656f287953cedd +Subproject commit 157df05e5da7cc4349f2fefaa6e3566da56a8213 From 1a48d647a40e40b429726fa3b393492ffb1b2d4d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 13 Nov 2024 02:39:32 -0800 Subject: [PATCH 529/810] Use Plone Sphinx Theme (#1770) * Use Plone Sphinx Theme for the theme - Update requirements.txt, removing pins and obsolete packages - Move vale styles into proper location * Sync conf.py with Plone Sphinx Theme options * Fix configuration for version and switcher Remove conflicting templates * Remove conflicting static assets and template files, and adjust configuration accordingly. * Remove obsolete Netlify files * Align version switcher to match this version * Add YouTube social icon. Remove obsolete comments. * Revert `make distclean` to merely purge the venv * Fix scrollspy * Whoops, just delete this monkeypatch, as it comes straight from PST. * Move icon-links from primary sidebar to footer_content_items. - Remove `version` from the whole-page footer. - Sort html_theme_options --- Makefile | 9 +- docs/_static/custom.css | 467 -------------- docs/_static/patch_scrollToActive.js | 41 -- docs/_static/search_shortcut.js | 35 - docs/_static/searchtools.js | 604 ------------------ docs/_static/switcher.json | 2 +- docs/_templates/layout.html | 5 - docs/_templates/page.html | 18 - docs/_templates/search-field.html | 19 - docs/_templates/search.html | 136 ---- docs/_templates/sections/header-article.html | 35 - docs/_templates/sections/sidebar.html | 4 - docs/conf.py | 253 +++++--- docs/netlify_robots.txt | 3 - netlify.toml | 6 - requirements.txt | 21 +- .../vocabularies}/Base/accept.txt | 0 .../vocabularies}/Base/reject.txt | 0 .../vocabularies}/Plone/accept.txt | 0 .../vocabularies}/Plone/reject.txt | 0 20 files changed, 171 insertions(+), 1487 deletions(-) delete mode 100644 docs/_static/custom.css delete mode 100644 docs/_static/patch_scrollToActive.js delete mode 100644 docs/_static/search_shortcut.js delete mode 100644 docs/_static/searchtools.js delete mode 100644 docs/_templates/page.html delete mode 100644 docs/_templates/search-field.html delete mode 100644 docs/_templates/search.html delete mode 100644 docs/_templates/sections/header-article.html delete mode 100644 docs/_templates/sections/sidebar.html delete mode 100644 docs/netlify_robots.txt delete mode 100644 netlify.toml rename styles/{Vocab => config/vocabularies}/Base/accept.txt (100%) rename styles/{Vocab => config/vocabularies}/Base/reject.txt (100%) rename styles/{Vocab => config/vocabularies}/Plone/accept.txt (100%) rename styles/{Vocab => config/vocabularies}/Plone/reject.txt (100%) diff --git a/Makefile b/Makefile index 6d54cdb42..f48736ff9 100644 --- a/Makefile +++ b/Makefile @@ -30,13 +30,8 @@ clean: ## Clean docs build directory cd $(DOCS_DIR) && rm -rf $(BUILDDIR)/ .PHONY: distclean -distclean: ## Clean docs build directory and Python virtual environment, then install requirements - cd $(DOCS_DIR) && rm -rf $(BUILDDIR)/ - python3 -m venv venv --clear - venv/bin/pip install -r requirements-initial.txt - venv/bin/pip install -r requirements.txt - @echo - @echo "Installation of requirements completed." +distclean: clean ## Clean docs build directory and Python virtual environment + rm -rf venv venv/bin/python: ## Setup up Python virtual environment and install requirements python3 -m venv venv diff --git a/docs/_static/custom.css b/docs/_static/custom.css deleted file mode 100644 index 6242c425c..000000000 --- a/docs/_static/custom.css +++ /dev/null @@ -1,467 +0,0 @@ -:root { - /* Add Font Awesome 5 icon and color for todo */ - --pst-icon-clipboard-list: '\f46d'; - --pst-icon-admonition-todo: var(--pst-icon-clipboard-list); - --pst-color-admonition-todo: 161, 46, 233; - --target-color: #b9ee9e; - --codeblock-color: #aad993; -} - -.visuallyhidden { - display: none; -} - -pre { - border-radius: 0; - background-color: white; - box-shadow: none; -} - -a, -a:visited, -main.bd-content #main-content a, -main.bd-content #main-content a:visited { - color: #2980b9; -} - -a:hover, -main.bd-content #main-content a:hover { - color: #1a567e; - text-decoration: none; -} - -ul { - list-style-type: square; -} - -ul li>p { - margin-bottom: 0.3rem; -} - -ol li>p { - margin-bottom: 0.3rem; -} - -img { - margin: 1rem 0; -} - -figure img, -img.figure, -.figure img { - box-shadow: 0 6px 24px 0 rgba(153, 153, 153, 0.3); -} - -.sidebar img.logo { - box-shadow: none; - width: 200px; - margin-bottom: 1rem; -} - -img.inline { - margin: 0; - height: 1em; -} - -span.linenos { - padding-right: 1em; -} - -p.ploneorglink img { - vertical-align: bottom; -} - -dt:target, -span.highlighted, -ul.search li span.highlighted { - background-color: var(--target-color); -} - -.bd-sidebar .nav ul { - padding: 0 0 0 1rem; -} - -.bd-sidebar .nav .toctree-checkbox~label i { - transform: rotate(90deg); -} - -.bd-sidebar .nav .toctree-checkbox:checked~label i { - transform: rotate(0deg); -} - -.toctree-wrapper .caption { - font-weight: bold; - font-size: 1.2em; - margin-top: 3rem; -} - -.toctree-wrapper ul { - list-style: none; -} - -section:not(#glossary) h1~dl { - display: grid; - grid-template-columns: max-content auto; -} - -section:not(#glossary) h1~dl dd { - margin-bottom: unset !important; -} - -div.section { - margin-bottom: 5rem; -} - -div.section div.section { - margin-bottom: 5rem; -} - -div.section div.section div.section { - margin-bottom: 2rem; -} - -/* admonitions */ -.admonition { - border-radius: 0; - border: none; - border-left: .2rem solid; - border-left-color: rgba(var(--pst-color-admonition-default), 1); -} - -.admonition .admonition-title { - margin-bottom: 1.5rem !important; -} - -/* admonition todo */ -.admonition.admonition-todo, -div.admonition.admonition-todo { - border-color: rgba(var(--pst-color-admonition-todo), 1); -} - -.admonition.admonition-todo>.admonition-title, -div.admonition.admonition-todo>.admonition-title { - background-color: rgba(var(--pst-color-admonition-todo), .1); -} - -.admonition.admonition-todo>.admonition-title::before, -div.admonition.admonition-todo>.admonition-title::before { - color: rgba(var(--pst-color-admonition-todo), 1); - content: var(--pst-icon-admonition-todo); -} - -.admonition-github-only.admonition { - display: none; -} - -/* admonition margin */ -.admonition.margin ul, -.admonition.margin ol { - padding-left: 1rem; -} - -.topic { - padding: 1.5em 1em .5em 1em; -} - -.topic-title { - font-weight: bold; -} - - -/* Bootstrap */ -.btn-primary { - color: #fff; - background-color: #2980b9; - border-color: #2980b9; -} - -.btn-primary { - background-color: #1f86ca; - border-color: #2980b9; -} - -/* Search */ - -/* Show search form. It is hidden by default. */ -#search-documentation, -#search-documentation~form, -#search-documentation~p { - display: block; -} - -#search-form:focus-within #shortcut-page, -.bd-search:focus-within #shortcut { - display: none; -} - -#shortcut-page.input-group-text { - padding-top: 0; - padding-bottom: 0; -} - -input#q { - border-radius: .25rem 0 0 .25rem; -} - -.form-control:focus { - box-shadow: none; - border-width: 2px; -} - -ul.search { - margin-left: 0; -} - -p.search-summary { - margin: 1em 0 2rem 0; -} - -#search-results ul { - list-style-type: none; - padding-left: 0; -} - -#search-results ul li, -ul.search li { - margin-bottom: 2rem; - padding: 0; - background-image: none; - border-bottom: none; -} - -#search-results ul li h3 { - margin: 0.4rem 0 .5rem; - font-size: 1.5rem; -} - -#search-results ul li .breadcrumbs { - display: flex; - flex-direction: row; - flex-wrap: wrap; -} - -#search-results ul li .breadcrumbs a { - font-weight: normal; -} - -#search-results ul li .breadcrumbs .lastbreadcrumb { - white-space: nowrap; - display: inline-block; - max-width: 12rem; - overflow: hidden; - /* "overflow"-Wert darf nicht "visible" sein */ - - text-overflow: ellipsis; -} - -ul.search li p.context { - margin-left: 0; -} - -/* Search form sidebar */ - -.bd-search { - font-size: .8rem; -} - -.bd-search:focus-within #search-input { - border-radius: .25rem; -} - -#shortcut.input-group-text { - padding-top: 0; - padding-bottom: 0; -} - -.bd-search input, -.bd-search .input-group-text { - font-size: .8rem; - padding-left: .5em; -} - -input#search-input { - padding-left: 2.1875rem; - border-radius: .25rem 0 0 .25rem; -} - -.search-icon { - position: absolute; - color: #a4a6a7; - left: .625rem; - z-index: 100; - align-self: center; -} - -.input-group-text kbd { - padding: 0rem 0.4rem; - font-size: 135%; -} - -.pathseparator { - padding: 0 0.7rem; -} - -/* header-article */ -div.header-article__label { - display: flex; - align-items: center; - margin: 0 auto 0 1em; - font-size: 80%; - overflow: hidden; - white-space: nowrap; -} - -/* submenu */ -.bd-toc { - box-shadow: 0 .2rem .5rem rgba(0, 0, 0, .05), 0 0 .0625rem rgba(0, 0, 0, .1); -} - -/* extra sidebar */ -div.sidebar:not(.margin) { - width: 40%; - float: right; - clear: right; - margin: .3rem 0 .3rem 0.5em; - padding: 2rem 0 1.5rem 1rem !important; - background-color: rgba(var(--pst-color-admonition-note), .1); - border: none; - border-left: 8px rgba(var(--pst-color-admonition-default), 1) solid; - border-radius: .2rem; - box-shadow: 0 .2rem .5rem rgba(0, 0, 0, .05), 0 0 .0625rem rgba(0, 0, 0, .1); -} - -div.sidebar:not(.margin) .figure { - margin-top: 0; - padding-top: 0; - margin-left: 0; - padding-left: 0; -} - -div.sidebar:not(.margin) img.logo { - margin-top: 0; - margin-bottom: .3rem; -} - -div.sidebar:not(.margin) p { - margin-bottom: 0; -} - -div.sidebar:not(.margin) p.sidebar-title { - display: none; -} - -div.sidebar:not(.margin) div.topic { - padding: .5em 0; - background-color: transparent; - border: none; -} - -div.sidebar:not(.margin) pre { - margin: .5em 0 1.5em 0; -} - -div.sidebar:not(.margin) div[class*="highlight-"] { - margin-right: .5em; -} - -div.sidebar:not(.margin) .admonition { - margin-right: .5em; - background-color: #ffffff; -} - -@media (min-width:768px) { - div.sidebar:not(.margin) { - width: 50%; - margin-left: 1.5em; - margin-right: -28%; - } -} - - -main.bd-content #main-content dl.simple dt { - margin-top: .8em; -} - -main.bd-content #main-content dl.simple dt:nth-of-type(1) { - margin-top: 0; -} - -main.bd-content #main-content dl.simple dd { - margin-top: .8em; -} - -main.bd-content #main-content dl.simple dt+dd { - margin-top: 0; -} - -.prev-next-bottom { - margin: 20px 0 30px 0; -} - -.prev-next-bottom a.left-prev, -.prev-next-bottom a.right-next { - padding: 5px 10px; - border: 1px solid rgba(0, 0, 0, .2); - max-width: 45%; - overflow-x: hidden; - color: rgba(0, 0, 0, .65); - border-radius: 10px; -} - -/* Local navigation */ -li.nav-item.toc-entry { - line-height: 1.25em; - margin-bottom: 0.25em; -} - -span.guilabel, -span.menuselection { - border: none; - background: #e7f2fa; - border-radius: 4px; - padding: 4px 5px; - font-size: 90%; - font-weight: bold; - white-space: nowrap; -} - - -/* - * extensions - */ - -/* definitions */ -dl.py.function { - margin-bottom: 5rem; -} - -dl.py.function>dt { - background-color: var(--codeblock-color); - padding: 4px 5px; -} - -dl.py.function>dt:target { - background-color: var(--target-color); -} - -dl.field-list>dt { - padding-left: 0; -} - -/* code blocks */ -div.viewcode-block:target { - padding: 10px 10px; - background-color: var(--codeblock-color); - border-top: 1px solid var(--codeblock-color); - border-bottom: 1px solid var(--codeblock-color); -} - -/* Fix paragraphs in list items. */ -#main-content ol > li > p:nth-child(n+2), -#main-content ul > li > p:nth-child(n+2) { - margin-top: 1em; -} - -video { - width: 100%; -} diff --git a/docs/_static/patch_scrollToActive.js b/docs/_static/patch_scrollToActive.js deleted file mode 100644 index 6cad65df0..000000000 --- a/docs/_static/patch_scrollToActive.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Patch of scrollToActive of sphinxbook theme - * Scroll to active navigation item - */ - -/** - * A helper function to load scripts when the DOM is loaded. - * This waits for everything to be on the page first before running, since - * some functionality doesn't behave properly until everything is ready. - */ - var sbRunWhenDOMLoaded = (cb) => { - if (document.readyState != "loading") { - cb(); - } else if (document.addEventListener) { - document.addEventListener("DOMContentLoaded", cb); - } else { - document.attachEvent("onreadystatechange", function () { - if (document.readyState == "complete") cb(); - }); - } -}; - -/** - * Sidebar scroll on load. - * - * Detect the active page in the sidebar, and scroll so that it is centered on - * the screen. - */ - -var scrollToActive = () => { - let navbar_scrollable = $("#site-navigation").children()[0]; - let active_navigation_item = $("#site-navigation .active").last(); - if (active_navigation_item) { - if (active_navigation_item.offset().top > $(window).height() * 0.5) { - navbar_scrollable.scrollTop = active_navigation_item.offset().top - $(window).height() * 0.2; - } - } -}; - - -sbRunWhenDOMLoaded(scrollToActive); diff --git a/docs/_static/search_shortcut.js b/docs/_static/search_shortcut.js deleted file mode 100644 index 177bf7f1a..000000000 --- a/docs/_static/search_shortcut.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Add shortcut `ctrl+k` to focus on search field - */ - - $(document).ready(() => { - if (window.location.pathname === '/search.html') { - $('form.bd-search .input-group').hide(); // Hide Sidebar Search field - - $(document).keydown(function(event) { - if ((event.ctrlKey || event.metaKey) && event.key == "k") { - event.preventDefault(); - $('#q').focus(); - } - }); - } else { - $(document).keydown(function(event) { - if ((event.ctrlKey || event.metaKey) && event.key == "k") { - event.preventDefault(); - $('#search-input').focus(); - } - }); - } - - // if OS isn't Mac change visual indication of search field - if (navigator.platform.indexOf('Mac') === -1) { - $('#search-shortcut').html("^"); - $('#search-page-shortcut').html("^"); - } - -}); - -function onReset() { - $('#search-form').trigger('reset'); - $('#search-form').trigger('submit'); -} \ No newline at end of file diff --git a/docs/_static/searchtools.js b/docs/_static/searchtools.js deleted file mode 100644 index a9b62c7e9..000000000 --- a/docs/_static/searchtools.js +++ /dev/null @@ -1,604 +0,0 @@ -/* - * searchtools.js - * ~~~~~~~~~~~~~~~~ - * - * Sphinx JavaScript utilities for the full-text search. - * - * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -var title_documentation = 'Plone Documentation'; - -if (!Scorer) { - /** - * Simple result scoring code. - */ - var Scorer = { - // Implement the following function to further tweak the score for each result - // The function takes a result array [filename, title, anchor, descr, score] - // and returns the new score. - /* - score: function(result) { - return result[4]; - }, - */ - - // query matches the full name of an object - objNameMatch: 11, - // or matches in the last dotted part of the object name - objPartialMatch: 6, - // Additive scores depending on the priority of the object - objPrio: {0: 15, // used to be importantResults - 1: 5, // used to be objectResults - 2: -5}, // used to be unimportantResults - // Used when the priority is not in the mapping. - objPrioDefault: 0, - - // query found in title - title: 15, - partialTitle: 7, - // query found in terms - term: 5, - partialTerm: 2 - }; -} - -if (!splitQuery) { - function splitQuery(query) { - return query.split(/\s+/); - } -} - -/** - * Search Module - */ -var Search = { - - _index : null, - _queued_query : null, - _pulse_status : -1, - - htmlToText : function(htmlString) { - var virtualDocument = document.implementation.createHTMLDocument('virtual'); - var htmlElement = $(htmlString, virtualDocument); - htmlElement.find('.headerlink').remove(); - docContent = htmlElement.find('[role=main]')[0]; - if(docContent === undefined) { - console.warn("Content block not found. Sphinx search tries to obtain it " + - "via '[role=main]'. Could you check your theme or template."); - return ""; - } - return docContent.textContent || docContent.innerText; - }, - - init : function() { - var params = $.getQueryParameters(); - let doc_section = params.doc_section ? params.doc_section[0] : 'all'; - $('input[id="doc_section_' + doc_section + '"]').prop("checked", true) - if (params.q) { - var query = params.q[0]; - $('input[name="q"]')[0].value = query; - $('input[name="q"]')[1].value = query; - this.performSearch(query, doc_section); - } - }, - - loadIndex : function(url) { - $.ajax({type: "GET", url: url, data: null, - dataType: "script", cache: true, - complete: function(jqxhr, textstatus) { - if (textstatus != "success") { - document.getElementById("searchindexloader").src = url; - } - }}); - }, - - setIndex : function(index) { - var q; - this._index = index; - if ((q = this._queued_query) !== null) { - this._queued_query = null; - Search.query(q); - } - }, - - hasIndex : function() { - return this._index !== null; - }, - - deferQuery : function(query) { - this._queued_query = query; - }, - - stopPulse : function() { - this._pulse_status = 0; - }, - - startPulse : function() { - if (this._pulse_status >= 0) - return; - function pulse() { - var i; - Search._pulse_status = (Search._pulse_status + 1) % 4; - var dotString = ''; - for (i = 0; i < Search._pulse_status; i++) - dotString += '.'; - Search.dots.text(dotString); - if (Search._pulse_status > -1) - window.setTimeout(pulse, 500); - } - pulse(); - }, - - /** - * perform a search for something (or wait until index is loaded) - */ - performSearch : function(query, doc_section) { - // create the required interface elements - this.out = $('#search-results'); - this.title = $('').appendTo(this.out); - this.dots = $('').appendTo(this.title); - this.status = $('

 

').appendTo(this.out); - this.output = $('

4;c*I%>| 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