.. _cookiecutter: https://cookiecutter.readthedocs.io/en/latest/ .. _Jinja: http://jinja.pocoo.org/ .. _recipes: Recipes ======= Recipes are used to generate directories and files based on given user input. They are most used to speed up the set up of * New Python packages * New groundwork projects * New groundwork applications, plugins or patterns. * New own projects Besides folder structures and needed files, they can also be used to provide project/company specific values for some preconfiguration. These values may be: * Contact details of project leader or IT administrators. * Common links to general documentation like IT security rules or project handbook. * Source and integrations of corporate designs like css files or office templates. * Company wide used libraries and their ready-to-use integration * Configurations for external IT services, like continuous integration systems and bug trackers. * Whatever is needed... Recipes makes it possible to start relevant coding in less than 30 seconds after a new project was set up. Without missing any rules, designs, integrations, checks or whatever is required for the current project. .. note:: groundwork recipes are based on `cookiecutter`_ and supports every function of it. To get a deep understandig of what is possible with groundwork recipes, you should take a look into `cookiecutter's documentation `_ as well. Workflow -------- So, what happens if a recipe gets executed? Here is the workflow: 1. Run `groundwork recipe_build gw_package`. **gw_package** is provided by groundwork, but can be replaced by any other recipe. 2. The user gets asked on command line interface for some variable inputs. 3. The recipe gets executed and uses the user's input to create folders and files with input related names. 4. In most cases the input is also used to become part of some files. For instance a README file may contain the author's name after generation. List available recipes ---------------------- groundwork knows all available recipes of a groundwork application. And if this app has loaded the `Gw Recipe Builder` plugin, it provides the command `recipe_list` to get a list of all registered recipes. The groundwork application itself already has some usable recipes. Just execute the following to get a complete list:: groundwork recipe_list recipe gw_package ~~~~~~~~~~~~~~~~~ At least you can see a recipe called **gw_package**. This recipe creates a ready-to-use, groundwork based Python package. Including an example groundwork application and plugin, configured `sphinx project `_ for documentation, configured test cases with `pytest `_ and a test environment based on `tox `_, `travis `_ support, ... Building/Execute a recipe ------------------------- To build/execute a recipe simply open a command line interface and move to the directory, where the initial recipe folder shall be created. Then execute:: groundwork recipe_build RECIPE_NAME # For instance groundwork recipe_build gw_package Based on the recipe, you may get asked some questions, which mostly affects the naming of files and directories. After the last question is answered, groundwork executes the recipe and everything gets created. After this there should be a new folder inside your current working directory. Creating own recipes -------------------- Registration ~~~~~~~~~~~~ Own recipes must be registered by a plugin, which needs to give the following data during registration: * name of the recipe * absolute path of the recipe directory * description of the recipe * final words, which will be printed after an recipe was executed (optional) See the following code from the RecipeBuilder plugin to get an example:: class GwRecipesBuilder(GwCommandsPattern, GwRecipesPattern): def __init__(self, *args, **kwargs): self.name = self.__class__.__name__ super().__init__(*args, **kwargs) def activate(self): ... self.recipes.register("gw_package", os.path.abspath(os.path.join(os.path.dirname(__file__), "../recipes/gw_package")), description="Groundwork basic package. Includes places for " "apps, plugins, patterns and recipes.", final_words="Recipe Installation is done.\n\n" "For installation run: 'python setup.py develop' \n" "For documentation run: 'make html' inside doc folder " "(after installation!)\n\n" "For more information, please take a look into the README file " "to know how to go on.\n" "For help visit: https://groundwork.readthedocs.io\n\n" "Have fun with your groundwork package.") Structure ~~~~~~~~~ A recipe must follow the rules of `cookiecutter`_. Therefore it needs to have the following structure:: / |-- cookiecutter.json | |-- {{ cookiecutter.project_name}} | | | |-- other directories/files, which will be copied. | |-- other directories/files, which will NOT be copied .. note:: It is important to have a **cookiecutter.json** file, as well as a single root-directory, which name is surrounded by **{{ }}**. cookiecutter.json ~~~~~~~~~~~~~~~~~ The **cookiecutter.json** file is used as configuration file and must hold a json string, which defines all needed parameters for the recipe setup. All these parameters can be used and access in directory / file names as well as in file content. Structure ````````` The following example for a **cookiecutter.json** file comes from the RecipeBuilder plugin:: { "full_name": "My Name", "github_user" : "{{cookiecutter.full_name.lower().replace(' ', '_') }}", "email": "{{cookiecutter.github_user}}@provider.com", "project_name": "My Package", "project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_') }}", "github_project_name": "{{cookiecutter.project_slug}}", "project_app": "{{cookiecutter.project_slug}}_app", "project_plugin": "{{cookiecutter.project_slug}}_plugin", "project_short_description": "Package for hosting groundwork apps and plugins like {{cookiecutter.project_app}} or {{cookiecutter.project_plugin}}.", "test_folder": "tests", "test_prefix": "test_", "version": "0.1.0", "license": ["MIT license", "BSD license", "ISC license", "Apache Software License 2.0", "GNU General Public License v3", "Not open source"] } Usage ````` The parameters from the configuration files are all accessible by using **{{cookiecutter.PARAMETER}}**, wherever you want to use this value: * Directory names * File names * File content * cookiecutter.json .. note:: As the parameters are also accessible in the **cookiecutter.json** file, you are free to manipulate an input and use it as default value for the next parameter. For instance: The project name can be used as python package name, by removing all whitespaces and make it lowercase. Example: "project_package": {{ cookiecutter.project_name.lower().replace(' ', '_') }}". Using Jinja ~~~~~~~~~~~ `Jinja`_ statements can be used to manipulate/modify inputs or make decisions out of them. For instance: Based on the chosen license, the content of a file called *LICENSE* could be changed by:: {% if cookiecutter.license == MIT %} Using MTI license {% else if cookiecutter.license == BSD %} Using BSD license {% else %} Using a private license {% endif %}