https://github.com/williarin/cook
Composer plugin to execute recipes embedded in packages
https://github.com/williarin/cook
php recipe-manager
Last synced: about 1 hour ago
JSON representation
Composer plugin to execute recipes embedded in packages
- Host: GitHub
- URL: https://github.com/williarin/cook
- Owner: williarin
- License: mit
- Created: 2023-01-15T15:01:07.000Z (over 2 years ago)
- Default Branch: master
- Last Pushed: 2024-05-02T10:41:52.000Z (over 1 year ago)
- Last Synced: 2024-11-07T04:20:09.656Z (11 months ago)
- Topics: php, recipe-manager
- Language: PHP
- Homepage:
- Size: 56.6 KB
- Stars: 24
- Watchers: 2
- Forks: 6
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Cook
Baking recipes for any PHP package.
[](https://github.com/williarin/cook/actions)
* [Cook](#cook)
* [Introduction](#introduction)
* [Features](#features)
* [Installation](#installation)
* [Documentation](#documentation)
* [Creating a recipe](#creating-a-recipe)
* [Files](#files)
* [Directories](#directories)
* [Post install output](#post-install-output)
* [Mergers](#mergers)
* [Text](#text)
* [PHP array](#php-array)
* [JSON](#json)
* [YAML](#yaml)
* [Docker Compose](#docker-compose)
* [Placeholders](#placeholders)
* [CLI](#cli)
* [License](#license)## Introduction
Cook is a Composer plugin that executes recipes embedded in packages, in a similar fashion to [Symfony Flex](https://github.com/symfony/flex).
It can be used alongside with Flex, or in any other PHP project, as long as Composer is installed.### Features
* Add new entries to arrays or export new arrays, filter how you want to output it
* Add content to existing files or create them (.env, Makefile, or anything else)
* Copy entire directories from your repository to the project
* Keep existing data by default or overwrite it with a CLI command
* Supports PHP arrays, JSON, YAML, text files
* Output post install instructions
* Process only required packages in the root project
* Uninstall recipe when a package is removed
* CLI commands to install or uninstall recipes## Installation
```
composer require williarin/cook
```Make sure to allow the plugin to run. If it's not added automatically, add this in your `composer.json` file:
```json
"config": {
"allow-plugins": {
"williarin/cook": true
}
},
```## Documentation
### Creating a recipe
Take a look at [williarin/cook-example](https://github.com/williarin/cook-example) for a working example of a Cook recipe.
To make your package Cook-compatible, you just have to create a valid `cook.yaml` or `cook.json` at the root directory.
The recipe schema must follow this structure:
| Top level parameter | Type | Comments |
|-------------------------|--------|----------------------------------------------------------------------------|
| **files** | array | Individual files to be created or merged. |
| **directories** | array | List of directories to be entirely copied from the package to the project. |
| **post_install_output** | string | A text to display after installation or update of a package. |#### Files
Files are a described as key-value pairs.
* Key is the path to the destination file
* Value is either an array or a stringIf a string is given, it must be a path to the source file.
| Parameter | Type | Comments |
|------------------------------|------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **type** | string | Type of file.
**Choices:**
- `text`
- `php_array`
- `json`
- `yaml`
- `env`
- `docker_compose`
**Optional** |
| **destination** | string | Path of the destination file in the project that will be created or merged.
**Required** |
| **source** | string | Path of the source file in the package which content will be used to create or merge in the destination file.
**Required** if **content** isn't defined |
| **content** | string | Text to merge in the destination file.
**Required** if **source** isn't defined |
| **entries** | array | Key-value pairs used to fill a PHP or JSON array.
**Required** if **type** is of type `php_array` or `json` |
| **filters** | {keys: array\, values: array\} | Filters for **entries** when **type** is `php_array`.
**Choices:**
- `keys`
- `class_constant` Convert the given string to a class constant. As an example, `'Williarin\Cook'` becomes `Williarin\Cook::class`
- `values`
- `class_constant` See above
- `single_line_array` If the value is an array, it will be exported on a single line
| **valid_sections** | array\ | Used if **type** is `yaml` or `json` in order to restrict which top-level parameters need to be merged.
Example: `[parameters, services]`
**Optional** |
| **blank_line_after** | array\ | Used if **type** is `yaml` in order to add a blank line under the merged section.
Example: `[services]`
**Optional** |
| **uninstall_empty_sections** | boolean | Used if **type** is `yaml` in order to remove an empty recipe section when uninstalling the recipe.
**Default:** `false`
**Optional** |
| **if_exists** | string | Used if **type** is `text` or `env`.
**Choices:**
- For type `type`
- `append` Adds content to the end of an existing file, or creates a new one.
- `overwrite` Overwrites existing content, or creates a new file.
- `ignore` Doesn't alter an existing file, or creates a new file.
- For type `env`
- `comment` Comments same name env vars
- `delete` Delete same name env vars
**Optional** |
#### Directories
Directories are a described as key-value pairs.
* Key is the path to the destination directory that will receive the files
* Value is the path of the source directory in the package that contains the files
#### Post install output
Maybe you want to display some text to the user after installation.
You can use colors using [Symfony Console](https://symfony.com/doc/current/console/coloring.html) syntax.
### Mergers
#### Text
The text merger can be used to extend any text-based file such as:
* .gitignore
* Makefile
As it's the default merger, you can simply use the `destination: source` format in the recipe.
**Example 1:** append to an existing file
Given `yourrepo/recipe/.gitignore` with this content:
```
# Ignore the .env file
.env
```
With this recipe:
```yaml
files:
.gitignore: recipe/.gitignore
```
The created `.gitignore` file will look like this:
```
###> yourname/yourrepo ###
# Ignore the .env file
.env
###< yourname/yourrepo ###
```
The `###> yourname/yourrepo ###` opening comment and `###< yourname/yourrepo ###` closing comment are used by Cook to identify the recipe in the file.
If you're familiar with Symfony Flex, the syntax is the same.
**Example 2:** overwrite an existing file
If you want to overwrite the existing file, you can use the `if_exists` parameter.
```yaml
files:
.gitignore:
source: recipe/.gitignore
if_exists: overwrite
```
This will replace the entire content of the `.gitignore` file with the content of `recipe/.gitignore`.
**Example 3:** ignore an existing file
If you want to ignore the existing file, you can use the `if_exists` parameter.
```yaml
files:
.gitignore:
source: recipe/.gitignore
if_exists: ignore
```
This will not alter the existing `.gitignore` file, and will not create a new one if it doesn't exist.
#### Env
The env merger is used to add new environment variables to an existing `.env` file or create a new one if it doesn't exist.
**Example 1:** merge or create a `.env` file with a given source file
Given `yourrepo/recipe/.env` with this content:
```dotenv
SOME_ENV_VARIABLE='hello'
ANOTHER_ENV_VARIABLE='world'
```
And an existing `.env` file in the project with this content:
```dotenv
# Existing environment variables
SOME_ENV_VARIABLE='foo'
```
With this recipe:
```yaml
files:
.env:
type: env
source: recipe/.env
```
The created `.env` file will look like this:
```dotenv
# Existing environment variables
#SOME_ENV_VARIABLE='foo'
###> yourname/yourrepo ###
SOME_ENV_VARIABLE='hello'
ANOTHER_ENV_VARIABLE='world'
###< yourname/yourrepo ###
```
The existing `SOME_ENV_VARIABLE` is commented out to avoid conflicts with the new value, this is the default behavior of the env merger.
**Example 2:** merge or create a `.env` file with a string input
Alternatively, you can use `content` instead of `source`, to avoid creating a file in your repository.
```yaml
files:
.env:
content: |-
SOME_ENV_VARIABLE='hello'
ANOTHER_ENV_VARIABLE='world'
```
#### PHP array
The PHP array merger adds new entries to existing arrays or creates a file if it doesn't exist.
**Example 1:** without filters
This recipe will create or merge the file `config/bundles.php` in the project.
```yaml
files:
config/bundles.php:
type: php_array
entries:
Williarin\CookExample\CookExampleBundle:
dev: true
test: true
```
The output will look like this:
```php
[
'dev' => true,
'test' => true,
],
];
```
**Example 2:** with filters
Let's add some filters to our entries.
```yaml
files:
config/bundles.php:
# ...
filters:
keys: [class_constant]
values: [single_line_array]
```
The output will look like this:
```php
['dev' => true, 'test' => true],
];
```
#### JSON
The JSON merger adds new entries to an existing JSON file or creates a file if needed.
**Note:** Only top-level keys are merged.
**Example:**
This recipe will add a script in the `composer.json` file of the project.
```yaml
files:
composer.json:
type: json
entries:
scripts:
post-create-project-cmd: php -r "copy('config/local-example.php', 'config/local.php');"
```
The output will look like this:
```json5
{
// ... existing config
"scripts": {
// ... other scripts
"post-create-project-cmd": "php -r \"copy('config/local-example.php', 'config/local.php');\""
}
}
```
#### YAML
The YAML merger adds new parameters to top-level parameters in an existing file or creates a file if needed.
Although a YAML file represents arrays like JSON or PHP arrays, the specificity of this merger is to allow YAML comments.
Therefore, instead of using `entries` which restricts content as key-value pairs, you need to describe the content to merge as a string, or a YAML file.
**Example 1:** default config
Given this existing file in `config/services.yaml`:
```yaml
parameters:
database_url: postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=14&charset=utf8
services:
_defaults:
autowire: true
autoconfigure: true
```
With this recipe:
```yaml
files:
config/services.yaml:
type: yaml
content: |
parameters:
locale: fr
services:
Some\Service: ~
```
The output will look like this:
```yaml
parameters:
###> williarin/cook-example ###
locale: fr
###< williarin/cook-example ###
database_url: postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=14&charset=utf8
services:
###> williarin/cook-example ###
Some\Service: ~
###< williarin/cook-example ###
_defaults:
autowire: true
autoconfigure: true
```
**Example 2:** with blank lines
To make things a bit prettier, let's add a blank line below our `services` merge:
```yaml
files:
config/services.yaml:
# ...
blank_line_after: [services]
```
The output will look like this:
```yaml
parameters:
###> williarin/cook-example ###
locale: fr
###< williarin/cook-example ###
database_url: postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=14&charset=utf8
services:
###> williarin/cook-example ###
Some\Service: ~
###< williarin/cook-example ###
_defaults:
autowire: true
autoconfigure: true
```
**Note:** the YAML merger is only able to prepend existing content, not append.
**Uninstalling YAML recipe**
When uninstalling a recipe, the YAML merger will not remove the entire section if it's empty,
unless you set the `uninstall_empty_sections` parameter to `true`.
```yaml
files:
config/routes.yaml:
type: yaml
source: |
other_routes:
resource: .
type: other_routes_loader
uninstall_empty_sections: true
```
In this example, if the `other_routes` section is empty, it will be removed when uninstalling the recipe.
#### Docker Compose
The Docker Compose merger is similar to the YAML merger with only specific sections that would be merged.
Only `services`, `volumes`, `configs`, `secrets` and `networks` top-level sections will be merged.
### Placeholders
You can use several placeholders in your destination and source paths:
* `%BIN_DIR%`: defaults to `bin`
* `%CONFIG_DIR%`: defaults to `config`
* `%SRC_DIR%`: defaults to `src`
* `%VAR_DIR%`: defaults to `var`
* `%PUBLIC_DIR%`: defaults to `public`
* `%ROOT_DIR%`: defaults to `.` or, if defined, to `extra.symfony.root-dir` defined in `composer.json`
You can override any of these placeholders by defining them in your `composer.json` file.
```json
"extra": {
"bin-dir": "bin",
"config-dir": "config",
"src-dir": "src",
"var-dir": "var",
"public-dir": "public"
}
```
Any other variable defined in `extra` is available with `%YOUR_VARIABLE%` in your recipe.
```json
"extra": {
"your-variable": "..."
}
```
### CLI
You may want to execute your recipes after installation.
Cook provides you this command to execute all available recipes:
```bash
composer cook
```
It won't overwrite your configuration if it already exists. To overwrite everything, run:
```bash
composer cook --overwrite
```
Additionally, you can uninstall a recipe with this command:
```bash
composer cook:uninstall [--all]
```
Use either `` for individual package uninstallation or `--all` for all packages.
## License
[MIT](LICENSE)
Copyright (c) 2023, William Arin