From d04c142fbe9da2ec5a2bfabf2f1dcedebad3f0c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Wed, 18 Jan 2023 11:02:16 +0100 Subject: [PATCH 01/10] docs: update documentation link --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a407f26..2911f6d 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ def hello_world(event, context): return "Hello World!" ``` -Deploy it with `scw_serverless`: +Deploy it with `scw-serverless`: ```console scw-serverless deploy app.py @@ -26,10 +26,10 @@ scw-serverless deploy app.py ### Install ```console -pip install scw_serverless +pip install scw-serverless ``` -This will install `scw-serverless`: +This will install the `scw-serverless` CLI: ```console scw-serverless --help @@ -53,7 +53,7 @@ def hello_world(event, context): ``` The configuration is done by passing arguments to the decorator. -To view which arguments are supported, head over to this [documentation](https://serverless-apifw-docs.s3-website.fr-par.scw.cloud/configuring.html) page. +To view which arguments are supported, head over to this [documentation](https://serverless-api-project.readthedocs.io/) page. When you are ready, you can deploy your function with the `scw-serverless` CLI tool: @@ -65,7 +65,7 @@ The tool will use your Scaleway credentials from your environment and config fil ## What’s Next? -To learn more about the framework, have a look at the [documentation](https://serverless-apifw-docs.s3-website.fr-par.scw.cloud/index.html). +To learn more about the framework, have a look at the [documentation](https://serverless-api-project.readthedocs.io/). If you want to see it in action, we provide some [examples](https://github.com/scaleway/serverless-api-project/tree/main/examples) to get you started. ## Contributing From 31ca94308b725d572f3c0bc21b45cdd9cbc165d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Wed, 18 Jan 2023 12:01:22 +0100 Subject: [PATCH 02/10] chore: update pre-commit hooks --- .pre-commit-config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a00faa3..b27f4a6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,18 +2,18 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 + rev: v4.4.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - id: check-added-large-files - repo: https://github.com/psf/black - rev: 22.10.0 + rev: 22.12.0 hooks: - id: black - repo: https://github.com/pycqa/isort - rev: 5.10.1 + rev: 5.11.4 hooks: - id: isort name: isort (python) @@ -30,7 +30,7 @@ repos: "--rcfile=pyproject.toml", ] - repo: https://github.com/pycqa/flake8 - rev: 5.0.4 + rev: 6.0.0 hooks: - id: flake8 additional_dependencies: [flake8-annotations] From 742df5df570fc891cec45cf4fa2ae674561b4f51 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 18 Jan 2023 11:05:43 +0000 Subject: [PATCH 03/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .github/CODE_OF_CONDUCT.md | 1 - .github/CONTRIBUTING.md | 3 +-- .github/ISSUE_TEMPLATE/bug_report.md | 1 - .github/ISSUE_TEMPLATE/feature_request.md | 1 - .github/pull_request_template.md | 1 - SECURITY.md | 1 - 6 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index 84ef0f6..d9c8871 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -74,4 +74,3 @@ available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.ht For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq - diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 1fd05f1..a58e3ea 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -49,7 +49,7 @@ The goal of the following guidelines is to have Pull Requests (PRs) that are fai - **Pull Request title should respect [conventional commits](https://www.conventionalcommits.org/en/v1.0.0) specifications** and be clear on what is being changed. - **Keep it readable for human reviewers** and prefer a subset of functionality (code) with tests and documentation over delivering them separately -- **Don't forget commenting code** to help reviewers understand +- **Don't forget commenting code** to help reviewers understand - **Notify Work In Progress PRs** by prefixing the title with `[WIP]` - **Please, keep us updated.** We will try our best to merge your PR, but please notice that PRs may be closed after 30 days of inactivity. @@ -63,4 +63,3 @@ Keep in mind only the **pull request title** will be used as commit message as w See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). Thank you for reading through all of this, if you have any question feel free to [reach us](README.md#reach-us)! - diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 543a665..a3b5538 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -29,4 +29,3 @@ labels: bug ## More info - diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 1a72dcf..1ee7f8f 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -23,4 +23,3 @@ labels: enhancement ### References - diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 0b84302..6b02b8c 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -21,4 +21,3 @@ If the change is not user facing, just write "NONE" in the release-note block be - [ ] I have added unit test covering every changes I have made - [ ] I have updated the relevant documentation - diff --git a/SECURITY.md b/SECURITY.md index d015af4..14f3a41 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -11,4 +11,3 @@ We will follow up with you promptly with more information and a plan for remedia We currently do not offer a paid security bounty program, but we would love to send some Scaleway swag your way along with our deepest gratitude for your assistance in making Scaleway a more secure Cloud ecosystem. - From 9792398f744b3262d03d868c7de11c0fc1813a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Wed, 18 Jan 2023 14:21:07 +0100 Subject: [PATCH 04/10] chore: fix lines-too-long linter errors --- .flake8 | 4 +++- .pre-commit-config.yaml | 9 +++++++++ examples/cron/handler.py | 2 +- examples/pr_notifier/notifier.py | 10 ++++++++-- pyproject.toml | 8 +++++++- scw_serverless/app.py | 3 +-- scw_serverless/cli.py | 8 ++++++-- scw_serverless/config/function.py | 6 ++++-- scw_serverless/config/generators/terraform.py | 5 ++++- scw_serverless/dependencies_manager.py | 10 ++++------ scw_serverless/triggers/cron.py | 5 ++++- 11 files changed, 51 insertions(+), 19 deletions(-) diff --git a/.flake8 b/.flake8 index a7b56e7..870aa6c 100644 --- a/.flake8 +++ b/.flake8 @@ -1,8 +1,10 @@ [flake8] per-file-ignores = - # ignore type hints returns in test + # Ignore type hints returns in test tests/*: ANN201 **/__init__.py: F401 + # Ignore invalid syntax in file that use python3.10 + examples/pr_notifier/*: E999 extend-ignore = # See: https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html E203, diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b27f4a6..66c6a79 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,3 +1,7 @@ +ci: + # Can't use a local installation of pylint with pre-commit.ci + skip: [pylint] + # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks repos: @@ -12,6 +16,7 @@ repos: rev: 22.12.0 hooks: - id: black + args: [--safe, --quiet] - repo: https://github.com/pycqa/isort rev: 5.11.4 hooks: @@ -39,3 +44,7 @@ repos: hooks: - id: python-bandit-vulnerability-check args: [--skip, "B101", --recursive, clumper] + - repo: https://github.com/regebro/pyroma + rev: "4.1" + hooks: + - id: pyroma diff --git a/examples/cron/handler.py b/examples/cron/handler.py index f715972..6f0fe24 100644 --- a/examples/cron/handler.py +++ b/examples/cron/handler.py @@ -14,7 +14,7 @@ inputs={"myname": "Georges"}, privacy="public", ) -def hello_cron(event: dict[str, Any], _context: dict[str, Any]): +def hello_cron(event: dict[str, Any], _context: dict[str, Any]) -> dict[str, Any]: """A simple cron that regularly greets you during business days.""" body = json.loads(event["body"]) my_name = body["myname"] diff --git a/examples/pr_notifier/notifier.py b/examples/pr_notifier/notifier.py index cd17d8f..e29ddb9 100644 --- a/examples/pr_notifier/notifier.py +++ b/examples/pr_notifier/notifier.py @@ -328,7 +328,10 @@ def load_pr_from_bucket(bucket_path: str) -> Tuple[str, PullRequest]: def handle_github(event, _content): """Handles GitHub webhook request. - .. seealso:: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#pull_request + .. seealso:: + + GitHub Events Documentation + https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#pull_request """ body = json.loads(event["body"]) match body: @@ -369,7 +372,10 @@ def handle_github(event, _content): def handle_gitlab(event, _content): """Handles GitLab webhook request. - .. seealso:: https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#merge-request-events + .. seealso:: + + GitLab Events Documentation + https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#merge-request-events """ body = json.loads(event["body"]) match body: diff --git a/pyproject.toml b/pyproject.toml index a510de3..67c09ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,10 +6,13 @@ build-backend = "setuptools.build_meta" name = "scw_serverless" version = "0.0.2" description = "An API framework to make it easy to work with Scaleway Serverless functions." +authors = [ + { name = "Scaleway Serverless Team", email = "opensource@scaleway.com" }, +] readme = "README.md" requires-python = ">=3.9" license = { file = "LICENSE" } -keywords = ["serverless", "scaleway", "functions", "cloud"] +keywords = ["serverless", "scaleway", "functions", "cloud", "faas"] # Should be one of: # 'Development Status :: 3 - Alpha' @@ -23,6 +26,9 @@ classifiers = [ "Topic :: Internet", "License :: OSI Approved :: MIT License", "Programming Language :: Python", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", ] dependencies = [ diff --git a/scw_serverless/app.py b/scw_serverless/app.py index 8087e20..7e9a961 100644 --- a/scw_serverless/app.py +++ b/scw_serverless/app.py @@ -1,13 +1,12 @@ from typing import TYPE_CHECKING, Any, Callable, List, Optional, Union -from typing_extensions import Unpack - if TYPE_CHECKING: try: from typing import Unpack except ImportError: from typing_extensions import Unpack # pylint: disable=wrong-import-position # Conditional import considered a statement + from scw_serverless.config.function import Function, FunctionKwargs from scw_serverless.config.route import HTTPMethod from scw_serverless.triggers import CronTrigger diff --git a/scw_serverless/cli.py b/scw_serverless/cli.py index 9195bea..2600649 100644 --- a/scw_serverless/cli.py +++ b/scw_serverless/cli.py @@ -29,10 +29,14 @@ ), ) -# TODO: link to the doc + @click.group() def cli() -> None: - """Deploy your Serverless functions on Scaleway's Cloud.""" + """Deploy your Serverless functions on Scaleway's Cloud. + + Documentation: + https://serverless-api-project.readthedocs.io/en/latest/ + """ # TODO?: clean up the locals by introducing a class diff --git a/scw_serverless/config/function.py b/scw_serverless/config/function.py index 5a8ac9f..f1616fe 100644 --- a/scw_serverless/config/function.py +++ b/scw_serverless/config/function.py @@ -46,10 +46,12 @@ class FunctionKwargs(TypedDict): :param timeout: Max duration to respond to a request. :param description: Description. Defaults to the function docstring if defined. :param http_option: Either "enabled" or "redirected". - If "redirected" (default), redirects http traffic to your function. + If "redirected" (default), allow http traffic to your function. Blocked otherwise. - .. seealso:: https://developers.scaleway.com/en/products/functions/api/#create-a-function + .. seealso:: + Scaleway Developers Documentation + https://developers.scaleway.com/en/products/functions/api/#create-a-function """ env: NotRequired[dict[str, str]] diff --git a/scw_serverless/config/generators/terraform.py b/scw_serverless/config/generators/terraform.py index 1180179..4cac0e4 100644 --- a/scw_serverless/config/generators/terraform.py +++ b/scw_serverless/config/generators/terraform.py @@ -119,7 +119,10 @@ def from_serverless(serverless: Serverless): class TerraformGenerator(Generator): """Generates the Terraform configuration to deploy the functions. - .. seealso:: https://registry.terraform.io/providers/scaleway/scaleway/latest/docs/resources/function + .. seealso:: + + Scaleway Terraform Provider Documentation: + https://registry.terraform.io/providers/scaleway/scaleway/latest/docs/resources/function """ def __init__(self, instance: Serverless, deps_manager: DependenciesManager): diff --git a/scw_serverless/dependencies_manager.py b/scw_serverless/dependencies_manager.py index 55cc92e..b07a2ca 100644 --- a/scw_serverless/dependencies_manager.py +++ b/scw_serverless/dependencies_manager.py @@ -17,15 +17,13 @@ class DependenciesManager: It does not currently handles native dependencies. - .. seealso:: https://developers.scaleway.com/en/products/functions/api/#python-additional-dependencies + .. seealso:: + + Scaleway Documentation + """ def __init__(self, in_path: pathlib.Path, out_path: pathlib.Path) -> None: - if type(in_path) == str: - in_path = pathlib.Path(in_path) - if type(out_path) == str: - out_path = pathlib.Path(out_path) - self.in_path = in_path self.out_path = out_path self.logger = get_logger() diff --git a/scw_serverless/triggers/cron.py b/scw_serverless/triggers/cron.py index 0d4a8bf..be2a353 100644 --- a/scw_serverless/triggers/cron.py +++ b/scw_serverless/triggers/cron.py @@ -10,7 +10,10 @@ class CronTrigger: :param args: Data to be sent in the body. :param name: Name to give to your resource. - .. seealso:: https://developers.scaleway.com/en/products/functions/api/#create-a-cron-trigger-for-your-function + .. seealso:: + + Scaleway Documentation + """ schedule: str From ece702e24c26230a975795b457cb7f9c2a237a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Wed, 18 Jan 2023 14:54:57 +0100 Subject: [PATCH 05/10] chore: clean up logger --- examples/pr_notifier/notifier.py | 4 +-- scw_serverless/app.py | 11 +++--- scw_serverless/logger.py | 61 +++++++++++++++++++------------- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/examples/pr_notifier/notifier.py b/examples/pr_notifier/notifier.py index e29ddb9..095183b 100644 --- a/examples/pr_notifier/notifier.py +++ b/examples/pr_notifier/notifier.py @@ -325,7 +325,7 @@ def load_pr_from_bucket(bucket_path: str) -> Tuple[str, PullRequest]: @app.func() -def handle_github(event, _content): +def handle_github(event: dict[str, Any], _content: dict[str, Any]): """Handles GitHub webhook request. .. seealso:: @@ -369,7 +369,7 @@ def handle_github(event, _content): @app.func(min_scale=1, memory_limit=1024) -def handle_gitlab(event, _content): +def handle_gitlab(event: dict[str, Any], _content: dict[str, Any]): """Handles GitLab webhook request. .. seealso:: diff --git a/scw_serverless/app.py b/scw_serverless/app.py index 7e9a961..0172ac9 100644 --- a/scw_serverless/app.py +++ b/scw_serverless/app.py @@ -1,10 +1,9 @@ -from typing import TYPE_CHECKING, Any, Callable, List, Optional, Union +from typing import Any, Callable, List, Optional, Union -if TYPE_CHECKING: - try: - from typing import Unpack - except ImportError: - from typing_extensions import Unpack +try: + from typing import Unpack +except ImportError: + from typing_extensions import Unpack # pylint: disable=wrong-import-position # Conditional import considered a statement from scw_serverless.config.function import Function, FunctionKwargs diff --git a/scw_serverless/logger.py b/scw_serverless/logger.py index 50c32e7..3f7b756 100644 --- a/scw_serverless/logger.py +++ b/scw_serverless/logger.py @@ -1,3 +1,5 @@ +from typing import NamedTuple + import click DEBUG = 0 @@ -11,66 +13,75 @@ _LOGGER_SINGLETON = None -def get_logger(): - """Get""" - global _LOGGER_SINGLETON +def get_logger() -> "Logger": + """Gets the global logger instance.""" + # pylint: disable=global-statement # Known issue FIXME + global _LOGGER_SINGLETON # noqa # This is the first time we call get_logger, init the singleton if not _LOGGER_SINGLETON: _LOGGER_SINGLETON = Logger() return _LOGGER_SINGLETON -class _LogRecord: - def __init__(self, message: str = None, level: int = 0): - self.message = message - self.level = level +_LogRecord = NamedTuple("LogRecord", [("level", int), ("message", str)]) class Logger: + """A logger built on top of click.echo.""" + def __init__(self): self.level = DEFAULT - def set_level(self, level: int): + def set_level(self, level: int) -> None: + """Sets the log level.""" self.level = level - def critical(self, message: str): + def critical(self, message: str) -> None: + """Logs a critical message.""" self.log(CRITICAL, message) - def error(self, message: str): + def error(self, message: str) -> None: + """Logs an error message.""" self.log(ERROR, message) - def warning(self, message: str): + def warning(self, message: str) -> None: + """Logs a warning message.""" self.log(WARNING, message) - def success(self, message: str): + def success(self, message: str) -> None: + """Logs a success message.""" self.log(SUCCESS, message) - def info(self, message: str): + def info(self, message: str) -> None: + """Logs an info message.""" self.log(INFO, message) - def default(self, message: str): + def default(self, message: str) -> None: + """Logs a message.""" self.log(DEFAULT, message) - def debug(self, message: str): + def debug(self, message: str) -> None: + """Logs a debug message.""" self.log(DEBUG, message) - def log(self, level: int, message: str): - self.emit(_LogRecord(message=message, level=level)) + def log(self, level: int, message: str) -> None: + """Logs a message with a specific level.""" + self._emit(_LogRecord(message=message, level=level)) - def emit(self, record: _LogRecord): + def _emit(self, record: _LogRecord): if record.level < self.level: return err = False - fg = "" - if record.level == ERROR or record.level == CRITICAL: + color = "" + if record.level in [ERROR, CRITICAL]: err = True - fg = "red" + color = "red" elif record.level == WARNING: - fg = "yellow" + color = "yellow" elif record.level == INFO: - fg = "cyan" + color = "cyan" elif record.level == SUCCESS: - fg = "green" + color = "green" - click.echo(click.style(record.message, fg=fg), err=err) + click.echo(click.style(record.message, fg=color), err=err) From 8a2f7f36ce74a64120eff82eb3106f0269322b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Wed, 18 Jan 2023 15:03:22 +0100 Subject: [PATCH 06/10] chore(examples): fix linter errros on pr_notifier --- examples/pr_notifier/notifier.py | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/examples/pr_notifier/notifier.py b/examples/pr_notifier/notifier.py index 095183b..c763273 100644 --- a/examples/pr_notifier/notifier.py +++ b/examples/pr_notifier/notifier.py @@ -146,7 +146,10 @@ def bucket_path(self) -> str: def from_github(repository: dict[str, Any], pull_request: dict[str, Any]): """Creates from a GitHub PR. - .. seealso:: https://docs.github.com/en/rest/pulls/pulls?apiVersion=2022-11-28#get-a-pull-request + .. seealso:: + + GitHub Documentation + https://docs.github.com/en/rest/pulls/pulls?apiVersion=2022-11-28#get-a-pull-request """ return PullRequest( number=pull_request["number"], @@ -191,11 +194,11 @@ def from_gitlab( deletions=None, ) - def on_draft(self): + def on_draft(self) -> None: """Saves a PR marked as a draft to notify when it's ready.""" save_pr_to_bucket(self, "") - def on_created(self): + def on_created(self) -> None: """Sends a notification for a newly created PR.""" response = client.chat_postMessage( channel=SLACK_CHANNEL, blocks=self._as_slack_notification() @@ -206,13 +209,13 @@ def on_created(self): timestamp = str(response["ts"]) save_pr_to_bucket(self, timestamp) - def on_updated(self): + def on_updated(self) -> None: """Performs the necessary changes when a PR is updated.""" _timestamp, pull = load_pr_from_bucket(self.bucket_path) if pull.is_draft and not self.is_draft: self.on_created() - def on_reviewed(self, review: Review, reviewer: Developer): + def on_reviewed(self, review: Review, reviewer: Developer) -> None: """Updates the notification when a new review is made.""" timestamp, pull = load_pr_from_bucket(self.bucket_path) self.reviews = pull.reviews.copy() @@ -233,7 +236,7 @@ def on_reviewed(self, review: Review, reviewer: Developer): if not response["ok"]: logging.warning(response["error"]) - def on_closed(self): + def on_closed(self) -> None: """Sends a message in the thread when the PR is merged.""" if self.is_merged: timestamp, _pull = load_pr_from_bucket(self.bucket_path) @@ -297,19 +300,20 @@ def get_reminder_slack_blk(self, timestamp: str) -> blks.SectionBlock: """Gets the message to be added to the reminder.""" url = self.url if SLACK_INSTANCE: - url = f"https://{ SLACK_INSTANCE }.slack.com/archives/{ SLACK_CHANNEL }/p{ timestamp }" + instance_url = f"https://{SLACK_INSTANCE}.slack.com" + url = f"{instance_url}/archives/{SLACK_CHANNEL}/p{timestamp}" reminder = f"*<{url}|{self.title}>*" return blks.SectionBlock( text=blks.MarkdownTextObject(text=reminder, verbatim=True), ) -def delete_pr_from_bucket(bucket_path: str): +def delete_pr_from_bucket(bucket_path: str) -> None: """Deletes a PR.""" s3.Object(S3_BUCKET, bucket_path).delete() -def save_pr_to_bucket(pull: PullRequest, timestamp: str): +def save_pr_to_bucket(pull: PullRequest, timestamp: str) -> None: """Saves a PR associated with a Slack timestamp.""" s3.Object(S3_BUCKET, pull.bucket_path).put( Body=json.dumps({"ts": timestamp, "pull_request": pull.to_dict()}) @@ -325,7 +329,7 @@ def load_pr_from_bucket(bucket_path: str) -> Tuple[str, PullRequest]: @app.func() -def handle_github(event: dict[str, Any], _content: dict[str, Any]): +def handle_github(event: dict[str, Any], _content: dict[str, Any]) -> dict[str, Any]: """Handles GitHub webhook request. .. seealso:: @@ -369,7 +373,7 @@ def handle_github(event: dict[str, Any], _content: dict[str, Any]): @app.func(min_scale=1, memory_limit=1024) -def handle_gitlab(event: dict[str, Any], _content: dict[str, Any]): +def handle_gitlab(event: dict[str, Any], _content: dict[str, Any]) -> dict[str, Any]: """Handles GitLab webhook request. .. seealso:: @@ -424,7 +428,9 @@ def handle_gitlab(event: dict[str, Any], _content: dict[str, Any]): @app.schedule(REMINDER_SCHEDULE) -def pull_request_reminder(_event, _content): +def pull_request_reminder( + _event: dict[str, Any], _content: dict[str, Any] +) -> dict[str, Any]: """Daily reminder to review opened pull-requests.""" blocks = [blks.HeaderBlock(text="PRs awaiting for review: "), blks.DividerBlock()] for opened_pr in s3.Bucket(S3_BUCKET).objects.all(): From a7af56fffec356431f6a4127f450897b88126430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Wed, 18 Jan 2023 17:20:19 +0100 Subject: [PATCH 07/10] fix(build): missing important subpackages --- pyproject.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 67c09ae..fe645ad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,9 +49,8 @@ repository = "https://github.com/scaleway/serverless-api-project" scw-serverless = "scw_serverless.cli:main" [tool.setuptools] +# Using: https://setuptools.pypa.io/en/latest/userguide/package_discovery.html#flat-layout include-package-data = true -# See: https://setuptools.pypa.io/en/latest/userguide/package_discovery.html#flat-layout -packages = ["scw_serverless"] [tool.setuptools.package-data] scw_serverless = ["**/*.json", "**/*.yml"] From 489dd2cf17f863d1140e3fcbc8f3b29feff15519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Wed, 18 Jan 2023 17:30:29 +0100 Subject: [PATCH 08/10] chore: update scaleway-sdk to 0.5 --- requirements.txt | 2 +- .../deploy/backends/scaleway_api_backend.py | 24 +++++++++---------- tests/integrations/utils.py | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/requirements.txt b/requirements.txt index c466c29..f183234 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ click==8.1.3 PyYAML==6.0 -scaleway==0.2.0 +scaleway==0.5.0 setuptools==66.0.0 requests==2.28.2 typing_extensions==4.4.0 diff --git a/scw_serverless/deploy/backends/scaleway_api_backend.py b/scw_serverless/deploy/backends/scaleway_api_backend.py index a693844..2e9ed97 100644 --- a/scw_serverless/deploy/backends/scaleway_api_backend.py +++ b/scw_serverless/deploy/backends/scaleway_api_backend.py @@ -32,7 +32,7 @@ def _get_or_create_function(self, function: Function, namespace_id: str) -> str: self.logger.default(f"Looking for an existing function {function.name}...") created_function = None # Checking if a function already exists - for func in self.api.list_functions_all(namespace_id): + for func in self.api.list_functions_all(namespace_id=namespace_id): if func.name == function.name: created_function = func if not created_function: @@ -93,10 +93,10 @@ def _deploy_function( self.logger.default(f"Deploying function {function.name}...") # deploy the newly uploaded function - self.api.deploy_function(function_id) + self.api.deploy_function(function_id=function_id) return self.api.wait_for_function( - function_id, + function_id=function_id, options=WaitForOptions( timeout=DEPLOY_TIMEOUT, stop=lambda f: (f.status != sdk.FunctionStatus.PENDING), @@ -106,7 +106,7 @@ def _deploy_function( def _deploy_trigger(self, function_id: str, trigger: Trigger) -> sdk.Cron: created_trigger = None # Checking if a trigger already exists - for cron in self.api.list_crons_all(function_id): + for cron in self.api.list_crons_all(function_id=function_id): if cron.name == trigger.name: created_trigger = cron if not created_trigger: @@ -118,11 +118,11 @@ def _deploy_trigger(self, function_id: str, trigger: Trigger) -> sdk.Cron: ) else: created_trigger = self.api.update_cron( - created_trigger.id, + cron_id=created_trigger.id, schedule=trigger.schedule, args=trigger.args, ) - return self.api.wait_for_cron(created_trigger.id) + return self.api.wait_for_cron(cron_id=created_trigger.id) def _create_deployment_zip(self) -> int: """Create a ZIP archive containing the entire project.""" @@ -154,21 +154,21 @@ def _upload_deployment_zip(self, upload_url: str, zip_size: int): def _remove_missing_functions(self, namespace_id: str): """Deletes functions no longer present in the code.""" function_names = [func.name for func in self.app_instance.functions] - for func in self.api.list_functions_all(namespace_id=namespace_id): - if func.name not in function_names: - self.logger.info(f"Deleting function {func.name}...") - self.api.delete_function(func.id) + for function in self.api.list_functions_all(namespace_id=namespace_id): + if function.name not in function_names: + self.logger.info(f"Deleting function {function.name}...") + self.api.delete_function(function_id=function.id) def _remove_missing_triggers(self, namespace_id: str, deployed_triggers: set[str]): """Deletes triggers no longer present in the code.""" for function in self.api.list_functions_all(namespace_id=namespace_id): unmanaged = filter( lambda c: c.id not in deployed_triggers, - self.api.list_crons_all(function.id), + self.api.list_crons_all(function_id=function.id), ) for cron in unmanaged: self.logger.info(f"Deleting Cron {cron.name}...") - self.api.delete_cron(cron.id) + self.api.delete_cron(cron_id=cron.id) def _get_or_create_namespace(self) -> str: project_id = self.api.client.default_project_id diff --git a/tests/integrations/utils.py b/tests/integrations/utils.py index 419bc8f..4048b75 100644 --- a/tests/integrations/utils.py +++ b/tests/integrations/utils.py @@ -186,7 +186,7 @@ def _create_project(self) -> str: sha = os.getenv("GITHUB_SHA", "local") name = f"apifw-{sha[:7]}-{random.randint(0, 9999)}" project = AccountV2API(self.client).create_project( - name, + name=name, description="Created by the Serverless API Framework integration suite.", ) return project.id @@ -229,7 +229,7 @@ def _delete_project(self, max_tries: int = 5): api = AccountV2API(self.client) for _ in range(max_tries): try: - api.delete_project(self.project_id) + api.delete_project(project_id=self.project_id) return except ScalewayException as e: # This is just very finicky, the account API is somewhat unstable. From c5a1f943ddddeb858da5a44764bf66ba9231d631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Wed, 18 Jan 2023 17:36:30 +0100 Subject: [PATCH 09/10] chore: also bump scaleway-sdk in pyproject --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index fe645ad..730ac84 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ classifiers = [ dependencies = [ "click >= 8", "PyYAML >= 6", - "scaleway >= 0.2", + "scaleway >= 0.5", # Requires support for pyproject.toml "setuptools >= 61", "requests >= 2", From 04c9d831e0330a59aa0fc4ec459ebfb84b8a270b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andy=20M=C3=A9ry?= Date: Wed, 18 Jan 2023 17:54:02 +0100 Subject: [PATCH 10/10] chore: update scw-serverless in examples --- examples/github_actions/requirements.txt | 2 +- examples/pr_notifier/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/github_actions/requirements.txt b/examples/github_actions/requirements.txt index e7937d6..2ee6dac 100644 --- a/examples/github_actions/requirements.txt +++ b/examples/github_actions/requirements.txt @@ -1 +1 @@ -scw-serverless +scw-serverless~=0.0.2 diff --git a/examples/pr_notifier/requirements.txt b/examples/pr_notifier/requirements.txt index b23f62f..9265e74 100644 --- a/examples/pr_notifier/requirements.txt +++ b/examples/pr_notifier/requirements.txt @@ -1,4 +1,4 @@ boto3~=1.26 dataclass-wizard~=0.22 -scw_serverless==0.0.1b0 +scw-serverless~=0.0.2 slack_sdk~=3.19