diff --git a/.github/workflows/makefile.yml b/.github/workflows/makefile.yml index 838ec5b..6556e92 100644 --- a/.github/workflows/makefile.yml +++ b/.github/workflows/makefile.yml @@ -1,6 +1,10 @@ name: Makefile CI -on: ["push", "pull_request"] +on: + push: + branches: [ main ] + pull_request: + types: [ opened, synchronize, reopened, closed ] jobs: build: diff --git a/2dc4491c-fa27-4c5e-bd0c-71951b3ef0e5.png b/2dc4491c-fa27-4c5e-bd0c-71951b3ef0e5.png new file mode 100644 index 0000000..5224907 Binary files /dev/null and b/2dc4491c-fa27-4c5e-bd0c-71951b3ef0e5.png differ diff --git a/Makefile b/Makefile index 187abf2..a0c0018 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,6 @@ test: testint: bash demo.sh 0to100 && bash demo.sh 0to100_sb - format: black zero_to_one_hundred @@ -15,3 +14,5 @@ lint: pylint --disable=C0116,C0115,W0702,C0114,C0301,C0103,C0209,R0913,R0902,R0903,E1101,W0612,W0718,R0801,W0150,W0613 zero_to_one_hundred refactor: format lint + +pr: format lint test testint install diff --git a/README.md b/README.md index 1756c0f..f35f13d 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,7 @@ and you have a `toc.md` for free to use as your index (bookmark it) > as I use myself Lorenzo's great utility `safaribooks` I added some code to convert the downloaded epub contents into a related pdf and split that in chunks so I can easily use it on ipad or better remarkable for studying and later sync back in a repo for hands-on code... they call that **learning by doing** 🖖🏻 example: +![](2dc4491c-fa27-4c5e-bd0c-71951b3ef0e5.png) ![](z05502bb-4b90-422f-9624-568d9f02cd01.png) ### tools diff --git a/demo.sh b/demo.sh index 38e6caa..b210fcb 100644 --- a/demo.sh +++ b/demo.sh @@ -32,16 +32,20 @@ function 0to100 { setup0to100 ./main.py help - - url=https://cloud.google.com/docs/ - ./main.py create_section "$url" - - url=https://docs.getdbt.com/docs/introduction - ./main.py create_section "$url" - - url=https://cloud.google.com/docs/ - ./main.py done_section "$url" - +content=$(cat << 'EOF' +https://www.cloudskillsboost.google/paths/16 +https://www.cloudskillsboost.google/games/4424/labs/28651 +https://www.cloudskillsboost.google/course_templates/3 +https://www.cloudskillsboost.google/games/4422 +https://storage.googleapis.com/cloud-training/cls-html5-courses/T-BQRS-I/M1/index.html + +EOF +) +while IFS= read -r section || [[ -n "$section" ]]; do + ./main.py create_section "$section" +done <<< "$content" + + ls -1R 0to100 } diff --git a/zero_to_one_hundred/configs/a_config_map.py b/zero_to_one_hundred/configs/a_config_map.py index a3bb83c..aae0321 100644 --- a/zero_to_one_hundred/configs/a_config_map.py +++ b/zero_to_one_hundred/configs/a_config_map.py @@ -1,7 +1,7 @@ # pylint: disable=W0246 import os from abc import ABC -from enum import Enum +from dataclasses import dataclass from zero_to_one_hundred.exceptions.errors import SomeError from zero_to_one_hundred.repository.a_persist_fs import APersistFS @@ -10,14 +10,18 @@ class AConfigMap(ABC): MAP_YAML_PATH = "MAP_YAML_PATH" - class SUPPORTED_EXTRA_MAP(Enum): - gcp = 1 - datacamp = 2 + @dataclass + class LegendIcons: + name: str + icon: str + regex: str def __init__(self, persist_fs: APersistFS): self.map_yaml_path = os.getenv(AConfigMap.MAP_YAML_PATH) if self.map_yaml_path is None: - raise SomeError(f"map_yaml_path {self.map_yaml_path} is not valid") + raise SomeError( + f"map_yaml_path {self.map_yaml_path} is not valid, please set it in the env" + ) self.persist_fs = persist_fs def __repr__(self): @@ -32,3 +36,32 @@ def load(self): @property def get_type(self): return self.load["type"] + + @property + def get_legend_icons(self): + legend = self.load.get("legend") + if legend: + return [ + AConfigMap.LegendIcons( + name=icon_data["name"], + icon=icon_data["icon"], + regex=icon_data["regex"], + ) + for icon_data in legend.get("icons", []) + if isinstance(icon_data, dict) + ] + return [] + + @property + def get_legend_type(self) -> str | None: + return ( + None + if self.load.get("legend") is None + else self.load.get("legend").get("type") + ) + + @property + def get_legend_icons_as_md(self): + icons = self.get_legend_icons + res = [f"`{i.name}` {i.icon}" for i in icons] + return "" if res == [] else "**legend_icons**\n" + "\n".join(res) diff --git a/zero_to_one_hundred/configs/ztoh_config_map.py b/zero_to_one_hundred/configs/ztoh_config_map.py index 055428f..5832022 100644 --- a/zero_to_one_hundred/configs/ztoh_config_map.py +++ b/zero_to_one_hundred/configs/ztoh_config_map.py @@ -19,7 +19,3 @@ def get_repo_map_md(self): @property def get_repo_sorted(self) -> bool: return self.load["repo"].get("sorted") - - @property - def get_repo_legend_type(self) -> str | None: - return self.load["repo"].get("legend_type") diff --git a/zero_to_one_hundred/models/map.py b/zero_to_one_hundred/models/map.py index 435c08d..0dc5f5f 100644 --- a/zero_to_one_hundred/models/map.py +++ b/zero_to_one_hundred/models/map.py @@ -1,6 +1,5 @@ from typing import List -from zero_to_one_hundred.configs.a_config_map import AConfigMap from zero_to_one_hundred.configs.ztoh_config_map import ZTOHConfigMap from zero_to_one_hundred.models.section import Section from zero_to_one_hundred.repository.ztoh_persist_fs import ZTOHPersistFS @@ -26,14 +25,13 @@ def __repr__(self): return f"Map {str(self.sections)}" def get_sections(self): - - res :List[Section] = self.sections + res: List[Section] = self.sections if self.config_map.get_repo_sorted == "abc": - print('*** abc') - res= sorted(self.sections, key=lambda s: s.dir_name) + print("*** abc") + res = sorted(self.sections, key=lambda s: s.dir_name) if self.config_map.get_repo_sorted == "00:00:00": - print('*** 00:00:00') - res = sorted(self.sections, key=lambda s: s.get_readme_md_time()) + print("*** 00:00:00") + res = sorted(self.sections, key=lambda s: s.get_readme_md_time()) return res def asMarkDown(self) -> str: @@ -42,30 +40,9 @@ def asMarkDown(self) -> str: def get_legend_as_md(self): txt: str = """ ## legend: - - | footprints | completed | - |---|---| - | :footprints: | :green_heart: | """ txt += lf_char - - match self.config_map.get_repo_legend_type: - case AConfigMap.SUPPORTED_EXTRA_MAP.gcp.name: - txt += """ - > extra - > - | quest | lab | template | game | course | - |---|---|---|----|---| - | :cyclone: | :floppy_disk: | :whale: | :snake: | :pushpin: |""".strip() - case AConfigMap.SUPPORTED_EXTRA_MAP.datacamp.name: - txt += """ - > extra - > - | projects | tutorial | course | - |---|---|---| - | :cyclone: | :floppy_disk: | :whale: |""".strip() - case _: - txt += lf_char + txt += self.config_map.get_legend_icons_as_md return txt txt = f"""{f"# map {self.readme_md}, {len(self.sections)}"} diff --git a/zero_to_one_hundred/models/section.py b/zero_to_one_hundred/models/section.py index 37683e6..2280de1 100644 --- a/zero_to_one_hundred/models/section.py +++ b/zero_to_one_hundred/models/section.py @@ -1,6 +1,6 @@ # pylint: disable= R0904 +import re -from zero_to_one_hundred.configs.a_config_map import AConfigMap from zero_to_one_hundred.configs.ztoh_config_map import ZTOHConfigMap from zero_to_one_hundred.models.readme_md import ReadMeMD from zero_to_one_hundred.repository.ztoh_persist_fs import ZTOHPersistFS @@ -46,7 +46,7 @@ def asMarkDown(self): + self.dir_readme_md + ")" + self.get_done_as_md - + self.get_format_as_md + + self.get_matching_icon_as_md ) @property @@ -55,7 +55,7 @@ def get_http_url(self): @property def get_done_as_md(self): - return " :green_heart:" if self.is_done else " :footprints:" + return "`done`" if self.is_done else "`wip`" @property def get_dir_name(self): @@ -86,9 +86,7 @@ def write_done_section(self): ) def get_readme_md_time(self): - return self.persist_fs.get_biz_ts( - self.dir_readme_md - ) + return self.persist_fs.get_biz_ts(self.dir_readme_md) @classmethod def from_http_url_to_dir_to(cls, dir_name): @@ -215,31 +213,11 @@ def is_datacamp_course(self): return "courses" in self.http_url and "app.datacamp.com" in self.http_url @property - def get_format_as_md(self): - a = [] - match self.config_map.get_repo_legend_type: - case AConfigMap.SUPPORTED_EXTRA_MAP.gcp.name: - a = [ - ":cyclone:" if self.is_gcp_quest else None, - ":floppy_disk:" if self.is_gcp_lab else None, - ":whale:" if self.is_gcp_template else None, - ":snake:" if self.is_gcp_game else None, - ":pushpin:", - ] - case AConfigMap.SUPPORTED_EXTRA_MAP.datacamp.name: - a = [ - ":cyclone:" if self.is_datacamp_project else None, - ":floppy_disk:" if self.is_datacamp_tutorial else None, - ":whale:" if self.is_datacamp_course else None, - ":pushpin:", - ] - case _: - a = [] - try: - res = next(item for item in a if item is not None) - except StopIteration: - return "" - return res + def get_matching_icon_as_md(self): + icons = self.config_map.get_legend_icons + + res = [i.icon for i in icons if re.search(i.regex, self.http_url)] + return " ".join(res) def __eq__(self, other): if other is self: diff --git a/zero_to_one_hundred/repository/ztoh_persist_fs.py b/zero_to_one_hundred/repository/ztoh_persist_fs.py index 64a4091..854715a 100644 --- a/zero_to_one_hundred/repository/ztoh_persist_fs.py +++ b/zero_to_one_hundred/repository/ztoh_persist_fs.py @@ -34,7 +34,6 @@ def done_section_status(cls, abs_repo_path, path): @classmethod def get_biz_ts(cls, path): - # print(f"path {path}") exists = os.path.exists(path) # print(f"exists {exists}") diff --git a/zero_to_one_hundred/runner.py b/zero_to_one_hundred/runner.py index 993f5fd..7c846fb 100644 --- a/zero_to_one_hundred/runner.py +++ b/zero_to_one_hundred/runner.py @@ -3,6 +3,7 @@ import traceback from typing import List +from zero_to_one_hundred.exceptions.errors import SomeError from zero_to_one_hundred.factories.a_factory import AFactory from zero_to_one_hundred.factories.a_factory_provider import AFactoryProvider @@ -19,7 +20,12 @@ def run_core(argv: List[str], factory_provider: AFactoryProvider): try: factory = factory_provider.provide() [processor.process() for processor in factory.get_processor(argv) if processor] - + except SomeError as se: + print(se) + return + except FileNotFoundError as se: + print(se) + return except Exception as e: print(e) traceback.print_exc() diff --git a/zero_to_one_hundred/tests/test_ztoh/resources/datacamp_map.yaml b/zero_to_one_hundred/tests/test_ztoh/resources/datacamp_map.yaml index 19e831b..c4950eb 100644 --- a/zero_to_one_hundred/tests/test_ztoh/resources/datacamp_map.yaml +++ b/zero_to_one_hundred/tests/test_ztoh/resources/datacamp_map.yaml @@ -2,4 +2,15 @@ type: ztoh-map repo: path: "./0to100" map_md: "toc.md" - legend_type: "datacamp" +legend: + type: "datacamp" + icons: + - name: Project + icon: ":cyclone:" + regex: "project" + - name: Tutorial + icon: ":floppy_disk:" + regex: "tutorial" + - name: Course + icon: ":whale:" + regex: "course" diff --git a/zero_to_one_hundred/tests/test_ztoh/resources/gcp_map.yaml b/zero_to_one_hundred/tests/test_ztoh/resources/gcp_map.yaml index 83531b4..d2a5b91 100644 --- a/zero_to_one_hundred/tests/test_ztoh/resources/gcp_map.yaml +++ b/zero_to_one_hundred/tests/test_ztoh/resources/gcp_map.yaml @@ -2,5 +2,23 @@ type: ztoh-map repo: path: "./0to100" map_md: "toc.md" - legend_type: "gcp" - sorted: "abc" # oder alph \ No newline at end of file +legend: + type: "gcp" + icons: + - name: Path + icon: ":cyclone:" + regex: "path" + - name: Lab + icon: ":floppy_disk:" + regex: "lab" + - name: Template + icon: ":whale:" + regex: "template" + - name: Game + icon: ":snake:" + regex: "game" + - name: Course + icon: ":pushpin:" + regex: "course" + +sorted: "abc" # oder alph diff --git a/zero_to_one_hundred/tests/test_ztoh/test_map.py b/zero_to_one_hundred/tests/test_ztoh/test_map.py index dad553f..72057e1 100644 --- a/zero_to_one_hundred/tests/test_ztoh/test_map.py +++ b/zero_to_one_hundred/tests/test_ztoh/test_map.py @@ -26,12 +26,8 @@ def test_asMarkDown( # map toc.md, 2 ## legend: -| footprints | completed | -|---|---| -| :footprints: | :green_heart: | - -1.[`here`](./0to100/https§§§cloud.google.com§zzz/readme.md) :footprints: -1.[`here`](./0to100/https§§§cloud.google.com§abc/readme.md) :footprints: +1.[`here`](./0to100/https§§§cloud.google.com§zzz/readme.md) `wip` +1.[`here`](./0to100/https§§§cloud.google.com§abc/readme.md) `wip` """ assert str_relaxed(current) == str_relaxed(expected) @@ -56,13 +52,9 @@ def test_asMarkDown_0( # map toc.md, 3 ## legend: -| footprints | completed | -|---|---| -| :footprints: | :green_heart: | - -1.[`here`](./0to100/https§§§cloud.google.com§abc/readme.md) :footprints: -1.[`here`](./0to100/https§§§cloud.google.com§efg/readme.md) :footprints: -1.[`here`](./0to100/https§§§cloud.google.com§zzz/readme.md) :footprints: +1.[`here`](./0to100/https§§§cloud.google.com§abc/readme.md) `wip` +1.[`here`](./0to100/https§§§cloud.google.com§efg/readme.md) `wip` +1.[`here`](./0to100/https§§§cloud.google.com§zzz/readme.md) `wip` """ assert str_relaxed(current) == str_relaxed(expected) @@ -88,13 +80,9 @@ def test_asMarkDown_1( # map toc.md, 3 ## legend: -| footprints | completed | -|---|---| -| :footprints: | :green_heart: | - -1.[`here`](./0to100/https§§§cloud.google.com§abc/readme.md) :footprints: -1.[`here`](./0to100/https§§§cloud.google.com§zzz/readme.md) :footprints: -1.[`here`](./0to100/https§§§cloud.google.com§efg/readme.md) :footprints: +1.[`here`](./0to100/https§§§cloud.google.com§abc/readme.md) `wip` +1.[`here`](./0to100/https§§§cloud.google.com§zzz/readme.md) `wip` +1.[`here`](./0to100/https§§§cloud.google.com§efg/readme.md) `wip` """ diff --git a/zero_to_one_hundred/tests/test_ztoh/test_section.py b/zero_to_one_hundred/tests/test_ztoh/test_section.py index bff60cd..55b5041 100644 --- a/zero_to_one_hundred/tests/test_ztoh/test_section.py +++ b/zero_to_one_hundred/tests/test_ztoh/test_section.py @@ -3,6 +3,7 @@ from pyfakefs.fake_filesystem_unittest import Patcher from zero_to_one_hundred.models.section import Section +from zero_to_one_hundred.tests.conftest import str_relaxed def test_init(get_config_map, persist_fs, process_fs, http_url_1): @@ -89,13 +90,12 @@ def test_gcp_get_format_as_md(get_gcp_config_map, persist_fs, process_fs): actual = Section.build_from_dir( persist_fs, process_fs, get_gcp_config_map, http_url ) - assert actual.get_format_as_md == """:snake:""" + assert actual.get_matching_icon_as_md == """:snake:""" def test_asMarkDown(get_config_map, persist_fs, process_fs, http_url_1): actual = Section(get_config_map, persist_fs, process_fs, http_url_1) current = actual.asMarkDown() - assert ( - current - == "1. [`here`](./0to100/https§§§cloud.google.com§abc/readme.md) :footprints:" + assert str_relaxed(current) == str_relaxed( + "1. [`here`](./0to100/https§§§cloud.google.com§abc/readme.md) `wip`" ) diff --git a/zero_to_one_hundred/tests/test_ztoh/test_ztoh_config_map.py b/zero_to_one_hundred/tests/test_ztoh/test_ztoh_config_map.py index 61e482c..fd8787f 100644 --- a/zero_to_one_hundred/tests/test_ztoh/test_ztoh_config_map.py +++ b/zero_to_one_hundred/tests/test_ztoh/test_ztoh_config_map.py @@ -1,6 +1,5 @@ from zero_to_one_hundred.configs.ztoh_config_map import ZTOH_MAP, ZTOHConfigMap - # pylint: disable=W0621,W0613 @@ -9,7 +8,7 @@ def test_config_map(get_config_map: ZTOHConfigMap): assert actual.get_type == ZTOH_MAP assert actual.get_repo_path is not None assert actual.get_repo_map_md == "toc.md" - assert actual.get_repo_legend_type is None + assert actual.get_legend_type is None def test__repr__(get_config_map: ZTOHConfigMap, get_map_yaml_path: str): @@ -25,7 +24,14 @@ def test_gcp_config_map(get_gcp_config_map: ZTOHConfigMap): assert actual.get_type == ZTOH_MAP assert actual.get_repo_path is not None assert actual.get_repo_map_md == "toc.md" - assert actual.get_repo_legend_type == "gcp" + assert actual.get_legend_type == "gcp" + assert actual.get_legend_icons == [ + ZTOHConfigMap.LegendIcons("Path", ":cyclone:", "path"), + ZTOHConfigMap.LegendIcons("Lab", ":floppy_disk:", "lab"), + ZTOHConfigMap.LegendIcons("Template", ":whale:", "template"), + ZTOHConfigMap.LegendIcons("Game", ":snake:", "game"), + ZTOHConfigMap.LegendIcons("Course", ":pushpin:", "course"), + ] def test_datacamp_config_map(get_datacamp_config_map: ZTOHConfigMap): @@ -33,7 +39,12 @@ def test_datacamp_config_map(get_datacamp_config_map: ZTOHConfigMap): assert actual.get_type == ZTOH_MAP assert actual.get_repo_path is not None assert actual.get_repo_map_md == "toc.md" - assert actual.get_repo_legend_type == "datacamp" + assert actual.get_legend_type == "datacamp" + assert actual.get_legend_icons == [ + ZTOHConfigMap.LegendIcons("Project", ":cyclone:", "project"), + ZTOHConfigMap.LegendIcons("Tutorial", ":floppy_disk:", "tutorial"), + ZTOHConfigMap.LegendIcons("Course", ":whale:", "course"), + ] def test_unsupported_config_map(get_unsupported_config_map: ZTOHConfigMap): @@ -47,7 +58,7 @@ def test_config_map_sorted_0(get_config_map_sorted_0: ZTOHConfigMap): assert actual.get_repo_path is not None assert actual.get_repo_sorted == "abc" assert actual.get_repo_map_md == "toc.md" - assert actual.get_repo_legend_type is None + assert actual.get_legend_type is None def test_config_map_sorted_1(get_config_map_sorted_1: ZTOHConfigMap): @@ -56,4 +67,4 @@ def test_config_map_sorted_1(get_config_map_sorted_1: ZTOHConfigMap): assert actual.get_repo_path is not None assert actual.get_repo_sorted == "00:00:00" assert actual.get_repo_map_md == "toc.md" - assert actual.get_repo_legend_type is None + assert actual.get_legend_type is None