{"id":19624973,"url":"https://github.com/williarin/cook","last_synced_at":"2025-10-05T15:51:29.484Z","repository":{"id":65895691,"uuid":"589245099","full_name":"williarin/cook","owner":"williarin","description":"Composer plugin to execute recipes embedded in packages","archived":false,"fork":false,"pushed_at":"2024-05-02T10:41:52.000Z","size":58,"stargazers_count":24,"open_issues_count":1,"forks_count":6,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-11-07T04:20:09.656Z","etag":null,"topics":["php","recipe-manager"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/williarin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-15T15:01:07.000Z","updated_at":"2024-06-15T20:38:50.000Z","dependencies_parsed_at":"2023-12-29T16:38:46.414Z","dependency_job_id":"aa2449cd-f542-471a-9069-46c6484cf8b4","html_url":"https://github.com/williarin/cook","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/williarin%2Fcook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/williarin%2Fcook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/williarin%2Fcook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/williarin%2Fcook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/williarin","download_url":"https://codeload.github.com/williarin/cook/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224097674,"owners_count":17255353,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["php","recipe-manager"],"created_at":"2024-11-11T11:39:39.915Z","updated_at":"2025-10-05T15:51:29.470Z","avatar_url":"https://github.com/williarin.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cook\n\nBaking recipes for any PHP package.\n\n\n[![Github Workflow](https://github.com/williarin/cook/workflows/Test/badge.svg)](https://github.com/williarin/cook/actions)\n\n\u003c!-- TOC --\u003e\n* [Cook](#cook)\n  * [Introduction](#introduction)\n    * [Features](#features)\n  * [Installation](#installation)\n  * [Documentation](#documentation)\n    * [Creating a recipe](#creating-a-recipe)\n      * [Files](#files)\n      * [Directories](#directories)\n      * [Post install output](#post-install-output)\n    * [Mergers](#mergers)\n      * [Text](#text)\n      * [PHP array](#php-array)\n      * [JSON](#json)\n      * [YAML](#yaml)\n      * [Docker Compose](#docker-compose)\n    * [Placeholders](#placeholders)\n    * [CLI](#cli)\n  * [License](#license)\n\u003c!-- TOC --\u003e\n\n## Introduction\n\nCook is a Composer plugin that executes recipes embedded in packages, in a similar fashion to [Symfony Flex](https://github.com/symfony/flex).\nIt can be used alongside with Flex, or in any other PHP project, as long as Composer is installed.\n\n### Features\n\n* Add new entries to arrays or export new arrays, filter how you want to output it\n* Add content to existing files or create them (.env, Makefile, or anything else)\n* Copy entire directories from your repository to the project\n* Keep existing data by default or overwrite it with a CLI command\n* Supports PHP arrays, JSON, YAML, text files\n* Output post install instructions\n* Process only required packages in the root project\n* Uninstall recipe when a package is removed\n* CLI commands to install or uninstall recipes\n\n## Installation\n\n```\ncomposer require williarin/cook\n```\n\nMake sure to allow the plugin to run. If it's not added automatically, add this in your `composer.json` file:\n\n```json\n    \"config\": {\n        \"allow-plugins\": {\n            \"williarin/cook\": true\n        }\n    },\n```\n\n## Documentation\n\n### Creating a recipe\n\nTake a look at [williarin/cook-example](https://github.com/williarin/cook-example) for a working example of a Cook recipe.\n\nTo make your package Cook-compatible, you just have to create a valid `cook.yaml` or `cook.json` at the root directory.\n\nThe recipe schema must follow this structure:\n\n| Top level parameter     | Type   | Comments                                                                   |\n|-------------------------|--------|----------------------------------------------------------------------------|\n| **files**               | array  | Individual files to be created or merged.                                  |\n| **directories**         | array  | List of directories to be entirely copied from the package to the project. |\n| **post_install_output** | string | A text to display after installation or update of a package.               |\n\n#### Files\n\nFiles are a described as key-value pairs.\n\n* Key is the path to the destination file\n* Value is either an array or a string\n\nIf a string is given, it must be a path to the source file.\n\n| Parameter                    | Type                                           | Comments                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |\n|------------------------------|------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| **type**                     | string                                         | Type of file.\u003cbr/\u003e\u003cbr/\u003e**Choices:**\u003cul\u003e\u003cli\u003e`text`\u003c/li\u003e\u003cli\u003e`php_array`\u003c/li\u003e\u003cli\u003e`json`\u003c/li\u003e\u003cli\u003e`yaml`\u003c/li\u003e\u003cli\u003e`env`\u003c/li\u003e\u003cli\u003e`docker_compose`\u003c/li\u003e\u003c/ul\u003e**Default:** `text`\u003cbr/\u003e**Optional**                                                                                                                                                                                                                                                                                                                                                            |\n| **destination**              | string                                         | Path of the destination file in the project that will be created or merged.\u003cbr/\u003e\u003cbr/\u003e**Required**                                                                                                                                                                                                                                                                                                                                                                                                                                                   |\n| **source**                   | string                                         | Path of the source file in the package which content will be used to create or merge in the destination file.\u003cbr/\u003e\u003cbr/\u003e**Required** if **content** isn't defined                                                                                                                                                                                                                                                                                                                                                                                    |\n| **content**                  | string                                         | Text to merge in the destination file.\u003cbr/\u003e\u003cbr/\u003e**Required** if **source** isn't defined                                                                                                                                                                                                                                                                                                                                                                                                                                                            |\n| **entries**                  | array\u003cstring, mixed\u003e                           | Key-value pairs used to fill a PHP or JSON array.\u003cbr/\u003e\u003cbr/\u003e**Required** if **type** is of type `php_array` or `json`                                                                                                                                                                                                                                                                                                                                                                                                                                |\n| **filters**                  | {keys: array\\\u003cstring\u003e, values: array\\\u003cstring\u003e} | Filters for **entries** when **type** is `php_array`.\u003cbr/\u003e\u003cbr/\u003e**Choices:**\u003cul\u003e\u003cli\u003e`keys`\u003cul\u003e\u003cli\u003e`class_constant` Convert the given string to a class constant. As an example, `'Williarin\\Cook'` becomes `Williarin\\Cook::class`\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e`values`\u003cul\u003e\u003cli\u003e`class_constant` See above\u003c/li\u003e\u003cli\u003e`single_line_array` If the value is an array, it will be exported on a single line\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e**Optional**                                                                                                                           |\n| **valid_sections**           | array\\\u003cstring\u003e                                 | Used if **type** is `yaml` or `json` in order to restrict which top-level parameters need to be merged.\u003cbr/\u003e\u003cbr/\u003eExample: `[parameters, services]`\u003cbr/\u003e\u003cbr/\u003e**Optional**                                                                                                                                                                                                                                                                                                                                                                            |\n| **blank_line_after**         | array\\\u003cstring\u003e                                 | Used if **type** is `yaml` in order to add a blank line under the merged section.\u003cbr/\u003e\u003cbr/\u003eExample: `[services]`\u003cbr/\u003e\u003cbr/\u003e**Optional**                                                                                                                                                                                                                                                                                                                                                                                                              |\n| **uninstall_empty_sections** | boolean                                        | Used if **type** is `yaml` in order to remove an empty recipe section when uninstalling the recipe.\u003cbr/\u003e\u003cbr/\u003e**Default:** `false`\u003cbr/\u003e**Optional**                                                                                                                                                                                                                                                                                                                                                                                                  |\n| **if_exists**                | string                                         | Used if **type** is `text` or `env`. \u003cbr/\u003e\u003cbr/\u003e**Choices:**\u003cul\u003e\u003cli\u003eFor type `type`\u003cul\u003e\u003cli\u003e`append` Adds content to the end of an existing file, or creates a new one.\u003c/li\u003e\u003cli\u003e`overwrite` Overwrites existing content, or creates a new file.\u003c/li\u003e\u003cli\u003e`ignore` Doesn't alter an existing file, or creates a new file.\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eFor type `env`\u003cul\u003e\u003cli\u003e`comment` Comments same name env vars\u003c/li\u003e\u003cli\u003e`delete` Delete same name env vars\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e**Default:** `append` for `text` type. `comment` for `env` type.\u003cbr/\u003e**Optional** |\n\n#### Directories\n\nDirectories are a described as key-value pairs.\n\n* Key is the path to the destination directory that will receive the files\n* Value is the path of the source directory in the package that contains the files\n\n#### Post install output\n\nMaybe you want to display some text to the user after installation.  \nYou can use colors using [Symfony Console](https://symfony.com/doc/current/console/coloring.html) syntax.\n\n### Mergers\n\n#### Text\n\nThe text merger can be used to extend any text-based file such as:\n* .gitignore\n* Makefile\n\nAs it's the default merger, you can simply use the `destination: source` format in the recipe.\n\n**Example 1:** append to an existing file\n\nGiven `yourrepo/recipe/.gitignore` with this content:\n```\n# Ignore the .env file\n.env\n```\nWith this recipe:\n```yaml\nfiles:\n    .gitignore: recipe/.gitignore\n```\nThe created `.gitignore` file will look like this:\n```\n###\u003e yourname/yourrepo ###\n# Ignore the .env file\n.env\n###\u003c yourname/yourrepo ###\n```\n\nThe `###\u003e yourname/yourrepo ###` opening comment and `###\u003c yourname/yourrepo ###` closing comment are used by Cook to identify the recipe in the file.\nIf you're familiar with Symfony Flex, the syntax is the same.\n\n**Example 2:** overwrite an existing file\n\nIf you want to overwrite the existing file, you can use the `if_exists` parameter.\n\n```yaml\nfiles:\n    .gitignore:\n        source: recipe/.gitignore\n        if_exists: overwrite\n```\nThis will replace the entire content of the `.gitignore` file with the content of `recipe/.gitignore`.\n\n**Example 3:** ignore an existing file\n\nIf you want to ignore the existing file, you can use the `if_exists` parameter.\n\n```yaml\nfiles:\n    .gitignore:\n        source: recipe/.gitignore\n        if_exists: ignore\n```\nThis will not alter the existing `.gitignore` file, and will not create a new one if it doesn't exist.\n\n#### Env\n\nThe env merger is used to add new environment variables to an existing `.env` file or create a new one if it doesn't exist.\n\n**Example 1:** merge or create a `.env` file with a given source file\n\nGiven `yourrepo/recipe/.env` with this content:\n```dotenv\nSOME_ENV_VARIABLE='hello'\nANOTHER_ENV_VARIABLE='world'\n```\nAnd an existing `.env` file in the project with this content:\n```dotenv\n# Existing environment variables\nSOME_ENV_VARIABLE='foo'\n```\nWith this recipe:\n```yaml\nfiles:\n    .env:\n        type: env\n        source: recipe/.env\n```\nThe created `.env` file will look like this:\n```dotenv\n# Existing environment variables\n#SOME_ENV_VARIABLE='foo'\n\n###\u003e yourname/yourrepo ###\nSOME_ENV_VARIABLE='hello'\nANOTHER_ENV_VARIABLE='world'\n###\u003c yourname/yourrepo ###\n```\n\nThe existing `SOME_ENV_VARIABLE` is commented out to avoid conflicts with the new value, this is the default behavior of the env merger.\n\n**Example 2:** merge or create a `.env` file with a string input\n\nAlternatively, you can use `content` instead of `source`, to avoid creating a file in your repository.\n```yaml\nfiles:\n    .env:\n        content: |-\n            SOME_ENV_VARIABLE='hello'\n            ANOTHER_ENV_VARIABLE='world'\n```\n\n#### PHP array\n\nThe PHP array merger adds new entries to existing arrays or creates a file if it doesn't exist.\n\n**Example 1:** without filters\n\nThis recipe will create or merge the file `config/bundles.php` in the project.\n```yaml\nfiles:\n    config/bundles.php:\n        type: php_array\n        entries:\n            Williarin\\CookExample\\CookExampleBundle:\n                dev: true\n                test: true\n```\nThe output will look like this:\n```php\n\u003c?php\n\nreturn [\n    'Williarin\\CookExample\\CookExampleBundle' =\u003e [\n        'dev' =\u003e true,\n        'test' =\u003e true,\n    ],\n];\n```\n\n**Example 2:** with filters\n\nLet's add some filters to our entries.\n```yaml\nfiles:\n    config/bundles.php:\n        # ...\n        filters:\n            keys: [class_constant]\n            values: [single_line_array]\n```\nThe output will look like this:\n```php\n\u003c?php\n\nreturn [\n    Williarin\\CookExample\\CookExampleBundle::class =\u003e ['dev' =\u003e true, 'test' =\u003e true],\n];\n```\n\n#### JSON\n\nThe JSON merger adds new entries to an existing JSON file or creates a file if needed.\n\n**Note:** Only top-level keys are merged.\n\n**Example:**\n\nThis recipe will add a script in the `composer.json` file of the project.\n```yaml\nfiles:\n    composer.json:\n        type: json\n        entries:\n            scripts:\n                post-create-project-cmd: php -r \"copy('config/local-example.php', 'config/local.php');\"\n```\nThe output will look like this:\n```json5\n{\n    // ... existing config\n    \"scripts\": {\n        // ... other scripts\n        \"post-create-project-cmd\": \"php -r \\\"copy('config/local-example.php', 'config/local.php');\\\"\"\n    }\n}\n```\n\n#### YAML\n\nThe YAML merger adds new parameters to top-level parameters in an existing file or creates a file if needed.\n\nAlthough a YAML file represents arrays like JSON or PHP arrays, the specificity of this merger is to allow YAML comments.\nTherefore, 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.\n\n**Example 1:** default config\n\nGiven this existing file in `config/services.yaml`:\n```yaml\nparameters:\n    database_url: postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=14\u0026charset=utf8\n\nservices:\n    _defaults:\n        autowire: true\n        autoconfigure: true\n```\nWith this recipe:\n```yaml\nfiles:\n    config/services.yaml:\n        type: yaml\n        content: |\n            parameters:\n                locale: fr\n\n            services:\n                Some\\Service: ~\n```\nThe output will look like this:\n```yaml\nparameters:\n###\u003e williarin/cook-example ###\n    locale: fr\n###\u003c williarin/cook-example ###\n    database_url: postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=14\u0026charset=utf8\n\nservices:\n###\u003e williarin/cook-example ###\n    Some\\Service: ~\n###\u003c williarin/cook-example ###\n    _defaults:\n        autowire: true\n        autoconfigure: true\n```\n\n**Example 2:** with blank lines\n\nTo make things a bit prettier, let's add a blank line below our `services` merge:\n```yaml\nfiles:\n    config/services.yaml:\n        # ...\n        blank_line_after: [services]\n```\nThe output will look like this:\n```yaml\nparameters:\n###\u003e williarin/cook-example ###\n    locale: fr\n###\u003c williarin/cook-example ###\n    database_url: postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=14\u0026charset=utf8\n\nservices:\n###\u003e williarin/cook-example ###\n    Some\\Service: ~\n###\u003c williarin/cook-example ###\n    \n    _defaults:\n        autowire: true\n        autoconfigure: true\n```\n\n**Note:** the YAML merger is only able to prepend existing content, not append.\n\n**Uninstalling YAML recipe**\n    \nWhen uninstalling a recipe, the YAML merger will not remove the entire section if it's empty,\nunless you set the `uninstall_empty_sections` parameter to `true`.\n\n```yaml\nfiles:\n    config/routes.yaml:\n        type: yaml\n        source: |\n            other_routes:\n                resource: .\n                type: other_routes_loader\n        uninstall_empty_sections: true\n```\n\nIn this example, if the `other_routes` section is empty, it will be removed when uninstalling the recipe.\n\n#### Docker Compose\n\nThe Docker Compose merger is similar to the YAML merger with only specific sections that would be merged.\n\nOnly `services`, `volumes`, `configs`, `secrets` and `networks` top-level sections will be merged.\n\n### Placeholders\n\nYou can use several placeholders in your destination and source paths:\n* `%BIN_DIR%`: defaults to `bin`\n* `%CONFIG_DIR%`: defaults to `config`\n* `%SRC_DIR%`: defaults to `src`\n* `%VAR_DIR%`: defaults to `var`\n* `%PUBLIC_DIR%`: defaults to `public`\n* `%ROOT_DIR%`: defaults to `.` or, if defined, to `extra.symfony.root-dir` defined in `composer.json`\n\nYou can override any of these placeholders by defining them in your `composer.json` file.\n\n```json\n    \"extra\": {\n        \"bin-dir\": \"bin\",\n        \"config-dir\": \"config\",\n        \"src-dir\": \"src\",\n        \"var-dir\": \"var\",\n        \"public-dir\": \"public\"\n    }\n```\n\nAny other variable defined in `extra` is available with `%YOUR_VARIABLE%` in your recipe.\n\n```json\n    \"extra\": {\n        \"your-variable\": \"...\"\n    }\n```\n\n### CLI\n\nYou may want to execute your recipes after installation.\nCook provides you this command to execute all available recipes:\n\n```bash\ncomposer cook\n```\n\nIt won't overwrite your configuration if it already exists. To overwrite everything, run:\n\n```bash\ncomposer cook --overwrite\n```\n\nAdditionally, you can uninstall a recipe with this command:\n\n```bash\ncomposer cook:uninstall \u003cpackage\u003e [--all]\n```\nUse either `\u003cpackage\u003e` for individual package uninstallation or `--all` for all packages. \n\n## License\n\n[MIT](LICENSE)\n\nCopyright (c) 2023, William Arin\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwilliarin%2Fcook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwilliarin%2Fcook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwilliarin%2Fcook/lists"}