ci: migrate from setuptools to PEP517 hatchling to build

This commit is contained in:
Stefan Reimer 2022-06-28 13:15:45 +02:00
parent b32de905a4
commit 42d4a62679
9 changed files with 89 additions and 129 deletions

View File

@ -1,6 +1,6 @@
ARG RUNTIME_VERSION="3.8" ARG RUNTIME_VERSION="3.9"
ARG DISTRO_VERSION="3.15" ARG DISTRO_VERSION="3.16"
ARG PULUMI_VERSION="3.35.0" ARG PULUMI_VERSION="3.35.1"
FROM python:${RUNTIME_VERSION}-alpine${DISTRO_VERSION} AS builder FROM python:${RUNTIME_VERSION}-alpine${DISTRO_VERSION} AS builder
ARG PULUMI_VERSION ARG PULUMI_VERSION

View File

@ -14,10 +14,7 @@ endif
.PHONY: pytest build test_upload upload all dev_setup pybuild .PHONY: pytest build test_upload upload all dev_setup pybuild
all: pybuild pytest all: pytest pybuild
dev_setup:
pip install -U -r dev-requirements.txt --user
pytest: pytest:
flake8 cloudbender tests flake8 cloudbender tests
@ -27,7 +24,7 @@ clean:
rm -rf .cache build .coverage .eggs cloudbender.egg-info .pytest_cache dist rm -rf .cache build .coverage .eggs cloudbender.egg-info .pytest_cache dist
pybuild: pybuild:
python setup.py bdist_wheel --universal hatchling build
test_upload: $(PACKAGE_FILE) test_upload: $(PACKAGE_FILE)
twine upload --repository-url https://test.pypi.org/legacy/ dist/cloudbender-*.whl twine upload --repository-url https://test.pypi.org/legacy/ dist/cloudbender-*.whl

View File

@ -7,18 +7,15 @@ import yaml
import copy import copy
import subprocess import subprocess
import sys import sys
import zlib
import jinja2 import jinja2
import python_minifier
import markupsafe import markupsafe
from jinja2.filters import make_attrgetter from jinja2.filters import make_attrgetter
from jinja2.runtime import Undefined from jinja2.runtime import Undefined
import pyminifier.token_utils
import pyminifier.minification
import pyminifier.compression
import pyminifier.obfuscate
import types
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -129,40 +126,41 @@ def sub(value="", pattern="", replace="", ignorecase=False):
return re.sub(pattern, replace, value, flags=flags) return re.sub(pattern, replace, value, flags=flags)
def pyminify(source, obfuscate=False, minify=True): def pyminify(source):
# pyminifier options minified = python_minifier.awslambda(source, filename=None, entrypoint=None)
options = types.SimpleNamespace( gz_source = gz_pack(minified)
tabs=False,
replacement_length=1,
use_nonlatin=0,
obfuscate=0,
obf_variables=1,
obf_classes=0,
obf_functions=0,
obf_import_methods=0,
obf_builtins=0,
)
tokens = pyminifier.token_utils.listified_tokenizer(source)
if minify:
source = pyminifier.minification.minify(tokens, options)
tokens = pyminifier.token_utils.listified_tokenizer(source)
if obfuscate:
name_generator = pyminifier.obfuscate.obfuscation_machine(use_unicode=False)
pyminifier.obfuscate.obfuscate(
"__main__", tokens, options, name_generator=name_generator
)
# source = pyminifier.obfuscate.apply_obfuscation(source)
source = pyminifier.token_utils.untokenize(tokens)
# logger.info(source)
minified_source = pyminifier.compression.gz_pack(source)
logger.info( logger.info(
"Compressed python code from {} to {}".format(len(source), len(minified_source)) "Compressed python code from {} to {}".format(len(source), len(gz_source))
) )
return minified_source return gz_source
# From pyminifier
def gz_pack(source):
"""
Returns 'source' as a gzip-compressed, self-extracting python script.
.. note::
This method uses up more space than the zip_pack method but it has the
advantage in that the resulting .py file can still be imported into a
python program.
"""
out = ""
# Preserve shebangs (don't care about encodings for this)
first_line = source.split("\n")[0]
if re.compile('^#!.*$').match(first_line):
if first_line.rstrip().endswith("python"):
first_line = first_line.rstrip()
first_line += "3"
out = first_line + "\n"
compressed_source = zlib.compress(source.encode("utf-8"))
out += "import zlib, base64\n"
out += "exec(zlib.decompress(base64.b64decode('"
out += base64.b64encode(compressed_source).decode("utf-8")
out += "')))\n"
return out
def inline_yaml(block): def inline_yaml(block):

View File

@ -7,7 +7,7 @@ import time
import pathlib import pathlib
import pprint import pprint
import pulumi import pulumi
import pkg_resources import importlib.resources as pkg_resources
from datetime import datetime, timedelta from datetime import datetime, timedelta
from dateutil.tz import tzutc from dateutil.tz import tzutc
@ -518,10 +518,6 @@ class Stack(object):
if self.outputs: if self.outputs:
if self.store_outputs: if self.store_outputs:
try:
filename = self.cfn_data["Metadata"]["CustomOutputs"]["Name"]
my_template = self.cfn_data["Metadata"]["CustomOutputs"]["Template"]
except (TypeError, KeyError):
filename = self.stackname + ".yaml" filename = self.stackname + ".yaml"
my_template = pkg_resources.read_text(templates, "outputs.yaml") my_template = pkg_resources.read_text(templates, "outputs.yaml")

View File

@ -1,8 +0,0 @@
boto3
Jinja2
click
pyminifier
cfn-lint>=0.34
pulumi
pulumi-aws
pulumi-aws-native

45
pyproject.toml Normal file
View File

@ -0,0 +1,45 @@
[build-system]
requires = ["hatchling", "hatch-vcs"]
build-backend = "hatchling.build"
[project]
name = "cloudbender"
dynamic = ["version"]
authors = [
{ name="Stefan Reimer", email="stefan@zero-downtime.net" },
]
description = "Toolset to render and manage AWS Cloudformation"
readme = "README.md"
license = { file="LICENSE.md" }
requires-python = ">=3.7"
dependencies = [
"boto3",
"mock",
"Jinja2>=3.0.0",
"click",
"cfn-lint>=0.34",
"python-minifier",
"pulumi>=3.35.0",
"pulumi-aws>5.0.0",
"pulumi-aws-native",
"pulumi-policy",
]
classifiers = [
"Development Status :: 4 - Beta",
"Environment :: Console",
"Operating System :: POSIX",
"Programming Language :: Python",
"License :: OSI Approved :: GNU Affero General Public License v3",
]
[project.urls]
"Homepage" = "https://git.zero-downtime.net/ZeroDownTime/CloudBender"
[project.scripts]
cloudbender = "cloudbender.cli:cli"
[tool.hatch.version]
source = "vcs"
[tool.isort]
profile = "black"

View File

@ -2,13 +2,12 @@ boto3
mock mock
Jinja2>=3.0.0 Jinja2>=3.0.0
click click
pyminifier python-minifier
cfn-lint>=0.34 cfn-lint>=0.34
pulumi>=3.35.0 pulumi>=3.35.0
pulumi-aws>5.0.0 pulumi-aws>5.0.0
pulumi-aws-native pulumi-aws-native
pulumi-policy pulumi-policy
# apprise
# flake8 # flake8
# pytest # pytest

View File

@ -1,5 +0,0 @@
[metadata]
description_file = README.md
[bdist_wheel]
universal=1

View File

@ -1,62 +0,0 @@
#!/usr/bin/env python
import io
import os
import re
from setuptools import setup
from setuptools import find_packages
from setuptools.command.test import test as TestCommand
class PyTest(TestCommand):
"""TestCommand subclass to use pytest with setup.py test."""
def finalize_options(self):
"""Find our package name and test options to fill out test_args."""
TestCommand.finalize_options(self)
self.test_args = ['-rx', '--cov', 'cloudbender',
'--cov-report', 'term-missing']
self.test_suite = True
def run_tests(self):
"""Taken from http://pytest.org/latest/goodpractises.html."""
# have to import here, outside the eggs aren't loaded
import pytest
errno = pytest.main(self.test_args)
raise SystemExit(errno)
if os.path.isfile("README.md"):
with io.open("README.md", encoding="utf-8") as opendescr:
long_description = opendescr.read()
else:
long_description = __doc__
setup(
name='cloudbender',
setuptools_git_versioning={
"enabled": True,
"dev_template": "{tag}-{ccount}",
},
setup_requires=["setuptools-git-versioning"],
description='Toolset to render and manage AWS Cloudformation',
python_requires='>=3.8',
long_description=long_description,
long_description_content_type="text/markdown",
author='Stefan Reimer',
author_email='stefan@zero-downtime.net',
url='https://git.zero-downtime.net/ZeroDownTime/CloudBender',
packages=find_packages(),
package_data={ 'cloudbender': ['templates/*.md', 'templates/*.yaml'], },
include_package_data=True,
entry_points={'console_scripts': [ "cloudbender = cloudbender.cli:cli" ]},
install_requires=['boto3', 'Jinja2>=3.0.0', 'click', 'cfn-lint>=0.34', 'pyminifier', 'pulumi', 'pulumi-aws'], #'apprise'
tests_require=["pytest-cov", "moto", "mock", 'pytest'],
cmdclass={"test": PyTest},
classifiers=[
"Development Status :: 4 - Beta",
"Environment :: Console",
"Operating System :: POSIX",
"Programming Language :: Python",
"License :: OSI Approved :: GNU Affero General Public License v3"
])