From bcf386fe673ca7347f1176e7e972b164582ecb73 Mon Sep 17 00:00:00 2001 From: Alberto Vara Date: Tue, 25 Feb 2020 19:35:35 +0100 Subject: [PATCH] Create project from scaffold (#90) * Added new command startproject * Updated docs * Update README.md --- README.md | 56 ++++++++++++++++++++++-- docs/command_line.md | 69 ++++++++++++++++++++++++++++++ docs/index.md | 7 +-- docs/quickstart.md | 37 ++++++++++++++++ mkdocs.yml | 9 +++- pyms/cmd/__init__.py | 2 +- pyms/cmd/main.py | 21 ++++++++- pyms/config/__init__.py | 4 +- pyms/flask/app/__init__.py | 4 +- pyms/flask/healthcheck/__init__.py | 2 +- pyms/logger/__init__.py | 2 +- pyms/utils/__init__.py | 2 +- tests/test_cmd.py | 11 ++++- 13 files changed, 206 insertions(+), 20 deletions(-) create mode 100644 docs/command_line.md diff --git a/README.md b/README.md index 087412f..4e8e707 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,20 @@ [![Gitter](https://img.shields.io/gitter/room/DAVFoundation/DAV-Contributors.svg)](https://gitter.im/python-microservices/pyms) -PyMS, Python MicroService, is a collections of libraries, best practices and recommended ways to build microservices with Python. +PyMS, Python MicroService, is a [Microservice chassis pattern](https://microservices.io/patterns/microservice-chassis.html) +like Spring Boot (Java) or Gizmo (Golang). PyMS is a collection of libraries, best practices and recommended ways to build +microservices with Python which handles cross-cutting concerns: + +- Externalized configuration +- Logging +- Health checks +- Metrics +- Distributed tracing + +PyMS is powered by [Flask](https://flask.palletsprojects.com/en/1.1.x/), [Connexion](https://github.com/zalando/connexion) +and [Opentracing](https://opentracing.io/). + +Get started with [Installation](installation.md) and then get an overview with the [Quickstart](quickstart.md). ## Documentation @@ -26,15 +39,15 @@ nothing to create professional projects. Most articles say: - (Sometimes) "Create a swagger specs" - "TA-DA! you have a microservice" -But... what happens with our configuration out of code like Kubernetes configmap? what happens with transactionality? +But... what happens with our configuration out of code like Kubernetes configmap? what happens with transactionality? If we have many microservices, what happens with traces?. There are many problems around Python and microservices and we can`t find anyone to give a solution. -We start creating these projects to try to solve all the problems we have found in our professional lives about +We start creating these projects to try to solve all the problems we have found in our professional lives about microservices architecture. -Nowadays, is not perfect and we have a looong roadmap, but we hope this library could help other felas and friends ;) +Nowadays, is not perfect and we have a looong roadmap, but we hope this library could help other fellas and friends ;) ## Installation @@ -97,6 +110,41 @@ override it. See [Documentation](https://py-ms.readthedocs.io/en/latest/) to learn more. +## Create a project from scaffold + +PyMS has a command line option to create a project template like [Microservices Scaffold](https://github.com/python-microservices/microservices-scaffold). +This command use [cookiecutter](https://github.com/cookiecutter/cookiecutter) to download and install this [template](https://github.com/python-microservices/microservices-template) + +**[Warning]** You must run first `pip install cookiecutter==1.7.0` + +```bash +pyms startproject +``` + +this output a lot of options step by step: + +```bash +project_repo_url [https://github.com/python-microservices/microservices-scaffold]: +project_name [Python Microservices Boilerplate]: prueba descarga +project_folder [prueba_descarga]: +project_short_description [Python Boilerplate contains all the boilerplate you need to create a Python package.]: +create_model_class [y]: +microservice_with_swagger_and_connexion [y]: +microservice_with_traces [y]: +microservice_with_metrics [y]: +application_root [/prueba_descarga]: +Select open_source_license: +1 - MIT license +2 - BSD license +3 - ISC license +4 - Apache Software License 2.0 +5 - GNU General Public License v3 +6 - Not open source +Choose from 1, 2, 3, 4, 5, 6 [1]: +``` + +When you finish to introduce the options, a project will be created in `project_slug` folder + ## How To Contrib We appreciate opening issues and pull requests to make PyMS even more stable & useful! See [This doc](CONTRIBUTING.md) diff --git a/docs/command_line.md b/docs/command_line.md new file mode 100644 index 0000000..933099f --- /dev/null +++ b/docs/command_line.md @@ -0,0 +1,69 @@ +# Commnand line + +PyMS has some command to make easy your developments: + +```bash +pyms -h +``` +Show you a list of options and help instructions to use this command like: + +```bash +usage: main.py [-h] [-v VERBOSE] {encrypt,create-key,startproject} ... + +Python Microservices + +optional arguments: + -h, --help show this help message and exit + -v VERBOSE, --verbose VERBOSE + Verbose + +Commands: + Available commands + + {encrypt,create-key,startproject} + encrypt Encrypt a string + create-key Generate a Key to encrypt strings in config + startproject Generate a project from https://github.com/python- + microservices/microservices-template + +``` + +## Start a project + +Command: +```bash +pyms startproject +``` + +This command create a project template like [Microservices Scaffold](https://github.com/python-microservices/microservices-scaffold). +This command use [cookiecutter](https://github.com/cookiecutter/cookiecutter) to download and install this [template](https://github.com/python-microservices/microservices-template) + +!!! warning + You must run first `pip install cookiecutter==1.7.0` + +## Create a key encrypt/decrypt file + +Command: +```bash +pyms create-key +``` + +Create a key file to encrypt strings in your configuration file. This key is created with [AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard). +You can run the next command in the terminal. See [Encrypt/Decrypt Configuration](encrypt_decryt_configuration.md) +for more information + +## Encrypt a string + +Command: +```bash +pyms encrypt [string] +``` + +Encrypt a string to use in your [configfile](configuration.md) + +```bash +pyms encrypt 'mysql+mysqlconnector://important_user:****@localhost/my_schema' +>> Encrypted OK: b'gAAAAABeSwBJv43hnGAWZOY50QjBX6uGLxUb3Q6fcUhMxKspIVIco8qwwZvxRg930uRlsd47isroXzkdRRnb4-x2dsQMp0dln8Pm2ySHH7TryLbQYEFbSh8RQK7zor-hX6gB-JY3uQD3IMtiVKx9AF95D6U4ydT-OA==' +``` + +See [Encrypt/Decrypt Configuration](encrypt_decryt_configuration.md) for more information diff --git a/docs/index.md b/docs/index.md index 5871108..3c21ae0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -40,10 +40,11 @@ Nowadays, is not perfect and we have a looong roadmap, but we hope this library * [Installation](installation.md) * [Quickstart](quickstart.md) * [Configuration](configuration.md) -* [Encrypt/Decrypt Configuration](encrypt_decryt_configuration.md) * [Services](services.md) -* [PyMS structure](structure.md) * [Microservice class](ms_class.md) -* [Examples](examples.md) * [Routing](routing.md) +* [Encrypt/Decrypt Configuration](encrypt_decryt_configuration.md) +* [Command line](command_line.md) +* [Examples](examples.md) +* [PyMS structure](structure.md) * [Structure of a microservice project](structure_project.md) diff --git a/docs/quickstart.md b/docs/quickstart.md index b4ad35d..7522088 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -45,6 +45,43 @@ if it was defined in the pyms configuration block, create a tracer, add health-c `ms` attribute and you can access to it with `current_app.ms`. This steps has their each functions and you can easy override it. 3. `create_app` return the flask instance and you can interact with it as a typical flask app +# Create a project from scaffold +PyMS have a command line option to create a project template like [Microservices Scaffold](https://github.com/python-microservices/microservices-scaffold). +This command use [cookiecutter](https://github.com/cookiecutter/cookiecutter) to download and install this [template](https://github.com/python-microservices/microservices-template) + +!!! warning + You must run first `pip install cookiecutter==1.7.0` + +## Installation + +```bash +pyms startproject +` +`` + +this output a lot of options step by step + +```bash +project_repo_url [https://github.com/python-microservices/microservices-scaffold]: +project_name [Python Microservices Boilerplate]: prueba descarga +project_folder [prueba_descarga]: +project_short_description [Python Boilerplate contains all the boilerplate you need to create a Python package.]: +create_model_class [y]: +microservice_with_swagger_and_connexion [y]: +microservice_with_traces [y]: +microservice_with_metrics [y]: +application_root [/prueba_descarga]: +Select open_source_license: +1 - MIT license +2 - BSD license +3 - ISC license +4 - Apache Software License 2.0 +5 - GNU General Public License v3 +6 - Not open source +Choose from 1, 2, 3, 4, 5, 6 [1]: +``` + +When you finish to introduce the options, a project will be created in `[project_slug]` folder See [Configuration](configuration.md), [Routing](routing.md) and [Examples](examples.md) to continue with this tutorial \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 817c18e..34cc5db 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -9,10 +9,15 @@ nav: - Quickstart: quickstart.md - Configuration: configuration.md - Services: services.md - - Structure: structure.md - Microservice class: ms_class.md - - Examples: examples.md - Routing: routing.md + - Encrypt/Decrypt Configuration: encrypt_decryt_configuration.md + - Command line: command_line.md + - Examples: examples.md + - PyMS structure: structure.md - Structure of a microservice project: structure_project.md + +markdown_extensions: + - admonition theme: name: 'material' \ No newline at end of file diff --git a/pyms/cmd/__init__.py b/pyms/cmd/__init__.py index 81c17cc..c334bcc 100755 --- a/pyms/cmd/__init__.py +++ b/pyms/cmd/__init__.py @@ -1,3 +1,3 @@ -from pyms.cmd.main import Command +from .main import Command __all__ = ['Command'] diff --git a/pyms/cmd/main.py b/pyms/cmd/main.py index 3c9f4a7..134894f 100755 --- a/pyms/cmd/main.py +++ b/pyms/cmd/main.py @@ -5,6 +5,7 @@ import argparse import sys +from pyms.utils import check_package_exists, import_from from pyms.utils.crypt import Crypt @@ -28,10 +29,18 @@ def __init__(self, *args, **kwargs): parser_encrypt = commands.add_parser('encrypt', help='Encrypt a string') parser_encrypt.add_argument("encrypt", default='', type=str, help='Encrypt a string') - parser_create_key = commands.add_parser('create-key', help='Encrypt a string') + parser_create_key = commands.add_parser('create-key', help='Generate a Key to encrypt strings in config') parser_create_key.add_argument("create_key", action='store_true', help='Generate a Key to encrypt strings in config') + parser_startproject = commands.add_parser('startproject', + help='Generate a project from https://github.com/python-microservices/microservices-template') + parser_startproject.add_argument("startproject", action='store_true', + help='Generate a project from https://github.com/python-microservices/microservices-template') + + parser_startproject.add_argument("-b", "--branch", + help='Select a branch from https://github.com/python-microservices/microservices-template') + parser.add_argument("-v", "--verbose", default="", type=str, help="Verbose ") args = parser.parse_args(arguments) @@ -43,6 +52,11 @@ def __init__(self, *args, **kwargs): self.encrypt = args.encrypt except AttributeError: self.encrypt = "" + try: + self.startproject = args.startproject + self.branch = args.branch + except AttributeError: + self.startproject = False self.verbose = len(args.verbose) if autorun: # pragma: no cover result = self.run() @@ -70,6 +84,11 @@ def run(self): if self.encrypt: encrypted = crypt.encrypt(self.encrypt) self.print_ok("Encrypted OK: {}".format(encrypted)) + if self.startproject: + check_package_exists("cookiecutter") + cookiecutter = import_from("cookiecutter.main", "cookiecutter") + cookiecutter('gh:python-microservices/cookiecutter-pyms', checkout=self.branch) + self.print_ok("Created project OK") return True @staticmethod diff --git a/pyms/config/__init__.py b/pyms/config/__init__.py index dca9b14..57f58ac 100644 --- a/pyms/config/__init__.py +++ b/pyms/config/__init__.py @@ -1,4 +1,4 @@ -from pyms.config.conf import get_conf -from pyms.config.confile import ConfFile +from .conf import get_conf +from .confile import ConfFile __all__ = ['get_conf', 'ConfFile'] diff --git a/pyms/flask/app/__init__.py b/pyms/flask/app/__init__.py index bb305b6..6516942 100644 --- a/pyms/flask/app/__init__.py +++ b/pyms/flask/app/__init__.py @@ -1,5 +1,5 @@ -from pyms.flask.app.create_app import Microservice -from pyms.flask.app.create_config import config +from .create_app import Microservice +from .create_config import config __all__ = ['Microservice', 'config'] diff --git a/pyms/flask/healthcheck/__init__.py b/pyms/flask/healthcheck/__init__.py index 09693a8..931a15e 100644 --- a/pyms/flask/healthcheck/__init__.py +++ b/pyms/flask/healthcheck/__init__.py @@ -1,4 +1,4 @@ -from pyms.flask.healthcheck.healthcheck import healthcheck_blueprint +from .healthcheck import healthcheck_blueprint __all__ = ['healthcheck_blueprint'] diff --git a/pyms/logger/__init__.py b/pyms/logger/__init__.py index 50223f3..621faa3 100644 --- a/pyms/logger/__init__.py +++ b/pyms/logger/__init__.py @@ -1,5 +1,5 @@ """Init file """ -from pyms.logger.logger import CustomJsonFormatter +from .logger import CustomJsonFormatter __all__ = ['CustomJsonFormatter', ] diff --git a/pyms/utils/__init__.py b/pyms/utils/__init__.py index e69ff58..1583c00 100644 --- a/pyms/utils/__init__.py +++ b/pyms/utils/__init__.py @@ -1,3 +1,3 @@ -from pyms.utils.utils import import_from, import_package, check_package_exists +from .utils import import_from, import_package, check_package_exists __all__ = ['import_from', 'import_package', 'check_package_exists'] diff --git a/tests/test_cmd.py b/tests/test_cmd.py index e9e7535..c31a55f 100644 --- a/tests/test_cmd.py +++ b/tests/test_cmd.py @@ -7,7 +7,7 @@ import pytest from pyms.cmd import Command -from pyms.exceptions import FileDoesNotExistException +from pyms.exceptions import FileDoesNotExistException, PackageNotExists from pyms.utils.crypt import Crypt @@ -47,4 +47,11 @@ def test_output_key(self, input): cmd.run() with pytest.raises(FileNotFoundError) as excinfo: crypt.delete_key() - assert ("[Errno 2] No such file or directory: 'key.key'") in str(excinfo.value) + assert "[Errno 2] No such file or directory: 'key.key'" in str(excinfo.value) + + def test_startproject_error(self): + arguments = ["startproject"] + cmd = Command(arguments=arguments, autorun=False) + with pytest.raises(PackageNotExists) as excinfo: + cmd.run() + assert "cookiecutter is not installed. try with pip install -U cookiecutter" in str(excinfo.value)