recipe-plugin/README.md

188 lines
7.1 KiB
Markdown

# Silverstripe recipe-plugin
[![CI](https://github.com/silverstripe/recipe-plugin/actions/workflows/ci.yml/badge.svg)](https://github.com/silverstripe/recipe-plugin/actions/workflows/ci.yml)
[![Silverstripe supported module](https://img.shields.io/badge/silverstripe-supported-0071C4.svg)](https://www.silverstripe.org/software/addons/silverstripe-commercially-supported-module-list/)
## Introduction
This plugin enhances composer and allows for the installation of "silverstripe-recipe" packages.
These recipes allow for the following features:
- The ability to provide project resource files. These are copied to the appropriate project root location
on install, and can be safely modified by the developer. On subsequent updates to a later recipe,
composer will inform the user if a project file has been updated, and will ensure new files are
copied as they are introduced to the recipe.
- Recipes are composable, so resources or dependencies that are required by multiple recipes can include one another,
rather than having to duplicate content.
- Recipes also can be used as a base composer project.
- A `require-recipe` command to inline a recipe into the root composer.json, allowing the developer to customise the
recipe dependencies without mandating the inclusion of all requirements directly.
- An `update-recipe` command to upgrade to a newer version of a recipe.
## Example output
![example-output](docs/_images/require-usage.png)
## Creating a new project
Recipes can be introduced to any existing project (even if not created on a silverstripe base project)
```shell
$ composer init
$ composer require silverstripe/recipe-cms ^1.0@dev
````
Alternatively you can create a new project based on an existing recipe
```shell
$ composer create-project silverstripe/recipe-cms ./myssproject ^1.0@dev
```
## Inlining recipes
You can "inline" either a previously installed recipe, or a new one that you would like to include
dependencies for in your main project. By inlining a recipe, you promote its requirements, as well as
its project files, up into your main project, and remove the recipe itself from your dependencies.
This can be done with either `update-recipe`, which will update a recipe, or `require-recipe` which will
install a new recipe.
Note that if you wish to run this command you must first install either a recipe via normal composer
commands, or install the recipe plugin:
```shell
$ composer init
$ composer require silverstripe/recipe-plugin ^0.1
$ composer require-recipe silverstripe/recipe-cms ^1.0@dev
```
or
```shell
$ composer init
$ composer require silverstripe/recipe-cms ^1.0@dev
$ composer update-recipe silverstripe/recipe-cms
```
## Removing recipe dependencies or files
Any project file installed via a recipe, or any module installed by inlining a recipe, can be easily removed.
Subsequent updates to this recipe will not re-install any of those files or dependencies.
In order to ensure this, a record of all inlined modules, and all installed files are stored in composer.json
as below.
```json
{
"extra": {
"project-files-installed": [
"mysite/code/Page.php",
"mysite/code/PageController.php"
],
"project-dependencies-installed": {
"silverstripe/admin": "1.0.x-dev",
"silverstripe/asset-admin": "1.0.x-dev",
"silverstripe/campaign-admin": "1.0.x-dev"
}
}
}
```
To remove a file, simply delete it from the folder your project is installed in, but don't modify
`project-files-installed` (as this is how composer knows what not to re-install).
Likewise to remove a module, use `composer remove <module>` and it will be removed. As above, don't
modify `project-dependencies-instaleld`, otherwise that module will be re-installed on subsequent
`composer update-recipe`.
## Un-doing a deleted project file / dependency
If you have deleted a module or file and want to re-install it you should remove the appropriate
entry from either 'project-files-installed' or 'project-dependencies-installed' and then run
`composer update-recipe <recipe>` again.
The file or module will be re-installed.
## Removing recipes
As installation of a recipe inlines all dependencies and passes ownership to the root project,
there is no automatic removal process. To remove a recipe, you should manually remove any
required module that is no longer desired via `composer remove <module>`.
The `provide` reference to the recipe can also be safely removed, although it has no practical result
other than to disable future calls to `update-recipe` on this recipe.
## Installing or upgrading recipes without inlining them
If desired, the optional inline behaviour of recipes can be omitted. Simply use the composer commands `require` and
`update` in place of `require-recipe` and `update-recipe` respectively. This will not disable the project files
feature, but will not inline the recipe directly, keeping your root composer.json from getting cluttered.
If you have already inlined a recipe, it will be necessary to manually remove any undesired inlined requirements
manually, and the recipe will need to be included with `require` subsequently.
Note that using this method it's not necessary to include the `silverstripe/recipe-plugin` in the root project
for this to work.
## Recipe composer.json schema
Recipe types should follow the following rules:
- No mandatory resources, other than project files.
- Recipes must not rely on `autoload` as this are discarded on inline.
Likewise any `*-dev` or other root-only options should not be used, as these are ignored outside of the root project.
The exception to this is when these values are useful as a base project only.
- The `type` must be `silverstripe-recipe`
- The `require` must have `silverstripe/recipe-plugin` as a dependency.
- `extra.project-files` must be declared as a list of wildcard patterns, matching the files in the recipe root
as they should be copied to the root project. The relative paths of these resources are equivalent.
- `extra.public-files` must be declared for any files which should be copied to the `public` web folder. If the project
in question doesn't have any public folder, these will be copied to root instead. Note that all public files
must be committed to the recipe `public` folder.
An example recipe:
```json
{
"name": "silverstripe/example-recipe",
"description": "Example silverstripe recipe",
"type": "silverstripe-recipe",
"require": {
"silverstripe/recipe-plugin": "^0.1",
"silverstripe/recipe-cms": "^1.0",
"silverstripe/blog": "^3.0@dev",
"silverstripe/lumberjack": "^2.1@dev",
},
"extra": {
"project-files": [
"mysite/_config/*.yml",
"mysite/code/MyBlogPage.php"
"client/src/*"
],
"public-files": [
"client/dist/*"
]
},
"prefer-stable": true,
"minimum-stability": "dev"
}
```
The files within this recipe would be organised in the structure:
```
client/
src/
blog.scss
mysite/
_config/
settings.yml
code/
MyBlogPage.php
public/
client/
dist/
blog.css
composer.json
```