From ee45c3a3db35b7dcb92516fc93686969ab951113 Mon Sep 17 00:00:00 2001 From: Christian Busch Date: Fri, 7 Oct 2022 16:04:08 +0200 Subject: [PATCH 1/4] refactor: strategy pattern for deckfile fetching - preparation for bugfixes + features regarding deckfile, e.g. #81 - decouple deckfile fetching from parsing - tests added --- getdeck/__main__.py | 20 ++-- getdeck/deckfile/fetch/deck_fetcher.py | 129 +++++++++++++++++++++++++ getdeck/deckfile/fetch/utils.py | 33 +++++++ getdeck/utils.py | 111 ++++++++------------- test/src/test_deck_fetch_behavior.py | 80 +++++++++++++++ test/src/test_deck_fetch_utils.py | 90 +++++++++++++++++ test/src/test_deck_fetcher.py | 47 +++++++++ test/src/test_deckfile.py | 23 +++++ test/test_deckfile.py | 14 --- 9 files changed, 454 insertions(+), 93 deletions(-) create mode 100644 getdeck/deckfile/fetch/deck_fetcher.py create mode 100644 getdeck/deckfile/fetch/utils.py create mode 100644 test/src/test_deck_fetch_behavior.py create mode 100644 test/src/test_deck_fetch_utils.py create mode 100644 test/src/test_deck_fetcher.py create mode 100644 test/src/test_deckfile.py delete mode 100644 test/test_deckfile.py diff --git a/getdeck/__main__.py b/getdeck/__main__.py index 8005941..ed9bd56 100755 --- a/getdeck/__main__.py +++ b/getdeck/__main__.py @@ -134,15 +134,19 @@ def main(): logger.info(names) elif args.action == "get": if args.wait: - run_deck( - args.Deckfile, - args.name, - ignore_cluster=args.no_cluster, - wait=True, - timeout=int(args.timeout), - ) + wait = True + timeout = int(args.timeout) else: - run_deck(args.Deckfile, args.name, ignore_cluster=args.no_cluster) + wait = False + timeout = None + + run_deck( + args.Deckfile, + args.name, + ignore_cluster=args.no_cluster, + wait=wait, + timeout=timeout, + ) elif args.action == "remove": if args.cluster: remove_cluster(args.Deckfile, ignore_cluster=args.no_cluster) diff --git a/getdeck/deckfile/fetch/deck_fetcher.py b/getdeck/deckfile/fetch/deck_fetcher.py new file mode 100644 index 0000000..5840b8b --- /dev/null +++ b/getdeck/deckfile/fetch/deck_fetcher.py @@ -0,0 +1,129 @@ +from abc import ABC, abstractmethod +import os +from pydantic import BaseModel +import logging +import shutil +import tempfile + +import requests +from git import Repo, GitError + +from getdeck import configuration + +logger = logging.getLogger("deck") + + +class FetchError(Exception): + pass + + +class DeckFileData(BaseModel): + argument_location: str + cwd: str = os.getcwd() + path: str = None + name: str = configuration.DECKFILE_FILE + working_dir_path: str = None + is_temp_dir: bool = False + + +class DeckFetchBehavior(ABC): + @abstractmethod + def fetch(self, data: DeckFileData) -> DeckFileData: + pass + + @abstractmethod + def clean_up(self, data: DeckFileData): + pass + + +class Git(DeckFetchBehavior): + def fetch(self, data: DeckFileData) -> DeckFileData: + location = data.argument_location + + if "#" in location: + ref, rev = location.split("#") + else: + ref = location + rev = "HEAD" + + tmp_dir = tempfile.mkdtemp() + data.path = tmp_dir + data.working_dir_path = tmp_dir + data.is_temp_dir = True + + try: + repo = Repo.clone_from(ref, tmp_dir) + repo.git.checkout(rev) + except GitError as e: + self.clean_up(data=data) + raise FetchError(f"Cannot checkout {rev} from {ref}: {e}") + except Exception as e: + self.clean_up(data=data) + raise e + + return data + + def clean_up(self, data: DeckFileData): + shutil.rmtree(data.working_dir_path) + + +class Http(DeckFetchBehavior): + def fetch(self, data: DeckFileData) -> DeckFileData: + location = data.argument_location + + download = tempfile.NamedTemporaryFile(delete=False) + data.path = os.path.dirname(download.name) + data.name = os.path.basename(download.name) + + try: + logger.debug(f"Requesting {location}") + with requests.get(location, stream=True, timeout=10.0) as res: + res.raise_for_status() + for chunk in res.iter_content(chunk_size=4096): + if chunk: + download.write(chunk) + download.flush() + download.close() + except Exception as e: + download.close() + self.clean_up(data=data) + raise FetchError( + f"Cannot download Deckfile from http(s) location {location}: {e}" + ) + + return data + + def clean_up(self, data: DeckFileData): + os.remove(os.path.join(data.path, data.name)) + + +class DeckFetcher: + def __init__(self, fetch_behavior: DeckFetchBehavior) -> None: + self._fetch_behavior = fetch_behavior + + @property + def fetch_behavior(self) -> DeckFetchBehavior: + return self._fetch_behavior + + @fetch_behavior.setter + def fetch_behavior(self, fetch_behavior: DeckFetchBehavior) -> None: + self._fetch_behavior = fetch_behavior + + def fetch(self, data: DeckFileData) -> DeckFileData: + data = self._fetch_behavior.fetch(data=data) + return data + + +def select_fetch_behavior(location: str) -> DeckFetchBehavior | None: + if "#" in location: + location, _ = location.split("#") + + location_lo = location.lower() + + if location_lo.startswith("git") or location_lo.endswith(".git"): + return Git() + + if location_lo.startswith("https") or location_lo.startswith("http"): + return Http() + + return None diff --git a/getdeck/deckfile/fetch/utils.py b/getdeck/deckfile/fetch/utils.py new file mode 100644 index 0000000..80272a7 --- /dev/null +++ b/getdeck/deckfile/fetch/utils.py @@ -0,0 +1,33 @@ +import os +from typing import Tuple + +from getdeck import configuration + + +def get_path_and_name(location: str) -> Tuple[str, str]: + # None + if location is None: + location = "" + + # "~" + if location.startswith("~"): + location = os.path.expanduser(location) + + # ".", "" + if location in [".", ""]: + for extension in [".yaml", ".yml"]: + location_default = os.path.join( + os.getcwd(), + os.path.splitext(configuration.DECKFILE_FILE)[0] + extension, + ) + if os.path.isfile(location_default): + location = location_default + break + else: + location = os.path.join(os.getcwd(), configuration.DECKFILE_FILE) + + name = os.path.basename(location) + dirname = os.path.dirname(location) + path = os.path.abspath(dirname) + + return path, name diff --git a/getdeck/utils.py b/getdeck/utils.py index 52b95f6..82b6fc6 100644 --- a/getdeck/utils.py +++ b/getdeck/utils.py @@ -1,21 +1,24 @@ import logging import os -import shutil import subprocess -import tempfile from time import sleep from typing import Optional, Tuple -import requests -from git import Repo, GitError from semantic_version import Version -from getdeck import configuration from getdeck.configuration import ClientConfiguration +from getdeck.deckfile.fetch.deck_fetcher import ( + DeckFetcher, + DeckFileData, + select_fetch_behavior, +) +from getdeck.deckfile.fetch.utils import get_path_and_name from getdeck.deckfile.file import Deckfile from getdeck.provider.abstract import AbstractProvider from getdeck.provider.errors import NotSupportedError from getdeck.provider.types import ProviderType +from getdeck.deckfile.selector import deckfile_selector + logger = logging.getLogger("deck") @@ -36,76 +39,42 @@ def sniff_protocol(ref: str): def read_deckfile_from_location( - location: str, config: ClientConfiguration + location: str, *args, **kwargs ) -> Tuple[Deckfile, Optional[str], bool]: - protocol = sniff_protocol(location) logger.info(f"Reading Deckfile from: {location}") - if location == ".": - # load default file from this location - deckfile_location = os.path.join(os.getcwd(), configuration.DECKFILE_FILE) - if os.path.isfile(deckfile_location): - logger.debug("Is file location") - return ( - config.deckfile_selector.get(deckfile_location), - os.path.dirname(deckfile_location), - False, - ) - else: - raise RuntimeError(f"Cannot identify {location} as Deckfile") - elif protocol == "git": - if "#" in location: - ref, rev = location.split("#") - else: - ref = location - rev = "HEAD" - tmp_dir = tempfile.mkdtemp() - try: - repo = Repo.clone_from(ref, tmp_dir) - repo.git.checkout(rev) - deckfile = config.deckfile_selector.get( - os.path.join(tmp_dir, configuration.DECKFILE_FILE) - ) - return deckfile, tmp_dir, True - except GitError as e: - shutil.rmtree(tmp_dir) - raise RuntimeError(f"Cannot checkout {rev} from {ref}: {e}") - except Exception as e: - shutil.rmtree(tmp_dir) - raise e - elif protocol in ["http", "https"]: - download = tempfile.NamedTemporaryFile(delete=False) - try: - logger.debug(f"Requesting {location}") - with requests.get(location, stream=True, timeout=10.0) as res: - res.raise_for_status() - for chunk in res.iter_content(chunk_size=4096): - if chunk: - download.write(chunk) - download.flush() - download.close() - deckfile = config.deckfile_selector.get(download.name) - os.remove(download.name) - return deckfile, None, False - except Exception as e: - download.close() - os.remove(download.name) - raise RuntimeError( - f"Cannot read Deckfile from http(s) location {location}: {e}" - ) - elif protocol in (None, "local"): - # this is probably a file system location - if os.path.isfile(location): - logger.debug("Is file location") - return ( - config.deckfile_selector.get(location), - os.path.dirname(location), - False, - ) - else: - raise RuntimeError(f"Cannot identify {location} as Deckfile") + # fetch + data = DeckFileData(argument_location=location) + fetch_behavior = select_fetch_behavior(location=location) + if fetch_behavior: + deck_fetcher = DeckFetcher(fetch_behavior=fetch_behavior) + data = deck_fetcher.fetch(data=data) else: - raise RuntimeError("Cannot read Deckfile") + # local path and name + path, name = get_path_and_name(location=location) + data.path = path + data.name = name + data.working_dir_path = os.path.dirname(location) + + # validate (error flag used to raise exception after clean up) + error = False + file = os.path.join(data.path, data.name) + if not os.path.isfile(file): + error = True + + # parse + if not error: + deckfile = deckfile_selector.get(file) + + # clean up + if fetch_behavior: + fetch_behavior.clean_up(data=data) + + # error + if error: + raise RuntimeError(f"Cannot identify {location} as Deckfile") + + return deckfile, data.working_dir_path, data.is_temp_dir def ensure_cluster( diff --git a/test/src/test_deck_fetch_behavior.py b/test/src/test_deck_fetch_behavior.py new file mode 100644 index 0000000..7cc5782 --- /dev/null +++ b/test/src/test_deck_fetch_behavior.py @@ -0,0 +1,80 @@ +import os +from unittest import TestCase +from getdeck import configuration +from getdeck.deckfile.fetch.deck_fetcher import DeckFileData, FetchError, Git, Http + + +class GitTest(TestCase): + def test_git(self): + data = DeckFileData(argument_location="git@github.com:Getdeck/getdeck.git") + + fetch_behavior = Git() + data = fetch_behavior.fetch(data=data) + + self.assertTrue(os.path.isdir(data.path)) + self.assertIsNotNone(data.working_dir_path) + self.assertEqual(data.name, configuration.DECKFILE_FILE) + + fetch_behavior.clean_up(data=data) + self.assertFalse(os.path.isdir(data.working_dir_path)) + + def test_branch(self): + data = DeckFileData(argument_location="git@github.com:Getdeck/getdeck.git#main") + + fetch_behavior = Git() + data = fetch_behavior.fetch(data=data) + + self.assertTrue(os.path.isdir(data.path)) + self.assertIsNotNone(data.working_dir_path) + self.assertEqual(data.name, configuration.DECKFILE_FILE) + + fetch_behavior.clean_up(data=data) + self.assertFalse(os.path.isdir(data.working_dir_path)) + + def test_branch_invalid(self): + data = DeckFileData( + argument_location="git@github.com:Getdeck/getdeck.git#invalid" + ) + + fetch_behavior = Git() + with self.assertRaises(FetchError): + data = fetch_behavior.fetch(data=data) + + def test_https(self): + data = DeckFileData(argument_location="https://github.com/Getdeck/getdeck.git") + + fetch_behavior = Git() + data = fetch_behavior.fetch(data=data) + + self.assertTrue(os.path.isdir(data.path)) + self.assertIsNotNone(data.working_dir_path) + self.assertEqual(data.name, configuration.DECKFILE_FILE) + + fetch_behavior.clean_up(data=data) + self.assertFalse(os.path.isdir(data.working_dir_path)) + + +class HttpTest(TestCase): + def test_default(self): + data = DeckFileData( + argument_location="https://raw.githubusercontent.com/Getdeck/getdeck/main/test/deckfile/deck.empty.yaml" + ) + + fetch_behavior = Http() + data = fetch_behavior.fetch(data=data) + + self.assertTrue(os.path.isdir(data.path)) + self.assertIsNone(data.working_dir_path) + self.assertIsNotNone(data.name) + + fetch_behavior.clean_up(data=data) + self.assertFalse(os.path.isfile(os.path.join(data.path, data.name))) + + def test_url_invalid(self): + data = DeckFileData( + argument_location="https://raw.githubusercontent.com/Getdeck/getdeck/invalid/deck.yaml" + ) + + fetch_behavior = Http() + with self.assertRaises(FetchError): + _ = fetch_behavior.fetch(data=data) diff --git a/test/src/test_deck_fetch_utils.py b/test/src/test_deck_fetch_utils.py new file mode 100644 index 0000000..535d96a --- /dev/null +++ b/test/src/test_deck_fetch_utils.py @@ -0,0 +1,90 @@ +import os +from unittest import TestCase +from getdeck import configuration +from getdeck.deckfile.fetch.utils import get_path_and_name + + +class GetPathAndNameTest(TestCase): + def test_name_default(self): + location = configuration.DECKFILE_FILE + path, name = get_path_and_name(location=location) + + self.assertEqual(path, os.getcwd()) + self.assertEqual(name, configuration.DECKFILE_FILE) + + def test_name_custom(self): + location = "deck.empty.yaml" + path, name = get_path_and_name(location=location) + + self.assertEqual(path, os.getcwd()) + self.assertEqual(name, "deck.empty.yaml") + + def test_name_yaml(self): + location = "deck.yaml" + path, name = get_path_and_name(location=location) + + self.assertEqual(path, os.getcwd()) + self.assertEqual(name, "deck.yaml") + + def test_name_yml(self): + location = "deck.yml" + path, name = get_path_and_name(location=location) + + self.assertEqual(path, os.getcwd()) + self.assertEqual(name, "deck.yml") + + def test_path_relative(self): + location = "./deck.yaml" + path, name = get_path_and_name(location=location) + + self.assertEqual(path, os.getcwd()) + self.assertEqual(name, "deck.yaml") + + def test_path_relative_subfolder(self): + location = "./path/deck.yaml" + path, name = get_path_and_name(location=location) + + self.assertEqual(path, os.path.join(os.getcwd(), "path")) + self.assertEqual(name, "deck.yaml") + + def test_path_relative_parentfolder(self): + location = "../deck.yaml" + path, name = get_path_and_name(location=location) + + self.assertEqual(path, os.path.dirname(os.getcwd())) + self.assertEqual(name, "deck.yaml") + + def test_path_user(self): + location = "~/deck.yaml" + path, name = get_path_and_name(location=location) + + self.assertEqual(path, os.path.expanduser("~")) + self.assertEqual(name, "deck.yaml") + + def test_path_user_subfolder(self): + location = "~/path/deck.yaml" + path, name = get_path_and_name(location=location) + + self.assertEqual(path, os.path.join(os.path.expanduser("~"), "path")) + self.assertEqual(name, "deck.yaml") + + def test_dot(self): + location = "." + path, name = get_path_and_name(location=location) + + self.assertEqual(path, os.getcwd()) + self.assertEqual(name, "deck.yaml") + + def test_empty(self): + location = "" + path, name = get_path_and_name(location=location) + + self.assertEqual(path, os.getcwd()) + self.assertEqual(name, "deck.yaml") + + def test_none(self): + location = None + path, name = get_path_and_name(location=location) + + self.assertEqual(path, os.getcwd()) + self.assertEqual(name, "deck.yaml") diff --git a/test/src/test_deck_fetcher.py b/test/src/test_deck_fetcher.py new file mode 100644 index 0000000..2cd1989 --- /dev/null +++ b/test/src/test_deck_fetcher.py @@ -0,0 +1,47 @@ +from unittest import TestCase +from getdeck.deckfile.fetch.deck_fetcher import ( + DeckFetcher, + DeckFileData, + Git, + Http, + select_fetch_behavior, +) + + +class SelectFetchBehaviorTest(TestCase): + def test_git(self): + fetch_behavior = select_fetch_behavior( + location="git@github.com:Getdeck/getdeck.git" + ) + self.assertIsInstance(fetch_behavior, Git) + + def test_git_https(self): + fetch_behavior = select_fetch_behavior( + location="https://github.com/Getdeck/getdeck.git" + ) + self.assertIsInstance(fetch_behavior, Git) + + def test_https(self): + fetch_behavior = select_fetch_behavior( + location="https://raw.githubusercontent.com/Getdeck/getdeck/main/test/deckfile/deck.empty.yaml" + ) + self.assertIsInstance(fetch_behavior, Http) + + def test_local_dot(self): + fetch_behavior = select_fetch_behavior(location=".") + self.assertIsNone(fetch_behavior) + + def test_local_path(self): + fetch_behavior = select_fetch_behavior(location="./test/deck.yaml") + self.assertIsNone(fetch_behavior) + + +class DeckFetcherTest(TestCase): + def test_default(self): + location = "git@github.com:Getdeck/getdeck.git" + + data = DeckFileData(argument_location=location) + fetch_behavior = select_fetch_behavior(location=location) + deck_fetcher = DeckFetcher(fetch_behavior=fetch_behavior) + data = deck_fetcher.fetch(data=data) + fetch_behavior.clean_up(data=data) diff --git a/test/src/test_deckfile.py b/test/src/test_deckfile.py new file mode 100644 index 0000000..e448e69 --- /dev/null +++ b/test/src/test_deckfile.py @@ -0,0 +1,23 @@ +from unittest import TestCase +from getdeck.utils import read_deckfile_from_location + + +class DeckFileLocationTest(TestCase): + def test_local(self): + location = "./test/deckfile/deck.empty.yaml" + deckfile, working_dir_path, is_temp_dir = read_deckfile_from_location(location) + self.assertIsNotNone(deckfile) + self.assertEqual(working_dir_path, "./test/deckfile") + self.assertFalse(is_temp_dir) + + def test_git_with_no_deckfile(self): + location = "git@github.com:Getdeck/getdeck.git" + with self.assertRaises(RuntimeError): + _ = read_deckfile_from_location(location) + + def test_https(self): + location = "https://raw.githubusercontent.com/Getdeck/getdeck/main/test/deckfile/deck.empty.yaml" + deckfile, working_dir_path, is_temp_dir = read_deckfile_from_location(location) + self.assertIsNotNone(deckfile) + self.assertIsNone(working_dir_path) + self.assertFalse(is_temp_dir) diff --git a/test/test_deckfile.py b/test/test_deckfile.py deleted file mode 100644 index 6f832ce..0000000 --- a/test/test_deckfile.py +++ /dev/null @@ -1,14 +0,0 @@ -from unittest import TestCase -from getdeck.configuration import default_configuration -from getdeck.utils import read_deckfile_from_location - - -class DeckFileLocationTest(TestCase): - def test_local(self): - location = "./test/deckfile/deck.empty.yaml" - deckfile, working_dir_path, is_temp_dir = read_deckfile_from_location( - location, default_configuration - ) - self.assertIsNotNone(deckfile) - self.assertEqual(working_dir_path, "./test/deckfile") - self.assertFalse(is_temp_dir) From 20b78123eae80b53893cd4c27c4c7414939f3033 Mon Sep 17 00:00:00 2001 From: Christian Busch Date: Fri, 7 Oct 2022 16:53:55 +0200 Subject: [PATCH 2/4] fix: test gefyra demo --- getdeck/api/get.py | 5 ++++- getdeck/api/hosts.py | 6 +++++- getdeck/api/list.py | 6 +++++- getdeck/api/remove.py | 10 ++++++++-- getdeck/api/stop.py | 6 +++++- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/getdeck/api/get.py b/getdeck/api/get.py index 2ed0e70..f9ecba3 100644 --- a/getdeck/api/get.py +++ b/getdeck/api/get.py @@ -1,4 +1,5 @@ import logging +import os import shutil from typing import Callable @@ -128,8 +129,10 @@ def run_deck( # noqa: C901 if notes := deckfile.get_deck(deck_name).notes: logger.info(notes) - if is_temp_dir: + # TODO: refactor/remove? + if is_temp_dir and os.path.isdir(working_dir_path): shutil.rmtree(working_dir_path) + if wait: _wait_ready(config, generated_deck, timeout) return True diff --git a/getdeck/api/hosts.py b/getdeck/api/hosts.py index d29b978..ad28261 100644 --- a/getdeck/api/hosts.py +++ b/getdeck/api/hosts.py @@ -1,4 +1,5 @@ import logging +import os import shutil import socket @@ -53,8 +54,11 @@ def run_hosts( logger.error(f"Unknown host action '{host_action}'") else: logger.info("No hosts specified in Deckfile") - if is_temp_dir: + + # TODO: refactor/remove? + if is_temp_dir and os.path.isdir(working_dir_path): shutil.rmtree(working_dir_path) + return True diff --git a/getdeck/api/list.py b/getdeck/api/list.py index 7211a39..cb682dd 100644 --- a/getdeck/api/list.py +++ b/getdeck/api/list.py @@ -1,4 +1,5 @@ import logging +import os import shutil from typing import List @@ -17,6 +18,9 @@ def get_available_decks(deckfile_location: str, config=default_configuration) -> ) available_decks = deckfile.get_decks() logger.debug(available_decks) - if is_temp_dir: + + # TODO: refactor/remove? + if is_temp_dir and os.path.isdir(working_dir_path): shutil.rmtree(working_dir_path) + return available_decks diff --git a/getdeck/api/remove.py b/getdeck/api/remove.py index cef0cb7..cd52f26 100644 --- a/getdeck/api/remove.py +++ b/getdeck/api/remove.py @@ -1,4 +1,5 @@ import logging +import os import shutil from typing import Callable @@ -25,8 +26,11 @@ def remove_cluster( k8s_provider.delete() else: logger.info("Cluster does not exist") - if is_temp_dir: + + # TODO: refactor/remove? + if is_temp_dir and os.path.isdir(working_dir_path): shutil.rmtree(working_dir_path) + return True @@ -83,6 +87,8 @@ def remove_deck( else: logger.info("Cluster does not exist") - if is_temp_dir: + # TODO: refactor/remove? + if is_temp_dir and os.path.isdir(working_dir_path): shutil.rmtree(working_dir_path) + return True diff --git a/getdeck/api/stop.py b/getdeck/api/stop.py index b4c839a..69b55fc 100644 --- a/getdeck/api/stop.py +++ b/getdeck/api/stop.py @@ -1,4 +1,5 @@ import logging +import os import shutil from typing import Callable @@ -22,6 +23,9 @@ def stop_cluster( ) k8s_provider = ensure_cluster(deckfile, config, ignore_cluster, do_install=False) logger.info("Stopping cluster") - if is_temp_dir: + + # TODO: refactor/remove? + if is_temp_dir and os.path.isdir(working_dir_path): shutil.rmtree(working_dir_path) + k8s_provider.stop() From 1a7ca1d5034a6aabf0c763abadfb412ef0292592 Mon Sep 17 00:00:00 2001 From: Christian Busch Date: Fri, 7 Oct 2022 17:08:01 +0200 Subject: [PATCH 3/4] fix: add ssh agent for testing --- .github/workflows/python-test.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/python-test.yaml b/.github/workflows/python-test.yaml index 4b19f39..32da56f 100644 --- a/.github/workflows/python-test.yaml +++ b/.github/workflows/python-test.yaml @@ -9,6 +9,12 @@ jobs: steps: - uses: actions/checkout@v2 + - name: ssh agent + uses: webfactory/ssh-agent@v0.5.4 + with: + ssh-private-key: | + ${{ secrets.SSH_KEY_OF_GETDECK }} + - name: Setup Python uses: actions/setup-python@v2 with: From 6ee4164c3ba135b9039c2a4ef0fecb9f3f7fa0c5 Mon Sep 17 00:00:00 2001 From: Christian Busch Date: Fri, 7 Oct 2022 17:32:36 +0200 Subject: [PATCH 4/4] fix: increase try it yourself example timeout --- .github/workflows/python-test-gefyra.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-test-gefyra.yaml b/.github/workflows/python-test-gefyra.yaml index 138e69a..af5a6f0 100644 --- a/.github/workflows/python-test-gefyra.yaml +++ b/.github/workflows/python-test-gefyra.yaml @@ -10,7 +10,7 @@ on: jobs: test: runs-on: ubuntu-latest - timeout-minutes: 5 + timeout-minutes: 10 steps: - uses: actions/checkout@v2 - name: Set up Python