From 157d61417cd1ad1473698a1685941a828233f809 Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 09:49:44 +0000 Subject: [PATCH 01/40] migrate from setuptools to hatch with `hatch new --init` --- pyproject.toml | 132 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9b234df1..1ddb6af9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,134 @@ [build-system] -requires = ["setuptools>=42", "wheel"] # PEP 508 specifications. -build-backend = "setuptools.build_meta" +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "slo-generator" +dynamic = ["version"] +description = "SLO Generator" +readme = "README.md" +license = "Apache License 2.0" +requires-python = ">=3.7, <4" +authors = [ + { name = "Google Inc.", email = "olivier.cervello@gmail.com" }, +] +keywords = [ + "gcp", + "generator", + "sli", + "slo", +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Developers", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Topic :: Software Development :: Build Tools", + "Topic :: System :: Monitoring", +] +dependencies = [ + "certifi >=2023.07.22", + "click", + "python-dateutil", + "pyyaml", + "ruamel.yaml", + "setuptools >=65.5.1", +] + +[project.optional-dependencies] +api = [ + "cloudevents", + "Flask", + "functions-framework", + "gunicorn", + "requests", +] +bigquery = [ + "google-api-python-client", + "google-cloud-bigquery", +] +cloud_monitoring = [ + "google-api-python-client", + "google-cloud-monitoring", +] +cloud_service_monitoring = [ + "google-api-python-client", + "google-cloud-monitoring", +] +cloud_storage = [ + "google-api-python-client", + "google-cloud-storage", +] +cloudevent = [ + "cloudevents", +] +datadog = [ + "datadog", + "retrying==1.3.4", +] +dev = [ + "bandit", + "black >=24.3.0", + "flake8", + "GitPython >=3.1.35", + "isort", + "mock", + "mypy", + "pip >=23.3", + "pre-commit", + "pylint", + "pytest", + "pytest-cov", + "pytype", + "safety >=3", + "types-mock", + "types-protobuf", + "types-python-dateutil", + "types-PyYAML", + "types-requests", + "types-setuptools", + "wheel", +] +dynatrace = [ + "requests", +] +elasticsearch = [ + "elasticsearch", +] +opensearch = [ + "opensearch-py", +] +prometheus = [ + "prometheus-client", + "prometheus-http-client", +] +pubsub = [ + "google-api-python-client", + "google-cloud-pubsub", +] +splunk = [ + "splunk-sdk", +] + +[project.scripts] +slo-generator = "slo_generator.cli:main" + +[project.urls] +Homepage = "https://github.com/google/slo-generator" + +[tool.hatch.version] +path = "slo_generator/__init__.py" + +[tool.hatch.build.targets.sdist] +include = [ + "/slo_generator", +] [tool.mypy] # https://mypy.readthedocs.io/en/stable/config_file.html#using-a-pyproject-toml-file From 86a8b3bfc57e7b0b7c8fad7436cf2ed589664187 Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 09:50:40 +0000 Subject: [PATCH 02/40] add maintainers --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 1ddb6af9..1f0a9377 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,9 @@ requires-python = ">=3.7, <4" authors = [ { name = "Google Inc.", email = "olivier.cervello@gmail.com" }, ] +maintainers = [ + { name = "Laurent Vaylet", email = "laurent.vaylet@gmail.com" } +] keywords = [ "gcp", "generator", From 4c4c09c140db74c31cb25a3dc3dc06d11aeb1599 Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 09:53:42 +0000 Subject: [PATCH 03/40] set static project version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1f0a9377..76c705c6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "slo-generator" -dynamic = ["version"] +version = "2.6.0" description = "SLO Generator" readme = "README.md" license = "Apache License 2.0" From 69af1f6f8647cf1687d23c5b0e6b7bb071e746db Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 09:54:34 +0000 Subject: [PATCH 04/40] fix license codename --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 76c705c6..8aeaa861 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ name = "slo-generator" version = "2.6.0" description = "SLO Generator" readme = "README.md" -license = "Apache License 2.0" +license = "Apache-2.0" requires-python = ">=3.7, <4" authors = [ { name = "Google Inc.", email = "olivier.cervello@gmail.com" }, From e1b3a7311bd30def5960d28c348354fbfbc7b9c6 Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 09:56:25 +0000 Subject: [PATCH 05/40] update supported Python versions based on current Python release cycle --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8aeaa861..4f350254 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ version = "2.6.0" description = "SLO Generator" readme = "README.md" license = "Apache-2.0" -requires-python = ">=3.7, <4" +requires-python = ">=3.8, <4" authors = [ { name = "Google Inc.", email = "olivier.cervello@gmail.com" }, ] @@ -28,10 +28,10 @@ classifiers = [ "Intended Audience :: System Administrators", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Topic :: Software Development :: Build Tools", "Topic :: System :: Monitoring", ] From d7ad0fe8e36c8f3e91ea167b9aca67cbdbfe13bd Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 09:57:14 +0000 Subject: [PATCH 06/40] remove unused field, now that project version is set statically --- pyproject.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4f350254..61a43620 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -125,9 +125,6 @@ slo-generator = "slo_generator.cli:main" [project.urls] Homepage = "https://github.com/google/slo-generator" -[tool.hatch.version] -path = "slo_generator/__init__.py" - [tool.hatch.build.targets.sdist] include = [ "/slo_generator", From 5b4dc8b64cf86bb7c236545773b5dfea9620109f Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 10:17:53 +0000 Subject: [PATCH 07/40] remove unused dependency on `setuptools` --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 61a43620..777262c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,6 @@ dependencies = [ "python-dateutil", "pyyaml", "ruamel.yaml", - "setuptools >=65.5.1", ] [project.optional-dependencies] From 5d003491d57504d493fa1acf631248c958e49228 Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 12:30:21 +0000 Subject: [PATCH 08/40] add pre-commit hook for `bandit` --- .pre-commit-config.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index eedaf763..3be609d8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,3 +22,7 @@ repos: - id: ruff # Run the formatter. - id: ruff-format +- repo: https://github.com/PyCQA/bandit + rev: 1.7.8 + hooks: + - id: bandit From 9c9a143f82096dd30a9e9c4fc657a4e933212a05 Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 12:31:04 +0000 Subject: [PATCH 09/40] move package sources to src/ --- {slo_generator => src/slo_generator}/__init__.py | 0 {slo_generator => src/slo_generator}/api/__init__.py | 0 {slo_generator => src/slo_generator}/api/main.py | 0 {slo_generator => src/slo_generator}/backends/__init__.py | 0 .../slo_generator}/backends/cloud_monitoring.py | 0 .../slo_generator}/backends/cloud_monitoring_mql.py | 0 .../slo_generator}/backends/cloud_service_monitoring.py | 0 {slo_generator => src/slo_generator}/backends/datadog.py | 0 {slo_generator => src/slo_generator}/backends/dynatrace.py | 0 .../slo_generator}/backends/elasticsearch.py | 0 {slo_generator => src/slo_generator}/backends/open_search.py | 0 {slo_generator => src/slo_generator}/backends/prometheus.py | 0 {slo_generator => src/slo_generator}/backends/splunk.py | 0 {slo_generator => src/slo_generator}/cli.py | 4 ++-- {slo_generator => src/slo_generator}/compute.py | 0 {slo_generator => src/slo_generator}/constants.py | 0 {slo_generator => src/slo_generator}/exporters/__init__.py | 0 {slo_generator => src/slo_generator}/exporters/base.py | 0 {slo_generator => src/slo_generator}/exporters/bigquery.py | 0 .../slo_generator}/exporters/cloud_monitoring.py | 0 {slo_generator => src/slo_generator}/exporters/cloudevent.py | 0 {slo_generator => src/slo_generator}/exporters/datadog.py | 0 {slo_generator => src/slo_generator}/exporters/dynatrace.py | 0 {slo_generator => src/slo_generator}/exporters/prometheus.py | 0 .../slo_generator}/exporters/prometheus_self.py | 0 {slo_generator => src/slo_generator}/exporters/pubsub.py | 0 {slo_generator => src/slo_generator}/migrations/__init__.py | 0 {slo_generator => src/slo_generator}/migrations/migrator.py | 0 {slo_generator => src/slo_generator}/report.py | 0 {slo_generator => src/slo_generator}/utils.py | 0 30 files changed, 2 insertions(+), 2 deletions(-) rename {slo_generator => src/slo_generator}/__init__.py (100%) rename {slo_generator => src/slo_generator}/api/__init__.py (100%) rename {slo_generator => src/slo_generator}/api/main.py (100%) rename {slo_generator => src/slo_generator}/backends/__init__.py (100%) rename {slo_generator => src/slo_generator}/backends/cloud_monitoring.py (100%) rename {slo_generator => src/slo_generator}/backends/cloud_monitoring_mql.py (100%) rename {slo_generator => src/slo_generator}/backends/cloud_service_monitoring.py (100%) rename {slo_generator => src/slo_generator}/backends/datadog.py (100%) rename {slo_generator => src/slo_generator}/backends/dynatrace.py (100%) rename {slo_generator => src/slo_generator}/backends/elasticsearch.py (100%) rename {slo_generator => src/slo_generator}/backends/open_search.py (100%) rename {slo_generator => src/slo_generator}/backends/prometheus.py (100%) rename {slo_generator => src/slo_generator}/backends/splunk.py (100%) rename {slo_generator => src/slo_generator}/cli.py (98%) rename {slo_generator => src/slo_generator}/compute.py (100%) rename {slo_generator => src/slo_generator}/constants.py (100%) rename {slo_generator => src/slo_generator}/exporters/__init__.py (100%) rename {slo_generator => src/slo_generator}/exporters/base.py (100%) rename {slo_generator => src/slo_generator}/exporters/bigquery.py (100%) rename {slo_generator => src/slo_generator}/exporters/cloud_monitoring.py (100%) rename {slo_generator => src/slo_generator}/exporters/cloudevent.py (100%) rename {slo_generator => src/slo_generator}/exporters/datadog.py (100%) rename {slo_generator => src/slo_generator}/exporters/dynatrace.py (100%) rename {slo_generator => src/slo_generator}/exporters/prometheus.py (100%) rename {slo_generator => src/slo_generator}/exporters/prometheus_self.py (100%) rename {slo_generator => src/slo_generator}/exporters/pubsub.py (100%) rename {slo_generator => src/slo_generator}/migrations/__init__.py (100%) rename {slo_generator => src/slo_generator}/migrations/migrator.py (100%) rename {slo_generator => src/slo_generator}/report.py (100%) rename {slo_generator => src/slo_generator}/utils.py (100%) diff --git a/slo_generator/__init__.py b/src/slo_generator/__init__.py similarity index 100% rename from slo_generator/__init__.py rename to src/slo_generator/__init__.py diff --git a/slo_generator/api/__init__.py b/src/slo_generator/api/__init__.py similarity index 100% rename from slo_generator/api/__init__.py rename to src/slo_generator/api/__init__.py diff --git a/slo_generator/api/main.py b/src/slo_generator/api/main.py similarity index 100% rename from slo_generator/api/main.py rename to src/slo_generator/api/main.py diff --git a/slo_generator/backends/__init__.py b/src/slo_generator/backends/__init__.py similarity index 100% rename from slo_generator/backends/__init__.py rename to src/slo_generator/backends/__init__.py diff --git a/slo_generator/backends/cloud_monitoring.py b/src/slo_generator/backends/cloud_monitoring.py similarity index 100% rename from slo_generator/backends/cloud_monitoring.py rename to src/slo_generator/backends/cloud_monitoring.py diff --git a/slo_generator/backends/cloud_monitoring_mql.py b/src/slo_generator/backends/cloud_monitoring_mql.py similarity index 100% rename from slo_generator/backends/cloud_monitoring_mql.py rename to src/slo_generator/backends/cloud_monitoring_mql.py diff --git a/slo_generator/backends/cloud_service_monitoring.py b/src/slo_generator/backends/cloud_service_monitoring.py similarity index 100% rename from slo_generator/backends/cloud_service_monitoring.py rename to src/slo_generator/backends/cloud_service_monitoring.py diff --git a/slo_generator/backends/datadog.py b/src/slo_generator/backends/datadog.py similarity index 100% rename from slo_generator/backends/datadog.py rename to src/slo_generator/backends/datadog.py diff --git a/slo_generator/backends/dynatrace.py b/src/slo_generator/backends/dynatrace.py similarity index 100% rename from slo_generator/backends/dynatrace.py rename to src/slo_generator/backends/dynatrace.py diff --git a/slo_generator/backends/elasticsearch.py b/src/slo_generator/backends/elasticsearch.py similarity index 100% rename from slo_generator/backends/elasticsearch.py rename to src/slo_generator/backends/elasticsearch.py diff --git a/slo_generator/backends/open_search.py b/src/slo_generator/backends/open_search.py similarity index 100% rename from slo_generator/backends/open_search.py rename to src/slo_generator/backends/open_search.py diff --git a/slo_generator/backends/prometheus.py b/src/slo_generator/backends/prometheus.py similarity index 100% rename from slo_generator/backends/prometheus.py rename to src/slo_generator/backends/prometheus.py diff --git a/slo_generator/backends/splunk.py b/src/slo_generator/backends/splunk.py similarity index 100% rename from slo_generator/backends/splunk.py rename to src/slo_generator/backends/splunk.py diff --git a/slo_generator/cli.py b/src/slo_generator/cli.py similarity index 98% rename from slo_generator/cli.py rename to src/slo_generator/cli.py index aa678bad..29d9630b 100644 --- a/slo_generator/cli.py +++ b/src/slo_generator/cli.py @@ -23,7 +23,7 @@ from pathlib import Path import click -from pkg_resources import get_distribution +from importlib import metadata from slo_generator import utils from slo_generator.compute import compute as _compute @@ -47,7 +47,7 @@ def main(ctx, version): """CLI entrypoint.""" utils.setup_logging() if ctx.invoked_subcommand is None or version: - ver = get_distribution("slo-generator").version + ver = metadata.version("slo-generator") print(f"slo-generator v{ver}") sys.exit(0) diff --git a/slo_generator/compute.py b/src/slo_generator/compute.py similarity index 100% rename from slo_generator/compute.py rename to src/slo_generator/compute.py diff --git a/slo_generator/constants.py b/src/slo_generator/constants.py similarity index 100% rename from slo_generator/constants.py rename to src/slo_generator/constants.py diff --git a/slo_generator/exporters/__init__.py b/src/slo_generator/exporters/__init__.py similarity index 100% rename from slo_generator/exporters/__init__.py rename to src/slo_generator/exporters/__init__.py diff --git a/slo_generator/exporters/base.py b/src/slo_generator/exporters/base.py similarity index 100% rename from slo_generator/exporters/base.py rename to src/slo_generator/exporters/base.py diff --git a/slo_generator/exporters/bigquery.py b/src/slo_generator/exporters/bigquery.py similarity index 100% rename from slo_generator/exporters/bigquery.py rename to src/slo_generator/exporters/bigquery.py diff --git a/slo_generator/exporters/cloud_monitoring.py b/src/slo_generator/exporters/cloud_monitoring.py similarity index 100% rename from slo_generator/exporters/cloud_monitoring.py rename to src/slo_generator/exporters/cloud_monitoring.py diff --git a/slo_generator/exporters/cloudevent.py b/src/slo_generator/exporters/cloudevent.py similarity index 100% rename from slo_generator/exporters/cloudevent.py rename to src/slo_generator/exporters/cloudevent.py diff --git a/slo_generator/exporters/datadog.py b/src/slo_generator/exporters/datadog.py similarity index 100% rename from slo_generator/exporters/datadog.py rename to src/slo_generator/exporters/datadog.py diff --git a/slo_generator/exporters/dynatrace.py b/src/slo_generator/exporters/dynatrace.py similarity index 100% rename from slo_generator/exporters/dynatrace.py rename to src/slo_generator/exporters/dynatrace.py diff --git a/slo_generator/exporters/prometheus.py b/src/slo_generator/exporters/prometheus.py similarity index 100% rename from slo_generator/exporters/prometheus.py rename to src/slo_generator/exporters/prometheus.py diff --git a/slo_generator/exporters/prometheus_self.py b/src/slo_generator/exporters/prometheus_self.py similarity index 100% rename from slo_generator/exporters/prometheus_self.py rename to src/slo_generator/exporters/prometheus_self.py diff --git a/slo_generator/exporters/pubsub.py b/src/slo_generator/exporters/pubsub.py similarity index 100% rename from slo_generator/exporters/pubsub.py rename to src/slo_generator/exporters/pubsub.py diff --git a/slo_generator/migrations/__init__.py b/src/slo_generator/migrations/__init__.py similarity index 100% rename from slo_generator/migrations/__init__.py rename to src/slo_generator/migrations/__init__.py diff --git a/slo_generator/migrations/migrator.py b/src/slo_generator/migrations/migrator.py similarity index 100% rename from slo_generator/migrations/migrator.py rename to src/slo_generator/migrations/migrator.py diff --git a/slo_generator/report.py b/src/slo_generator/report.py similarity index 100% rename from slo_generator/report.py rename to src/slo_generator/report.py diff --git a/slo_generator/utils.py b/src/slo_generator/utils.py similarity index 100% rename from slo_generator/utils.py rename to src/slo_generator/utils.py From f956dcf616069c89c5b9c3a54fd049b07839335a Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 12:32:09 +0000 Subject: [PATCH 10/40] add comments on minimum package version requirements --- pyproject.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 777262c5..45261870 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ classifiers = [ "Topic :: System :: Monitoring", ] dependencies = [ - "certifi >=2023.07.22", + "certifi>=2023.07.22", # avoid CVE-2023-37920 (reported by `safety check`) "click", "python-dateutil", "pyyaml", @@ -76,9 +76,9 @@ datadog = [ ] dev = [ "bandit", - "black >=24.3.0", + "black >=24.3.0", # avoid CVE-2024-21503 (reported by `safety check`) "flake8", - "GitPython >=3.1.35", + "GitPython >=3.1.35", # avoid CVE-2023-41040, CVE-2023-40267 and CVE-2023-40590 (reported by `safety check`) "isort", "mock", "mypy", From 1226f74ee8c4956efe66d02d0fc9029ea972b50a Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 12:33:07 +0000 Subject: [PATCH 11/40] add useful project URLs --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 45261870..de89a90d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -123,6 +123,8 @@ slo-generator = "slo_generator.cli:main" [project.urls] Homepage = "https://github.com/google/slo-generator" +Issues = "https://github.com/google/slo-generator/issues" +Source = "https://github.com/google/slo-generator" [tool.hatch.build.targets.sdist] include = [ From 85b22ba86eecf953b907638edb058e81a9c0dca6 Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 12:35:26 +0000 Subject: [PATCH 12/40] configure build --- pyproject.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index de89a90d..38489f52 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -127,8 +127,10 @@ Issues = "https://github.com/google/slo-generator/issues" Source = "https://github.com/google/slo-generator" [tool.hatch.build.targets.sdist] -include = [ - "/slo_generator", +exclude = [ + "/.github", + "/docs", + "/tests", ] [tool.mypy] From dedd1e1af5894321573d05d5dba57825185f01d5 Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 12:37:54 +0000 Subject: [PATCH 13/40] configure hatch envs in `hatch.toml` --- hatch.toml | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 24 +----------------- 2 files changed, 70 insertions(+), 23 deletions(-) create mode 100644 hatch.toml diff --git a/hatch.toml b/hatch.toml new file mode 100644 index 00000000..9faa05fb --- /dev/null +++ b/hatch.toml @@ -0,0 +1,69 @@ +[envs.test] +dependencies = [ + "coverage[toml]>=6.5", + "mock", + "pytest", + "pytest-cov", +] +# Install all optional dependencies. +features = [ + "api", + "bigquery", + "cloud_monitoring", + "cloud_service_monitoring", + "cloud_storage", + "cloudevent", + "datadog", + "dynatrace", + "elasticsearch", + "opensearch", + "prometheus", + "pubsub", + "splunk", +] +[envs.test.scripts] +unit = "pytest {args:tests} -p no:warnings" +unit-cov = "coverage run -m pytest {args:tests} -p no:warnings" +[[envs.test.matrix]] +python = ["3.8", "3.9", "3.10", "3.11"] + +[envs.lint] +detached = true +dependencies = [ + "black>=24.3.0", # avoid CVE-2024-21503 (reported by `safety check`) + "mypy", + "ruff", +] +[envs.lint.scripts] +typing = "mypy --install-types --non-interactive {args:src/slo_generator}" +style = [ + "ruff check {args:.}", + "black --check --diff {args:.}", +] +fmt = [ + "black {args:.}", + "ruff check --fix {args:.}", + "style", +] +all = [ + "style", + "typing", +] +[[envs.lint.matrix]] +python = ["3.8", "3.9", "3.10", "3.11"] + +[envs.audit] +detached = true +dependencies = [ + "bandit", + "safety", +] +[envs.audit.scripts] +all = [ + "bandit -c pyproject.toml -r .", + # Ignore CVE-2018-20225 with Vulnerability ID 67599. + # We do not use the `--extra-index-url` option, and the behavior is intended anyway. + "safety check --ignore 67599", +] +[[envs.audit.matrix]] +python = ["3.8", "3.9", "3.10", "3.11"] diff --git a/pyproject.toml b/pyproject.toml index 38489f52..9e310993 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,29 +74,7 @@ datadog = [ "datadog", "retrying==1.3.4", ] -dev = [ - "bandit", - "black >=24.3.0", # avoid CVE-2024-21503 (reported by `safety check`) - "flake8", - "GitPython >=3.1.35", # avoid CVE-2023-41040, CVE-2023-40267 and CVE-2023-40590 (reported by `safety check`) - "isort", - "mock", - "mypy", - "pip >=23.3", - "pre-commit", - "pylint", - "pytest", - "pytest-cov", - "pytype", - "safety >=3", - "types-mock", - "types-protobuf", - "types-python-dateutil", - "types-PyYAML", - "types-requests", - "types-setuptools", - "wheel", -] + dynatrace = [ "requests", ] From d0c70166791eda3f599be07796754a105d572d86 Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 12:38:47 +0000 Subject: [PATCH 14/40] rename `test` GitHub Workflow to `ci` --- .github/workflows/ci.yml | 82 +++++++++++++--------------------------- 1 file changed, 26 insertions(+), 56 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1e7eeee..4bc6f067 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,70 +1,40 @@ -name: Continous Integration (CI) +name: Continuous Integration on: pull_request: jobs: - lint: - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] - architecture: ['x64'] - python-version: ['3.8', '3.9', '3.10', '3.11'] - runs-on: ${{ matrix.os }} + ci: + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v4 with: - python-version: ${{ matrix.python-version }} - architecture: ${{ matrix.architecture }} - - - name: Install dependencies - run: make install - - - name: Lint - run: make lint - - unit: - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] - architecture: ['x64'] - python-version: ['3.8', '3.9', '3.10', '3.11'] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + python-version: | + 3.8 + 3.9 + 3.10 + 3.11 + - name: Set up pip cache + if: runner.os == 'Linux' + uses: actions/cache@v3 with: - python-version: ${{ matrix.python-version }} - architecture: ${{ matrix.architecture }} - - - name: Install dependencies - run: make install - - - name: Run unit tests - run: make unit + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }} + restore-keys: ${{ runner.os }}-pip- + - name: Install Hatch + run: pipx install hatch + - name: Run unit tests with coverage + run: hatch run test:unit-cov env: - MIN_VALID_EVENTS: "10" + MIN_VALID_EVENTS: 10 GOOGLE_APPLICATION_CREDENTIALS: tests/unit/fixtures/fake_credentials.json - - - name: Run coverage report - run: make coverage - - audit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: "3.9" # same as Dockerfile - - - name: Install dependencies - run: make install - - - name: Audit for CVEs - run: make audit + - name: Lint + run: hatch run lint:all + - name: Audit + run: hatch run audit:all + - name: Build + run: hatch build docker: runs-on: ubuntu-latest From 4ffe7e343d6cd46465c3175e6afd913e60bab867 Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 12:47:37 +0000 Subject: [PATCH 15/40] list Hatch environments in CI --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4bc6f067..061eb6b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,6 +24,8 @@ jobs: restore-keys: ${{ runner.os }}-pip- - name: Install Hatch run: pipx install hatch + - name: List Hatch environments + run: hatch env show - name: Run unit tests with coverage run: hatch run test:unit-cov env: From ed3e596a7fe465065573eb5094351cdea01e74be Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 13:17:26 +0000 Subject: [PATCH 16/40] update GitHub Actions --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 061eb6b4..1741b45f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: | 3.8 @@ -17,7 +17,7 @@ jobs: 3.11 - name: Set up pip cache if: runner.os == 'Linux' - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }} From 672cbd0436b85b380f0554e85fb6d1c2b1e3444f Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 13:19:50 +0000 Subject: [PATCH 17/40] refactor Docker tests --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1741b45f..179b4c5c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,7 +42,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: docker-practice/actions-setup-docker@master - + - uses: docker/build-push-action@v5 - name: Build Docker image run: make docker_build From 82326114734e9876d0dd5f2ac5b2f567154944d7 Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 13:39:30 +0000 Subject: [PATCH 18/40] fix Docker image definition and CI workflow --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 179b4c5c..15c9a40e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,7 +41,6 @@ jobs: docker: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - uses: docker/build-push-action@v5 - name: Build Docker image run: make docker_build From 7b8c0054bc626f2a64f379ccfae30664882eea0e Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 14:15:45 +0000 Subject: [PATCH 19/40] replace Hatch matrices with GitHub matrices --- .github/workflows/ci.yml | 77 ++++++++++++++++++++++++++++++++++++---- hatch.toml | 6 ---- 2 files changed, 71 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 15c9a40e..ff589d89 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,17 +4,16 @@ on: pull_request: jobs: - ci: + unit: runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: - python-version: | - 3.8 - 3.9 - 3.10 - 3.11 + python-version: ${{ matrix.python-version }} - name: Set up pip cache if: runner.os == 'Linux' uses: actions/cache@v4 @@ -31,10 +30,76 @@ jobs: env: MIN_VALID_EVENTS: 10 GOOGLE_APPLICATION_CREDENTIALS: tests/unit/fixtures/fake_credentials.json + + lint: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10", "3.11"] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Set up pip cache + if: runner.os == 'Linux' + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }} + restore-keys: ${{ runner.os }}-pip- + - name: Install Hatch + run: pipx install hatch + - name: List Hatch environments + run: hatch env show - name: Lint run: hatch run lint:all + + audit: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10", "3.11"] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Set up pip cache + if: runner.os == 'Linux' + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }} + restore-keys: ${{ runner.os }}-pip- + - name: Install Hatch + run: pipx install hatch + - name: List Hatch environments + run: hatch env show - name: Audit run: hatch run audit:all + + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10", "3.11"] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Set up pip cache + if: runner.os == 'Linux' + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }} + restore-keys: ${{ runner.os }}-pip- + - name: Install Hatch + run: pipx install hatch + - name: List Hatch environments + run: hatch env show - name: Build run: hatch build diff --git a/hatch.toml b/hatch.toml index 9faa05fb..0f282d0a 100644 --- a/hatch.toml +++ b/hatch.toml @@ -24,8 +24,6 @@ features = [ [envs.test.scripts] unit = "pytest {args:tests} -p no:warnings" unit-cov = "coverage run -m pytest {args:tests} -p no:warnings" -[[envs.test.matrix]] -python = ["3.8", "3.9", "3.10", "3.11"] [envs.lint] detached = true @@ -49,8 +47,6 @@ all = [ "style", "typing", ] -[[envs.lint.matrix]] -python = ["3.8", "3.9", "3.10", "3.11"] [envs.audit] detached = true @@ -65,5 +61,3 @@ all = [ # We do not use the `--extra-index-url` option, and the behavior is intended anyway. "safety check --ignore 67599", ] -[[envs.audit.matrix]] -python = ["3.8", "3.9", "3.10", "3.11"] From 4decc491ee37ca625f553d5db4550f09b071194e Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 14:55:32 +0000 Subject: [PATCH 20/40] delete setuptools config files --- setup.cfg | 130 ------------------------------------------------------ setup.py | 28 ------------ 2 files changed, 158 deletions(-) delete mode 100644 setup.cfg delete mode 100644 setup.py diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index eb640317..00000000 --- a/setup.cfg +++ /dev/null @@ -1,130 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2020 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -[metadata] -name = slo-generator -version = 2.6.0 -author = Google Inc. -author_email = olivier.cervello@gmail.com -maintainer = Laurent VAYLET -maintainer_email = laurent.vaylet@gmail.com -url = https://github.com/google/slo-generator -description = SLO Generator -long_description = file: README.md -long_description_content_type = text/markdown -keywords = - slo - sli - generator - gcp -license = Apache License 2.0 -license_files = LICENSE -classifiers = - Development Status :: 5 - Production/Stable - Environment :: Console - Intended Audience :: Developers - Intended Audience :: System Administrators - License :: OSI Approved :: Apache Software License - Programming Language :: Python - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Topic :: Software Development :: Build Tools - Topic :: System :: Monitoring - -[options] -packages = find: -python_requires = >=3.7, <4 -install_requires = - pyyaml - ruamel.yaml - python-dateutil - click - setuptools >=65.5.1 # https://pyup.io/v/52495/f17 (reported by `safety check`) - certifi >=2023.07.22 # avoid CVE-2023-37920 (reported by `safety check`) - -[options.packages.find] -exclude = - contrib - docs - tests - -[options.extras_require] -api = - Flask - gunicorn - cloudevents - functions-framework - requests -prometheus = - prometheus-client - prometheus-http-client -datadog = - datadog - retrying==1.3.4 -dynatrace = - requests -bigquery = - google-api-python-client - google-cloud-bigquery -cloud_monitoring = - google-api-python-client - google-cloud-monitoring -cloud_service_monitoring = - google-api-python-client - google-cloud-monitoring -cloud_storage = - google-api-python-client - google-cloud-storage -elasticsearch = - elasticsearch -opensearch = - opensearch-py -splunk = - splunk-sdk -pubsub = - google-api-python-client - google-cloud-pubsub -cloudevent = - cloudevents -dev = - bandit - GitPython >=3.1.35 # avoid CVE-2023-41040, CVE-2023-40267 and CVE-2023-40590 (reported by `safety check`) - mock - mypy - pip >=23.3 # avoid known vulnerabilities in pip <23.3 (reported by `safety check`) - pre-commit - pytest - pytest-cov - pytype - ruff - safety - types-mock - types-protobuf - types-python-dateutil - types-PyYAML - types-requests - types-setuptools - wheel - -[options.entry_points] -console_scripts = - slo-generator = slo_generator.cli:main - -# Generated by synthtool. DO NOT EDIT! -[bdist_wheel] -universal = 1 diff --git a/setup.py b/setup.py deleted file mode 100644 index e042dc15..00000000 --- a/setup.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""A setuptools based setup module. - -See: -https://packaging.python.org/en/latest/distributing.html -https://github.com/pypa/sampleproject -""" - -import sys - -from setuptools import setup - -sys.dont_write_bytecode = True # avoid generating .pyc files - -if __name__ == "__main__": - setup() From bbd31e19d5d12a1c74224812b67516caed463da3 Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 14:55:58 +0000 Subject: [PATCH 21/40] ruff --- src/slo_generator/cli.py | 2 +- tests/unit/test_cli.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slo_generator/cli.py b/src/slo_generator/cli.py index 29d9630b..9f891dc6 100644 --- a/src/slo_generator/cli.py +++ b/src/slo_generator/cli.py @@ -20,10 +20,10 @@ import os import sys import time +from importlib import metadata from pathlib import Path import click -from importlib import metadata from slo_generator import utils from slo_generator.compute import compute as _compute diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index 8f73adb4..f2a163c1 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -31,7 +31,7 @@ class TestCLI(unittest.TestCase): def setUp(self): for key, value in CTX.items(): os.environ[key] = value - slo_config = f"{root}/samples/cloud_monitoring/slo_gae_app_availability.yaml" # noqa: E501 + slo_config = f"{root}/samples/cloud_monitoring/slo_gae_app_availability.yaml" config = f"{root}/samples/config.yaml" self.slo_config = slo_config self.slo_metadata_name = load_config(slo_config, ctx=CTX)["metadata"]["name"] From f30c30986a9dab350bcfb4f62063b2798adbcf6b Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 14:56:19 +0000 Subject: [PATCH 22/40] fix formatting of Hatch table --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ff589d89..e9360658 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: - name: Install Hatch run: pipx install hatch - name: List Hatch environments - run: hatch env show + run: hatch env show --ascii - name: Run unit tests with coverage run: hatch run test:unit-cov env: @@ -51,7 +51,7 @@ jobs: - name: Install Hatch run: pipx install hatch - name: List Hatch environments - run: hatch env show + run: hatch env show --ascii - name: Lint run: hatch run lint:all @@ -75,7 +75,7 @@ jobs: - name: Install Hatch run: pipx install hatch - name: List Hatch environments - run: hatch env show + run: hatch env show --ascii - name: Audit run: hatch run audit:all @@ -99,7 +99,7 @@ jobs: - name: Install Hatch run: pipx install hatch - name: List Hatch environments - run: hatch env show + run: hatch env show --ascii - name: Build run: hatch build From 1ce3b225c25aab17e60cc354583ec7b2848b5fcf Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Thu, 16 May 2024 07:27:17 +0000 Subject: [PATCH 23/40] add TODOs and FIXMEs --- .gitignore | 1 + Makefile | 9 +++------ hatch.toml | 7 ++++--- pyproject.toml | 3 +++ 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index cdbd6ec9..2b35e76c 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +# FIXME: Clean up unused entries and sort by categories __pycache__/ *.py[cod] *$py.class diff --git a/Makefile b/Makefile index 28b9cc9f..68cf76ac 100644 --- a/Makefile +++ b/Makefile @@ -55,16 +55,13 @@ deploy: clean install_twine build install_twine: $(PIP) install twine -develop: install - pre-commit install - +#TODO: Replace with Hatch. install: clean $(PIP) install -e ."[api, datadog, prometheus, elasticsearch, opensearch, splunk, pubsub, cloud_monitoring, bigquery, dev]" uninstall: clean - $(PIP) freeze --exclude-editable | xargs $(PIP) uninstall -y - -test: install unit lint audit +#TODO: How to handle pre-commit with Hatch environments? +#FIXME: Are all dependencies and features requested for all these targets? unit: clean pytest --cov=$(NAME) tests -p no:warnings diff --git a/hatch.toml b/hatch.toml index 0f282d0a..b681d4e3 100644 --- a/hatch.toml +++ b/hatch.toml @@ -22,8 +22,9 @@ features = [ "splunk", ] [envs.test.scripts] -unit = "pytest {args:tests} -p no:warnings" -unit-cov = "coverage run -m pytest {args:tests} -p no:warnings" +#TODO: Check what coverage does exactly, and if there is a more modern approach, for example with `py-cov`. +unit = "pytest --cov=coverage {args:tests} -p no:warnings" +cov = "coverage report --rcfile='.coveragerc'" [envs.lint] detached = true @@ -40,7 +41,7 @@ style = [ ] fmt = [ "black {args:.}", - "ruff check --fix {args:.}", + #FIXME Configure `mypy` from `pyproject.toml`, like `pytype`. "style", ] all = [ diff --git a/pyproject.toml b/pyproject.toml index 9e310993..803a7889 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,6 +4,9 @@ build-backend = "hatchling.build" [project] name = "slo-generator" +#TODO: Use dynamic version, stored in `src/slo_generator/__init__.py` as `__version__ = "2.6.0"`? +# Then use with `from . import __version__`. +# Is it compatible with release-please? version = "2.6.0" description = "SLO Generator" readme = "README.md" From 2ef026290809b1a9d84ade445e22eb5c6fbab828 Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Thu, 16 May 2024 07:27:37 +0000 Subject: [PATCH 24/40] ignore Ruff cache --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2b35e76c..9625388d 100644 --- a/.gitignore +++ b/.gitignore @@ -51,4 +51,4 @@ reports/ .pytest_cache/ .pytype/ .pip-wheel-metadata/ -.ruff_cache +.ruff_cache/ From 8174a9c9bf475af7513002550cc5098de7d2ba7c Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Thu, 16 May 2024 07:28:46 +0000 Subject: [PATCH 25/40] update Makefile for Hatch --- Makefile | 64 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 68cf76ac..f5bd6508 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -#!/usr/bin/make +#!/usr/bin/env make # WARN: gmake syntax ######################################################## # Makefile for $(NAME) @@ -12,25 +12,29 @@ # make audit -- run CVE scan separately # make integration -- run integration tests ######################################################## -# variable section + +# Variables NAME = slo_generator +HATCH = hatch PIP = pip3 PYTHON = python3 -TWINE = twine COVERAGE = coverage -SITELIB = $(shell $(PYTHON) -c "from distutils.sysconfig import get_python_lib; print get_python_lib()") -VERSION ?= $(shell grep "version = " setup.cfg | cut -d ' ' -f 3) +VERSION ?= $(shell grep "version = " pyproject.toml | cut -d ' ' -f 3) ######################################################## all: clean install test +############## + info: @echo "slo-generator version: ${VERSION}" +############## + clean: @echo "Cleaning up distutils stuff" rm -rf build @@ -46,43 +50,63 @@ clean: @echo "Cleaning up test reports" rm -rf report/* +############## + build: clean - $(PYTHON) setup.py sdist bdist_wheel + $(HATCH) build -deploy: clean install_twine build - $(TWINE) upload dist/* +deploy: build + $(HATCH) publish -install_twine: - $(PIP) install twine +############## #TODO: Replace with Hatch. install: clean $(PIP) install -e ."[api, datadog, prometheus, elasticsearch, opensearch, splunk, pubsub, cloud_monitoring, bigquery, dev]" uninstall: clean + $(HATCH) env prune + +############## + #TODO: How to handle pre-commit with Hatch environments? +develop: install + pre-commit install + +############## + +format: + $(HATCH) fmt + +############## + #FIXME: Are all dependencies and features requested for all these targets? +test: install unit lint audit + +############## unit: clean - pytest --cov=$(NAME) tests -p no:warnings + $(HATCH) run test:unit coverage: - $(COVERAGE) report --rcfile=".coveragerc" + $(HATCH) run test:cov -format: - ruff format +############## lint: ruff pytype mypy ruff: - ruff format --check - ruff check + $(HATCH) fmt pytype: - pytype + $(HATCH) run lint:pytype mypy: - mypy --show-error-codes $(NAME) + $(HATCH) run lint:mypy + +############## + +audit: bandit safety audit: bandit safety @@ -94,6 +118,8 @@ safety: # We do not use the `--extra-index-url` option, and the behavior is intended anyway. safety check --ignore 67599 +############## + integration: int_cm int_csm int_custom int_dd int_dt int_es int_prom int_sp int_os int_cm: @@ -123,6 +149,8 @@ int_sp: int_os: slo-generator compute -f samples/opensearch -c samples/config.yaml +############## + # Run API locally run_api: slo-generator api --target=run_compute --signature-type=http -c samples/config.yaml From c22038ae93ae41cf6ca685e1ee072cea1894ef5a Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Thu, 16 May 2024 07:29:25 +0000 Subject: [PATCH 26/40] configure `bandit` in `pyproject.toml` --- pyproject.toml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 803a7889..8900dfd9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -114,6 +114,24 @@ exclude = [ "/tests", ] +[tool.bandit] +exclude_dirs = [ + "tests", +] + +[tool.pylint] +ignore-patterns = [ + "test_.*?py", +] + +[tool.pylint.messages_control] +max-line-length = 88 +disable = [ + "logging-fstring-interpolation", + "import-error", + "possibly-used-before-assignment", +] + [tool.mypy] # https://mypy.readthedocs.io/en/stable/config_file.html#using-a-pyproject-toml-file ignore_missing_imports = true From 2d57ba039e083cfb08595b8fead772d799800bfd Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Thu, 16 May 2024 07:30:26 +0000 Subject: [PATCH 27/40] update `mypy` configuration --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 8900dfd9..c255f6be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -134,7 +134,8 @@ disable = [ [tool.mypy] # https://mypy.readthedocs.io/en/stable/config_file.html#using-a-pyproject-toml-file -ignore_missing_imports = true +# https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-library-stubs-or-py-typed-marker +disable_error_code = "import-untyped" [tool.pytype] inputs = ['slo_generator'] From 991140d243fefeec5d52f242fb4f71eee3d2598a Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Thu, 16 May 2024 07:30:46 +0000 Subject: [PATCH 28/40] configure Hatch environments --- hatch.toml | 50 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/hatch.toml b/hatch.toml index b681d4e3..a80ad3a9 100644 --- a/hatch.toml +++ b/hatch.toml @@ -1,4 +1,24 @@ +[envs.default] +python = "3.10" +# Install all optional dependencies. +features = [ + "api", + "bigquery", + "cloud_monitoring", + "cloud_service_monitoring", + "cloud_storage", + "cloudevent", + "datadog", + "dynatrace", + "elasticsearch", + "opensearch", + "prometheus", + "pubsub", + "splunk", +] + [envs.test] +python = "3.10" dependencies = [ "coverage[toml]>=6.5", "mock", @@ -27,22 +47,37 @@ unit = "pytest --cov=coverage {args:tests} -p no:warnings" cov = "coverage report --rcfile='.coveragerc'" [envs.lint] +python="3.10" detached = true dependencies = [ - "black>=24.3.0", # avoid CVE-2024-21503 (reported by `safety check`) "mypy", + "pytype", "ruff", ] +# Install all optional dependencies. +features = [ + "api", + "bigquery", + "cloud_monitoring", + "cloud_service_monitoring", + "cloud_storage", + "cloudevent", + "datadog", + "dynatrace", + "elasticsearch", + "opensearch", + "prometheus", + "pubsub", + "splunk", +] [envs.lint.scripts] -typing = "mypy --install-types --non-interactive {args:src/slo_generator}" style = [ - "ruff check {args:.}", - "black --check --diff {args:.}", + "ruff {args:.}", ] -fmt = [ - "black {args:.}", +typing = [ + "pytype", #FIXME Configure `mypy` from `pyproject.toml`, like `pytype`. - "style", + "mypy --install-types --show-error-codes --disable-error-code=import-untyped --non-interactive {args:src/slo_generator}", ] all = [ "style", @@ -50,6 +85,7 @@ all = [ ] [envs.audit] +python = "3.10" detached = true dependencies = [ "bandit", From 7346a9df97a63c55e2bd2fe89a1b083dbea6c42e Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Thu, 16 May 2024 07:31:17 +0000 Subject: [PATCH 29/40] update `pytype` configuration --- pyproject.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c255f6be..7776c37a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -138,7 +138,9 @@ disable = [ disable_error_code = "import-untyped" [tool.pytype] -inputs = ['slo_generator'] +inputs = [ + "src/slo_generator", +] [tool.ruff.lint] # https://docs.astral.sh/ruff/linter/#rule-selection From bf9cc8bbe17b761d69c4f09f9d7e3bddf29544a5 Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Thu, 16 May 2024 07:32:12 +0000 Subject: [PATCH 30/40] remove unneeded empty line --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7776c37a..3395bd8f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,7 +77,6 @@ datadog = [ "datadog", "retrying==1.3.4", ] - dynatrace = [ "requests", ] From 91be9e2d15e36ac641f0cba0aca80b5312bf0372 Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Thu, 16 May 2024 07:32:24 +0000 Subject: [PATCH 31/40] format with `ruff` --- src/slo_generator/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slo_generator/utils.py b/src/slo_generator/utils.py index b00dca5c..4beaa1e4 100644 --- a/src/slo_generator/utils.py +++ b/src/slo_generator/utils.py @@ -210,7 +210,7 @@ def get_human_time(timestamp: int, timezone: Optional[str] = None) -> str: str: Formatted human-readable date in ISO format. Example: - >>> get_human_time(1702660513.987654, timezone='Europe/Paris') + >>> get_human_time(1702660513.987654, timezone="Europe/Paris") >>> 2023-12-15T18:15:13.987654+01:00 which corresponds to the timestamp in ISO format """ From 7afb0e4437b878e7ea63d1c1a847eda105a4c1ff Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Thu, 16 May 2024 07:32:39 +0000 Subject: [PATCH 32/40] ignore type linting --- src/slo_generator/migrations/migrator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slo_generator/migrations/migrator.py b/src/slo_generator/migrations/migrator.py index 2ddae44f..9a17a376 100644 --- a/src/slo_generator/migrations/migrator.py +++ b/src/slo_generator/migrations/migrator.py @@ -30,7 +30,7 @@ from typing import Optional import click -from ruamel import yaml +from ruamel import yaml # type: ignore from slo_generator import utils from slo_generator.constants import ( From a337c0a2f52b775076ca44cc54afd645c6047daf Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Thu, 16 May 2024 13:31:39 +0000 Subject: [PATCH 33/40] add TODOs --- .github/workflows/ci.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e9360658..def24d06 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,10 @@ jobs: runs-on: ubuntu-latest strategy: matrix: + # TODO: Test Hatch matrices again. + # They could be as fast as concurrent GitHub jobs thanks to caching of dependencies and type check results. + # Then it is always possible to target a specific version of Python, for example with +py3.9 in the Dockerfile. + # Hatch matrices also vastly reduce the size of this workflow, with a single step for lint, test and audit. python-version: ["3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v4 @@ -20,7 +24,7 @@ jobs: with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }} - restore-keys: ${{ runner.os }}-pip- + restore-keys: ${{ runner.os }}-pip- - name: Install Hatch run: pipx install hatch - name: List Hatch environments @@ -47,7 +51,7 @@ jobs: with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }} - restore-keys: ${{ runner.os }}-pip- + restore-keys: ${{ runner.os }}-pip- - name: Install Hatch run: pipx install hatch - name: List Hatch environments @@ -57,6 +61,7 @@ jobs: audit: runs-on: ubuntu-latest + # TODO: Not sure `audit` is required to run on multiple versions of Python. strategy: matrix: python-version: ["3.8", "3.9", "3.10", "3.11"] @@ -71,7 +76,7 @@ jobs: with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }} - restore-keys: ${{ runner.os }}-pip- + restore-keys: ${{ runner.os }}-pip- - name: Install Hatch run: pipx install hatch - name: List Hatch environments @@ -95,7 +100,7 @@ jobs: with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }} - restore-keys: ${{ runner.os }}-pip- + restore-keys: ${{ runner.os }}-pip- - name: Install Hatch run: pipx install hatch - name: List Hatch environments From 54a2595e98f47ed76fa5e11eb71ed5345f92e743 Mon Sep 17 00:00:00 2001 From: Laurent Vaylet Date: Thu, 16 May 2024 17:02:30 +0200 Subject: [PATCH 34/40] ci: scan for CVEs in dedicated `audit` job with `bandit` and `safety` (#465) * create `audit` job for `bandit` and `safety` * [skip ci] fix indentation --- Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Makefile b/Makefile index f5bd6508..a0a62b5c 100644 --- a/Makefile +++ b/Makefile @@ -67,8 +67,6 @@ install: clean uninstall: clean $(HATCH) env prune -############## - #TODO: How to handle pre-commit with Hatch environments? develop: install pre-commit install @@ -78,8 +76,6 @@ develop: install format: $(HATCH) fmt -############## - #FIXME: Are all dependencies and features requested for all these targets? test: install unit lint audit From fe78f27fb1232f773a0169e241a7e8fc8fac7466 Mon Sep 17 00:00:00 2001 From: Laurent Vaylet Date: Thu, 16 May 2024 20:29:52 +0200 Subject: [PATCH 35/40] ci: use `ruff` for linting and formatting (#466) * use `ruff` in pre-commit hooks * remove unneeded empty line * use `ruff` everywhere! * format with `ruff` * use popular rule selection for linting * fix warnings reported by `ruff` * update contributing guide with `ruff` * fix issues reported by `ruff` * fix syntax * use type hints compatible with 3.8+ --- pyproject.toml | 133 +------------------------------------------------ 1 file changed, 1 insertion(+), 132 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3395bd8f..aec9fd1a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,144 +2,13 @@ requires = ["hatchling"] build-backend = "hatchling.build" -[project] -name = "slo-generator" -#TODO: Use dynamic version, stored in `src/slo_generator/__init__.py` as `__version__ = "2.6.0"`? -# Then use with `from . import __version__`. -# Is it compatible with release-please? -version = "2.6.0" -description = "SLO Generator" -readme = "README.md" -license = "Apache-2.0" -requires-python = ">=3.8, <4" -authors = [ - { name = "Google Inc.", email = "olivier.cervello@gmail.com" }, -] -maintainers = [ - { name = "Laurent Vaylet", email = "laurent.vaylet@gmail.com" } -] -keywords = [ - "gcp", - "generator", - "sli", - "slo", -] -classifiers = [ - "Development Status :: 5 - Production/Stable", - "Environment :: Console", - "Intended Audience :: Developers", - "Intended Audience :: System Administrators", - "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Topic :: Software Development :: Build Tools", - "Topic :: System :: Monitoring", -] -dependencies = [ - "certifi>=2023.07.22", # avoid CVE-2023-37920 (reported by `safety check`) - "click", - "python-dateutil", - "pyyaml", - "ruamel.yaml", -] - -[project.optional-dependencies] -api = [ - "cloudevents", - "Flask", - "functions-framework", - "gunicorn", - "requests", -] -bigquery = [ - "google-api-python-client", - "google-cloud-bigquery", -] -cloud_monitoring = [ - "google-api-python-client", - "google-cloud-monitoring", -] -cloud_service_monitoring = [ - "google-api-python-client", - "google-cloud-monitoring", -] -cloud_storage = [ - "google-api-python-client", - "google-cloud-storage", -] -cloudevent = [ - "cloudevents", -] -datadog = [ - "datadog", - "retrying==1.3.4", -] -dynatrace = [ - "requests", -] -elasticsearch = [ - "elasticsearch", -] -opensearch = [ - "opensearch-py", -] -prometheus = [ - "prometheus-client", - "prometheus-http-client", -] -pubsub = [ - "google-api-python-client", - "google-cloud-pubsub", -] -splunk = [ - "splunk-sdk", -] - -[project.scripts] -slo-generator = "slo_generator.cli:main" - -[project.urls] -Homepage = "https://github.com/google/slo-generator" -Issues = "https://github.com/google/slo-generator/issues" -Source = "https://github.com/google/slo-generator" - -[tool.hatch.build.targets.sdist] -exclude = [ - "/.github", - "/docs", - "/tests", -] - -[tool.bandit] -exclude_dirs = [ - "tests", -] - -[tool.pylint] -ignore-patterns = [ - "test_.*?py", -] - -[tool.pylint.messages_control] -max-line-length = 88 -disable = [ - "logging-fstring-interpolation", - "import-error", - "possibly-used-before-assignment", -] - [tool.mypy] # https://mypy.readthedocs.io/en/stable/config_file.html#using-a-pyproject-toml-file # https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-library-stubs-or-py-typed-marker disable_error_code = "import-untyped" [tool.pytype] -inputs = [ - "src/slo_generator", -] +inputs = ['slo_generator'] [tool.ruff.lint] # https://docs.astral.sh/ruff/linter/#rule-selection From cd9d51403641211d67b8b007d529aab20ee83aca Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 09:49:44 +0000 Subject: [PATCH 36/40] migrate from setuptools to hatch with `hatch new --init` --- pyproject.toml | 128 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index aec9fd1a..8c35f65f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,6 +2,134 @@ requires = ["hatchling"] build-backend = "hatchling.build" +[project] +name = "slo-generator" +dynamic = ["version"] +description = "SLO Generator" +readme = "README.md" +license = "Apache License 2.0" +requires-python = ">=3.7, <4" +authors = [ + { name = "Google Inc.", email = "olivier.cervello@gmail.com" }, +] +keywords = [ + "gcp", + "generator", + "sli", + "slo", +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Developers", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Topic :: Software Development :: Build Tools", + "Topic :: System :: Monitoring", +] +dependencies = [ + "certifi >=2023.07.22", + "click", + "python-dateutil", + "pyyaml", + "ruamel.yaml", + "setuptools >=65.5.1", +] + +[project.optional-dependencies] +api = [ + "cloudevents", + "Flask", + "functions-framework", + "gunicorn", + "requests", +] +bigquery = [ + "google-api-python-client", + "google-cloud-bigquery", +] +cloud_monitoring = [ + "google-api-python-client", + "google-cloud-monitoring", +] +cloud_service_monitoring = [ + "google-api-python-client", + "google-cloud-monitoring", +] +cloud_storage = [ + "google-api-python-client", + "google-cloud-storage", +] +cloudevent = [ + "cloudevents", +] +datadog = [ + "datadog", + "retrying==1.3.4", +] +dev = [ + "bandit", + "black >=24.3.0", + "flake8", + "GitPython >=3.1.35", + "isort", + "mock", + "mypy", + "pip >=23.3", + "pre-commit", + "pylint", + "pytest", + "pytest-cov", + "pytype", + "safety >=3", + "types-mock", + "types-protobuf", + "types-python-dateutil", + "types-PyYAML", + "types-requests", + "types-setuptools", + "wheel", +] +dynatrace = [ + "requests", +] +elasticsearch = [ + "elasticsearch", +] +opensearch = [ + "opensearch-py", +] +prometheus = [ + "prometheus-client", + "prometheus-http-client", +] +pubsub = [ + "google-api-python-client", + "google-cloud-pubsub", +] +splunk = [ + "splunk-sdk", +] + +[project.scripts] +slo-generator = "slo_generator.cli:main" + +[project.urls] +Homepage = "https://github.com/google/slo-generator" + +[tool.hatch.version] +path = "slo_generator/__init__.py" + +[tool.hatch.build.targets.sdist] +include = [ + "/slo_generator", +] + [tool.mypy] # https://mypy.readthedocs.io/en/stable/config_file.html#using-a-pyproject-toml-file # https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-library-stubs-or-py-typed-marker From 7505e24a1ffe4051d0c13135002d9f200efaac7d Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Wed, 15 May 2024 12:35:26 +0000 Subject: [PATCH 37/40] configure build --- pyproject.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8c35f65f..c0f157c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -126,8 +126,10 @@ Homepage = "https://github.com/google/slo-generator" path = "slo_generator/__init__.py" [tool.hatch.build.targets.sdist] -include = [ - "/slo_generator", +exclude = [ + "/.github", + "/docs", + "/tests", ] [tool.mypy] From 51f77e0216d09e9e1ff4828da62ec44656be9567 Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Thu, 16 May 2024 07:27:17 +0000 Subject: [PATCH 38/40] add TODOs and FIXMEs --- Makefile | 1 + pyproject.toml | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a0a62b5c..da32198d 100644 --- a/Makefile +++ b/Makefile @@ -62,6 +62,7 @@ deploy: build #TODO: Replace with Hatch. install: clean +#FIXME: Are all dependencies and features requested for all these targets? $(PIP) install -e ."[api, datadog, prometheus, elasticsearch, opensearch, splunk, pubsub, cloud_monitoring, bigquery, dev]" uninstall: clean diff --git a/pyproject.toml b/pyproject.toml index c0f157c2..6a5f7da1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,10 @@ build-backend = "hatchling.build" [project] name = "slo-generator" -dynamic = ["version"] +#TODO: Use dynamic version, stored in `src/slo_generator/__init__.py` as `__version__ = "2.6.0"`? +# Then use with `from . import __version__`. +# Is it compatible with release-please? +version = "2.6.0" description = "SLO Generator" readme = "README.md" license = "Apache License 2.0" From 61ce34d6cdb7fd8f42ddac5bc26db8b3c647adc4 Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Thu, 16 May 2024 07:28:46 +0000 Subject: [PATCH 39/40] update Makefile for Hatch --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index da32198d..a49a4ef8 100644 --- a/Makefile +++ b/Makefile @@ -68,6 +68,8 @@ install: clean uninstall: clean $(HATCH) env prune +############## + #TODO: How to handle pre-commit with Hatch environments? develop: install pre-commit install @@ -77,6 +79,8 @@ develop: install format: $(HATCH) fmt +############## + #FIXME: Are all dependencies and features requested for all these targets? test: install unit lint audit From 148c733d9c36a9fafa857892db608f9b8bdf489f Mon Sep 17 00:00:00 2001 From: Laurent VAYLET Date: Thu, 16 May 2024 07:31:17 +0000 Subject: [PATCH 40/40] update `pytype` configuration --- pyproject.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6a5f7da1..e2d177af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -141,7 +141,9 @@ exclude = [ disable_error_code = "import-untyped" [tool.pytype] -inputs = ['slo_generator'] +inputs = [ + "src/slo_generator", +] [tool.ruff.lint] # https://docs.astral.sh/ruff/linter/#rule-selection