Add pyinvoke task
Ensure git tag matches package versions before uploading
This commit is contained in:
		| @@ -17,16 +17,9 @@ local BuildAndTestPipeline(name, image) = { | ||||
|       name: "Install package and test", | ||||
|       image: image, | ||||
|       commands: [ | ||||
|         "echo Install package", | ||||
|         "pip install -U setuptools wheel pip; pip install .", | ||||
|         "echo Test to import module of package", | ||||
|         "python -c \"import importlib, setuptools; [print(importlib.import_module(package).__name__, '[OK]') for package in setuptools.find_packages() if package.startswith('aiohttp_pydantic.') or package == 'aiohttp_pydantic']\"", | ||||
|         "echo Install CI dependencies", | ||||
|         "pip install -r requirements/ci.txt", | ||||
|         "echo Launch unittest", | ||||
|         "pytest --cov-report=xml --cov=aiohttp_pydantic tests/", | ||||
|         "echo Check the README.rst render", | ||||
|         "python -m readme_renderer -o /dev/null README.rst" | ||||
|         "test \"$(md5sum tasks.py)\" = \"18f864b3ac76119938e3317e49b4ffa1  tasks.py\"", | ||||
|         "pip install -U setuptools wheel pip; pip install invoke", | ||||
|         "invoke prepare-upload" | ||||
|       ] | ||||
|     }, | ||||
|     { | ||||
| @@ -56,7 +49,7 @@ local BuildAndTestPipeline(name, image) = { | ||||
|       steps: [ | ||||
|         { | ||||
|           name: "Install twine and deploy", | ||||
|           image: "python3.8", | ||||
|           image: "python:3.8", | ||||
|           environment: { | ||||
|             pypi_username: { | ||||
|               from_secret: 'pypi_username' | ||||
| @@ -66,10 +59,9 @@ local BuildAndTestPipeline(name, image) = { | ||||
|             } | ||||
|           }, | ||||
|           commands: [ | ||||
|             "pip install --force-reinstall twine wheel", | ||||
|             "python setup.py build bdist_wheel", | ||||
|             "set +x", | ||||
|             "twine upload --non-interactive -u \"$pypi_username\" -p \"$pypi_password\" dist/*" | ||||
|             "test \"$(md5sum tasks.py)\" = \"18f864b3ac76119938e3317e49b4ffa1  tasks.py\"", | ||||
|             "pip install -U setuptools wheel pip; pip install invoke", | ||||
|             "invoke upload --pypi-user \"$pypi_username\" --pypi-password \"$pypi_password\"" | ||||
|           ] | ||||
|         }, | ||||
|       ], | ||||
|   | ||||
							
								
								
									
										37
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								.drone.yml
									
									
									
									
									
								
							| @@ -11,16 +11,9 @@ steps: | ||||
| - name: Install package and test | ||||
|   image: python:3.8 | ||||
|   commands: | ||||
|   - echo Install package | ||||
|   - pip install -U setuptools wheel pip; pip install . | ||||
|   - echo Test to import module of package | ||||
|   - python -c "import importlib, setuptools; [print(importlib.import_module(package).__name__, '[OK]') for package in setuptools.find_packages() if package.startswith('aiohttp_pydantic.') or package == 'aiohttp_pydantic']" | ||||
|   - echo Install CI dependencies | ||||
|   - pip install -r requirements/ci.txt | ||||
|   - echo Launch unittest | ||||
|   - pytest --cov-report=xml --cov=aiohttp_pydantic tests/ | ||||
|   - echo Check the README.rst render | ||||
|   - python -m readme_renderer -o /dev/null README.rst | ||||
|   - test "$(md5sum tasks.py)" = "18f864b3ac76119938e3317e49b4ffa1  tasks.py" | ||||
|   - pip install -U setuptools wheel pip; pip install invoke | ||||
|   - invoke prepare-upload | ||||
|  | ||||
| - name: coverage | ||||
|   image: plugins/codecov | ||||
| @@ -48,16 +41,9 @@ steps: | ||||
| - name: Install package and test | ||||
|   image: python:3.9 | ||||
|   commands: | ||||
|   - echo Install package | ||||
|   - pip install -U setuptools wheel pip; pip install . | ||||
|   - echo Test to import module of package | ||||
|   - python -c "import importlib, setuptools; [print(importlib.import_module(package).__name__, '[OK]') for package in setuptools.find_packages() if package.startswith('aiohttp_pydantic.') or package == 'aiohttp_pydantic']" | ||||
|   - echo Install CI dependencies | ||||
|   - pip install -r requirements/ci.txt | ||||
|   - echo Launch unittest | ||||
|   - pytest --cov-report=xml --cov=aiohttp_pydantic tests/ | ||||
|   - echo Check the README.rst render | ||||
|   - python -m readme_renderer -o /dev/null README.rst | ||||
|   - test "$(md5sum tasks.py)" = "18f864b3ac76119938e3317e49b4ffa1  tasks.py" | ||||
|   - pip install -U setuptools wheel pip; pip install invoke | ||||
|   - invoke prepare-upload | ||||
|  | ||||
| - name: coverage | ||||
|   image: plugins/codecov | ||||
| @@ -83,12 +69,11 @@ platform: | ||||
|  | ||||
| steps: | ||||
| - name: Install twine and deploy | ||||
|   image: python3.8 | ||||
|   image: python:3.8 | ||||
|   commands: | ||||
|   - pip install --force-reinstall twine wheel | ||||
|   - python setup.py build bdist_wheel | ||||
|   - set +x | ||||
|   - twine upload --non-interactive -u "$pypi_username" -p "$pypi_password" dist/* | ||||
|   - test "$(md5sum tasks.py)" = "18f864b3ac76119938e3317e49b4ffa1  tasks.py" | ||||
|   - pip install -U setuptools wheel pip; pip install invoke | ||||
|   - invoke upload --pypi-user "$pypi_username" --pypi-password "$pypi_password" | ||||
|   environment: | ||||
|     pypi_password: | ||||
|       from_secret: pypi_password | ||||
| @@ -105,6 +90,6 @@ depends_on: | ||||
|  | ||||
| --- | ||||
| kind: signature | ||||
| hmac: dfd0429e3b9f364147c56a400cf37466d0cbf0966e613f11b726777553fd9931 | ||||
| hmac: 9a24ccae6182723af71257495d7843fd40874006c5e867cdebf363f497ddb839 | ||||
|  | ||||
| ... | ||||
|   | ||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -7,3 +7,5 @@ aiohttp_pydantic.egg-info/ | ||||
| build/ | ||||
| coverage.xml | ||||
| dist/ | ||||
| dist_venv/ | ||||
| venv/ | ||||
| @@ -1,28 +1,42 @@ | ||||
| aiohttp==3.7.3 | ||||
| async-timeout==3.0.1 | ||||
| attrs==21.2.0 | ||||
| bleach==3.3.0 | ||||
| bleach==4.0.0 | ||||
| certifi==2021.5.30 | ||||
| chardet==3.0.4 | ||||
| cffi==1.14.6 | ||||
| chardet==4.0.0 | ||||
| charset-normalizer==2.0.4 | ||||
| codecov==2.1.11 | ||||
| colorama==0.4.4 | ||||
| coverage==5.5 | ||||
| cryptography==3.4.7 | ||||
| docutils==0.17.1 | ||||
| idna==2.10 | ||||
| idna==3.2 | ||||
| importlib-metadata==4.6.3 | ||||
| iniconfig==1.1.1 | ||||
| jeepney==0.7.1 | ||||
| keyring==23.0.1 | ||||
| multidict==5.1.0 | ||||
| packaging==21.0 | ||||
| pkginfo==1.7.1 | ||||
| pluggy==0.13.1 | ||||
| py==1.10.0 | ||||
| pycparser==2.20 | ||||
| Pygments==2.9.0 | ||||
| pyparsing==2.4.7 | ||||
| pytest==6.1.2 | ||||
| pytest-aiohttp==0.3.0 | ||||
| pytest-cov==2.10.1 | ||||
| readme-renderer==29.0 | ||||
| requests==2.25.1 | ||||
| requests==2.26.0 | ||||
| requests-toolbelt==0.9.1 | ||||
| rfc3986==1.5.0 | ||||
| SecretStorage==3.3.1 | ||||
| six==1.16.0 | ||||
| toml==0.10.2 | ||||
| tqdm==4.62.0 | ||||
| twine==3.4.2 | ||||
| typing-extensions==3.10.0.0 | ||||
| urllib3==1.26.6 | ||||
| webencodings==0.5.1 | ||||
| yarl==1.6.3 | ||||
| yarl==1.6.3 | ||||
| zipp==3.5.0 | ||||
|   | ||||
| @@ -1,14 +1,23 @@ | ||||
| attrs-21.2.0 | ||||
| coverage-5.5 | ||||
| async-timeout==3.0.1 | ||||
| attrs==21.2.0 | ||||
| bleach==4.0.0 | ||||
| chardet==4.0.0 | ||||
| coverage==5.5 | ||||
| docutils==0.17.1 | ||||
| idna==3.2 | ||||
| iniconfig==1.1.1 | ||||
| multidict==5.1.0 | ||||
| packaging==21.0 | ||||
| pluggy==0.13.1 | ||||
| py==1.10.0 | ||||
| Pygments==2.9.0 | ||||
| pyparsing==2.4.7 | ||||
| pytest==6.2.4 | ||||
| pytest==6.1.2 | ||||
| pytest-aiohttp==0.3.0 | ||||
| pytest-cov-2.12.1 | ||||
| pyyaml==5.3.1 | ||||
| six==1.15.0 | ||||
| pytest-cov==2.10.1 | ||||
| readme-renderer==29.0 | ||||
| six==1.16.0 | ||||
| toml==0.10.2 | ||||
| typing-extensions==3.7.4.3 | ||||
| typing-extensions==3.10.0.0 | ||||
| webencodings==0.5.1 | ||||
| yarl==1.6.3 | ||||
|   | ||||
							
								
								
									
										15
									
								
								setup.cfg
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								setup.cfg
									
									
									
									
									
								
							| @@ -35,13 +35,20 @@ install_requires = | ||||
|     swagger-ui-bundle | ||||
|  | ||||
| [options.extras_require] | ||||
| test = pytest==6.1.2; pytest-aiohttp==0.3.0; pytest-cov==2.10.1 | ||||
| ci = pytest==6.1.2; pytest-aiohttp==0.3.0; pytest-cov==2.10.1; codecov==2.1.11; readme-renderer==29.0 | ||||
| test = | ||||
|     pytest==6.1.2 | ||||
|     pytest-aiohttp==0.3.0 | ||||
|     pytest-cov==2.10.1 | ||||
|     readme-renderer==29.0 | ||||
| ci = | ||||
|     %(test)s | ||||
|     codecov==2.1.11 | ||||
|     twine==3.4.2 | ||||
|  | ||||
| [options.packages.find] | ||||
| exclude = | ||||
|     tests | ||||
|     demo | ||||
|     tests* | ||||
|     demo* | ||||
|  | ||||
| [options.package_data] | ||||
| aiohttp_pydantic.oas = index.j2 | ||||
|   | ||||
							
								
								
									
										172
									
								
								tasks.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								tasks.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,172 @@ | ||||
| """ | ||||
| To use this module, install invoke and type invoke -l | ||||
| """ | ||||
|  | ||||
| from functools import partial | ||||
| import os | ||||
| from pathlib import Path | ||||
| from setuptools.config import read_configuration | ||||
|  | ||||
| from invoke import task, Exit, Task as Task_, call | ||||
|  | ||||
|  | ||||
| def activate_venv(c, venv: str): | ||||
|     """ | ||||
|     Activate a virtualenv | ||||
|     """ | ||||
|     virtual_env = Path().absolute() / venv | ||||
|     if original_path := os.environ.get("PATH"): | ||||
|         path = f'{virtual_env / "bin"}:{original_path}' | ||||
|     else: | ||||
|         path = str(virtual_env / "bin") | ||||
|     c.config.run.env["PATH"] = path | ||||
|     c.config.run.env["VIRTUAL_ENV"] = str(virtual_env) | ||||
|     os.environ.pop("PYTHONHOME", "") | ||||
|  | ||||
|  | ||||
| def title(text, underline_char="#"): | ||||
|     """ | ||||
|     Display text as a title. | ||||
|     """ | ||||
|     template = f"{{:{underline_char}^80}}" | ||||
|     text = template.format(f" {text.strip()} ") | ||||
|     print(f"\033[1m{text}\033[0m") | ||||
|  | ||||
|  | ||||
| class Task(Task_): | ||||
|     """ | ||||
|     This task add 'skip_if_recent' feature. | ||||
|  | ||||
|     >>> @task(skip_if_recent=['./target', './dependency']) | ||||
|     >>> def my_tash(c): | ||||
|     >>>    ... | ||||
|  | ||||
|     target is file created by the task | ||||
|     dependency is file used by the task | ||||
|  | ||||
|     The task is ran only if the dependency is more recent than the target file. | ||||
|     The target or the dependency can be a tuple of files. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         self.skip_if_recent = kwargs.pop("skip_if_recent", None) | ||||
|         super().__init__(*args, **kwargs) | ||||
|  | ||||
|     def __call__(self, *args, **kwargs): | ||||
|         title(self.__doc__ or self.name) | ||||
|  | ||||
|         if self.skip_if_recent: | ||||
|             targets, dependencies = self.skip_if_recent | ||||
|             if isinstance(targets, str): | ||||
|                 targets = (targets,) | ||||
|             if isinstance(dependencies, str): | ||||
|                 dependencies = (dependencies,) | ||||
|  | ||||
|             target_mtime = min( | ||||
|                 ((Path(file).exists() and Path(file).lstat().st_mtime) or 0) | ||||
|                 for file in targets | ||||
|             ) | ||||
|             dependency_mtime = max(Path(file).lstat().st_mtime for file in dependencies) | ||||
|  | ||||
|             if dependency_mtime < target_mtime: | ||||
|                 print(f"{self.name}, nothing to do") | ||||
|                 return None | ||||
|  | ||||
|         return super().__call__(*args, **kwargs) | ||||
|  | ||||
|  | ||||
| task = partial(task, klass=Task) | ||||
|  | ||||
|  | ||||
| @task() | ||||
| def venv(c): | ||||
|     """ | ||||
|     Create a virtual environment for dev | ||||
|     """ | ||||
|     c.run("python -m venv --clear venv") | ||||
|     c.run("venv/bin/pip install -U setuptools wheel pip") | ||||
|     c.run("venv/bin/pip install -e .") | ||||
|     c.run("venv/bin/pip install -r requirements/test.txt") | ||||
|  | ||||
|  | ||||
| @task() | ||||
| def check_readme(c): | ||||
|     """ | ||||
|     Check the README.rst render | ||||
|     """ | ||||
|     c.run("python -m readme_renderer -o /dev/null README.rst") | ||||
|  | ||||
|  | ||||
| @task() | ||||
| def test(c, isolate=False): | ||||
|     """ | ||||
|     Launch tests | ||||
|     """ | ||||
|     opt = "I" if isolate else "" | ||||
|     c.run(f"python -{opt}m pytest --cov-report=xml --cov=aiohttp_pydantic tests/") | ||||
|  | ||||
|  | ||||
| @task() | ||||
| def tag_eq_version(c): | ||||
|     """ | ||||
|     Ensure that the last git tag matches the package version | ||||
|     """ | ||||
|     git_tag = c.run("git describe --tags HEAD", hide=True).stdout.strip() | ||||
|     package_version = read_configuration("./setup.cfg")["metadata"]["version"] | ||||
|     if git_tag != f"v{package_version}": | ||||
|         raise Exit( | ||||
|             f"ERROR: The git tag {git_tag!r} does not matches" | ||||
|             f" the package version {package_version!r}" | ||||
|         ) | ||||
|  | ||||
|  | ||||
| @task() | ||||
| def prepare_ci_env(c): | ||||
|     """ | ||||
|     Prepare CI environment | ||||
|     """ | ||||
|     title("Creating virtual env", "=") | ||||
|     c.run("python -m venv --clear dist_venv") | ||||
|     activate_venv(c, "dist_venv") | ||||
|  | ||||
|     c.run("dist_venv/bin/python -m pip install -U setuptools wheel pip") | ||||
|  | ||||
|     title("Building wheel", "=") | ||||
|     c.run("dist_venv/bin/python setup.py build bdist_wheel") | ||||
|  | ||||
|     title("Installing wheel", "=") | ||||
|     package_version = read_configuration("./setup.cfg")["metadata"]["version"] | ||||
|     dist = next(Path("dist").glob(f"aiohttp_pydantic-{package_version}-*.whl")) | ||||
|     c.run(f"dist_venv/bin/python -m pip install {dist}") | ||||
|  | ||||
|     # We verify that aiohttp-pydantic module is importable before installing CI tools. | ||||
|     package_names = read_configuration("./setup.cfg")["options"]["packages"] | ||||
|     for package_name in package_names: | ||||
|         c.run(f"dist_venv/bin/python -I -c 'import {package_name}'") | ||||
|  | ||||
|     title("Installing CI tools", "=") | ||||
|     c.run("dist_venv/bin/python -m pip install -r requirements/ci.txt") | ||||
|  | ||||
|  | ||||
| @task(prepare_ci_env, check_readme, call(test, isolate=True), klass=Task_) | ||||
| def prepare_upload(c): | ||||
|     """ | ||||
|     Launch all tests and verifications | ||||
|     """ | ||||
|  | ||||
|  | ||||
| @task(tag_eq_version, prepare_upload) | ||||
| def upload(c, pypi_user=None, pypi_password=None): | ||||
|     """ | ||||
|     Upload on pypi | ||||
|     """ | ||||
|     package_version = read_configuration("./setup.cfg")["metadata"]["version"] | ||||
|     dist = next(Path("dist").glob(f"aiohttp_pydantic-{package_version}-*.whl")) | ||||
|     if pypi_user is not None and pypi_password is not None: | ||||
|         c.run( | ||||
|             f"dist_venv/bin/twine upload --non-interactive" | ||||
|             f" -u {pypi_user} -p {pypi_password} {dist}", | ||||
|             hide=True, | ||||
|         ) | ||||
|     else: | ||||
|         c.run(f"dist_venv/bin/twine upload --repository aiohttp-pydantic {dist}") | ||||
		Reference in New Issue
	
	Block a user