From 74d7753a5aca6f57aa8a12fa5637e6cf4aa692eb Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 28 Apr 2022 19:12:08 +0530 Subject: [PATCH 1/6] refactor: split make_boilerplate function --- frappe/tests/test_boilerplate.py | 131 ++++++++++++++++++++++--------- frappe/utils/boilerplate.py | 47 +++++++---- 2 files changed, 125 insertions(+), 53 deletions(-) diff --git a/frappe/tests/test_boilerplate.py b/frappe/tests/test_boilerplate.py index 4dfb6e615b..8c9f8be683 100644 --- a/frappe/tests/test_boilerplate.py +++ b/frappe/tests/test_boilerplate.py @@ -1,4 +1,5 @@ import ast +import copy import glob import os import shutil @@ -6,33 +7,39 @@ import unittest from unittest.mock import patch import frappe -from frappe.utils.boilerplate import make_boilerplate +from frappe.utils.boilerplate import _create_app_boilerplate, _get_inputs class TestBoilerPlate(unittest.TestCase): @classmethod def setUpClass(cls): - title = "Test App" - description = "This app's description contains 'single quotes' and \"double quotes\"." - publisher = "Test Publisher" - email = "example@example.org" - icon = "" # empty -> default - color = "" - app_license = "MIT" + cls.default_hooks = frappe._dict( + { + "app_name": "test_app", + "app_title": "Test App", + "app_description": "This app's description contains 'single quotes' and \"double quotes\".", + "app_publisher": "Test Publisher", + "app_email": "example@example.org", + "app_icon": "octicon octicon-file-directory", + "app_color": "grey", + "app_license": "MIT", + } + ) - cls.user_input = [ - title, - description, - publisher, - email, - icon, - color, - app_license, - ] + cls.default_user_input = frappe._dict( + { + "title": "Test App", + "description": "This app's description contains 'single quotes' and \"double quotes\".", + "publisher": "Test Publisher", + "email": "example@example.org", + "icon": "", # empty -> default + "color": "", + "app_license": "MIT", + } + ) cls.bench_path = frappe.utils.get_bench_path() cls.apps_dir = os.path.join(cls.bench_path, "apps") - cls.app_names = ("test_app", "test_app_no_git") cls.gitignore_file = ".gitignore" cls.git_folder = ".git" @@ -55,39 +62,91 @@ class TestBoilerPlate(unittest.TestCase): "public", ] + def create_app(self, hooks, no_git=False): + self.addCleanup(self.delete_test_app, hooks.app_name) + _create_app_boilerplate(self.apps_dir, hooks, no_git) + @classmethod - def tearDownClass(cls): - test_app_dirs = (os.path.join(cls.bench_path, "apps", app_name) for app_name in cls.app_names) - for test_app_dir in test_app_dirs: - if os.path.exists(test_app_dir): - shutil.rmtree(test_app_dir) + def delete_test_app(cls, app_name): + test_app_dir = os.path.join(cls.bench_path, "apps", app_name) + if os.path.exists(test_app_dir): + shutil.rmtree(test_app_dir) + + @staticmethod + def get_user_input_stream(inputs): + user_inputs = [] + for value in inputs.values(): + if isinstance(value, list): + user_inputs.extend(value) + else: + user_inputs.append(value) + return user_inputs + + def test_simple_input_to_boilerplate(self): + with patch("builtins.input", side_effect=self.get_user_input_stream(self.default_user_input)): + hooks = _get_inputs(self.default_hooks.app_name) + self.assertDictEqual(hooks, self.default_hooks) + + def test_invalid_inputs(self): + invalid_inputs = copy.deepcopy(self.default_user_input).update( + { + "title": ["1nvalid Title", "valid title"], + } + ) + with patch("builtins.input", side_effect=self.get_user_input_stream(invalid_inputs)): + hooks = _get_inputs(self.default_hooks.app_name) + self.assertEqual(hooks.app_title, "valid title") def test_create_app(self): - with patch("builtins.input", side_effect=self.user_input): - make_boilerplate(self.apps_dir, self.app_names[0]) + app_name = "test_app" - new_app_dir = os.path.join(self.bench_path, self.apps_dir, self.app_names[0]) + hooks = frappe._dict( + { + "app_name": app_name, + "app_title": "Test App", + "app_description": "This app's description contains 'single quotes' and \"double quotes\".", + "app_publisher": "Test Publisher", + "app_email": "example@example.org", + "app_icon": "octicon octicon-file-directory", + "app_color": "grey", + "app_license": "MIT", + } + ) - paths = self.get_paths(new_app_dir, self.app_names[0]) + self.create_app(hooks) + new_app_dir = os.path.join(self.bench_path, self.apps_dir, app_name) + + paths = self.get_paths(new_app_dir, app_name) for path in paths: - self.assertTrue(os.path.exists(path), msg=f"{path} should exist in {self.app_names[0]} app") + self.assertTrue(os.path.exists(path), msg=f"{path} should exist in {app_name} app") self.check_parsable_python_files(new_app_dir) def test_create_app_without_git_init(self): - with patch("builtins.input", side_effect=self.user_input): - make_boilerplate(self.apps_dir, self.app_names[1], no_git=True) + app_name = "test_app_no_git" - new_app_dir = os.path.join(self.apps_dir, self.app_names[1]) + hooks = frappe._dict( + { + "app_name": app_name, + "app_title": "Test App", + "app_description": "This app's description contains 'single quotes' and \"double quotes\".", + "app_publisher": "Test Publisher", + "app_email": "example@example.org", + "app_icon": "octicon octicon-file-directory", + "app_color": "grey", + "app_license": "MIT", + } + ) + self.create_app(hooks, no_git=True) - paths = self.get_paths(new_app_dir, self.app_names[1]) + new_app_dir = os.path.join(self.apps_dir, app_name) + + paths = self.get_paths(new_app_dir, app_name) for path in paths: if os.path.basename(path) in (self.git_folder, self.gitignore_file): - self.assertFalse( - os.path.exists(path), msg=f"{path} shouldn't exist in {self.app_names[1]} app" - ) + self.assertFalse(os.path.exists(path), msg=f"{path} shouldn't exist in {app_name} app") else: - self.assertTrue(os.path.exists(path), msg=f"{path} should exist in {self.app_names[1]} app") + self.assertTrue(os.path.exists(path), msg=f"{path} should exist in {app_name} app") self.check_parsable_python_files(new_app_dir) diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index f5243ecc95..c2ba3f0eec 100644 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -17,23 +17,32 @@ def make_boilerplate(dest, app_name, no_git=False): # app_name should be in snake_case app_name = frappe.scrub(app_name) + hooks = _get_inputs(app_name) + _create_app_boilerplate(dest, hooks, no_git=no_git) + + +def _get_inputs(app_name): + """Prompt user for various inputs related to new app and return config.""" + app_name = frappe.scrub(app_name) hooks = frappe._dict() hooks.app_name = app_name app_title = hooks.app_name.replace("_", " ").title() - for key in ( - "App Title (default: {0})".format(app_title), - "App Description", - "App Publisher", - "App Email", - "App Icon (default 'octicon octicon-file-directory')", - "App Color (default 'grey')", - "App License (default 'MIT')", - ): - hook_key = key.split(" (")[0].lower().replace(" ", "_") + + NEW_APP_CONFIG = { + "app_title": {"prompt": "App Title (default: {0})".format(app_title)}, + "app_description": {"prompt": "App Description"}, + "app_publisher": {"prompt": "App Publisher"}, + "app_email": {"prompt": "App Email"}, + "app_icon": {"prompt": "App Icon (default 'octicon octicon-file-directory')"}, + "app_color": {"prompt": "App Color (default 'grey')"}, + "app_license": {"prompt": "App License (default 'MIT')"}, + } + + for property, config in NEW_APP_CONFIG.items(): hook_val = None while not hook_val: - hook_val = cstr(input(key + ": ")) + hook_val = cstr(input(config["prompt"] + ": ")) if not hook_val: defaults = { @@ -42,13 +51,13 @@ def make_boilerplate(dest, app_name, no_git=False): "app_color": "grey", "app_license": "MIT", } - if hook_key in defaults: - hook_val = defaults[hook_key] + if property in defaults: + hook_val = defaults[property] - if hook_key == "app_name" and hook_val.lower().replace(" ", "_") != hook_val: + if property == "app_name" and hook_val.lower().replace(" ", "_") != hook_val: print("App Name must be all lowercase and without spaces") hook_val = "" - elif hook_key == "app_title" and not re.match( + elif property == "app_title" and not re.match( r"^(?![\W])[^\d_\s][\w -]+$", hook_val, re.UNICODE ): print( @@ -56,8 +65,12 @@ def make_boilerplate(dest, app_name, no_git=False): ) hook_val = "" - hooks[hook_key] = hook_val + hooks[property] = hook_val + return hooks + + +def _create_app_boilerplate(dest, hooks, no_git=False): frappe.create_folder( os.path.join(dest, hooks.app_name, hooks.app_name, frappe.scrub(hooks.app_title)), with_init=True ) @@ -132,7 +145,7 @@ def make_boilerplate(dest, app_name, no_git=False): app_repo.git.add(A=True) app_repo.index.commit("feat: Initialize App") - print("'{app}' created at {path}".format(app=app_name, path=app_directory)) + print(f"'{hooks.app_name}' created at {app_directory}") manifest_template = """include MANIFEST.in From 53f54c37614a486ace9112936ca0779b633103b7 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 28 Apr 2022 20:26:29 +0530 Subject: [PATCH 2/6] refactor: use click for new-app prompts --- frappe/tests/test_boilerplate.py | 9 ++--- frappe/utils/boilerplate.py | 61 +++++++++++++++----------------- 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/frappe/tests/test_boilerplate.py b/frappe/tests/test_boilerplate.py index 8c9f8be683..ef1f0a12dc 100644 --- a/frappe/tests/test_boilerplate.py +++ b/frappe/tests/test_boilerplate.py @@ -4,6 +4,7 @@ import glob import os import shutil import unittest +from io import StringIO from unittest.mock import patch import frappe @@ -80,20 +81,20 @@ class TestBoilerPlate(unittest.TestCase): user_inputs.extend(value) else: user_inputs.append(value) - return user_inputs + return StringIO("\n".join(user_inputs)) def test_simple_input_to_boilerplate(self): - with patch("builtins.input", side_effect=self.get_user_input_stream(self.default_user_input)): + with patch("sys.stdin", self.get_user_input_stream(self.default_user_input)): hooks = _get_inputs(self.default_hooks.app_name) self.assertDictEqual(hooks, self.default_hooks) def test_invalid_inputs(self): - invalid_inputs = copy.deepcopy(self.default_user_input).update( + invalid_inputs = copy.copy(self.default_user_input).update( { "title": ["1nvalid Title", "valid title"], } ) - with patch("builtins.input", side_effect=self.get_user_input_stream(invalid_inputs)): + with patch("sys.stdin", self.get_user_input_stream(invalid_inputs)): hooks = _get_inputs(self.default_hooks.app_name) self.assertEqual(hooks.app_title, "valid title") diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index c2ba3f0eec..b26aadb9d1 100644 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -4,6 +4,7 @@ import os import re +import click import git import frappe @@ -29,47 +30,43 @@ def _get_inputs(app_name): hooks.app_name = app_name app_title = hooks.app_name.replace("_", " ").title() - NEW_APP_CONFIG = { - "app_title": {"prompt": "App Title (default: {0})".format(app_title)}, + new_app_config = { + "app_title": { + "prompt": "App Title".format(app_title), + "default": app_title, + "validator": is_valid_title, + }, "app_description": {"prompt": "App Description"}, "app_publisher": {"prompt": "App Publisher"}, "app_email": {"prompt": "App Email"}, - "app_icon": {"prompt": "App Icon (default 'octicon octicon-file-directory')"}, - "app_color": {"prompt": "App Color (default 'grey')"}, - "app_license": {"prompt": "App License (default 'MIT')"}, + "app_icon": {"prompt": "App Icon", "default": "octicon octicon-file-directory"}, + "app_color": {"prompt": "App Color", "default": "grey"}, + "app_license": {"prompt": "App License", "default": "MIT"}, } - for property, config in NEW_APP_CONFIG.items(): - hook_val = None - while not hook_val: - hook_val = cstr(input(config["prompt"] + ": ")) - - if not hook_val: - defaults = { - "app_title": app_title, - "app_icon": "octicon octicon-file-directory", - "app_color": "grey", - "app_license": "MIT", - } - if property in defaults: - hook_val = defaults[property] - - if property == "app_name" and hook_val.lower().replace(" ", "_") != hook_val: - print("App Name must be all lowercase and without spaces") - hook_val = "" - elif property == "app_title" and not re.match( - r"^(?![\W])[^\d_\s][\w -]+$", hook_val, re.UNICODE - ): - print( - "App Title should start with a letter and it can only consist of letters, numbers, spaces and underscores" - ) - hook_val = "" - - hooks[property] = hook_val + for property, config in new_app_config.items(): + value = None + while value is None: + value = click.prompt( + config["prompt"], default=config.get("default"), type=config.get("type", str) + ) + if validator_function := config.get("validator"): + if not validator_function(value): + value = None + hooks[property] = value return hooks +def is_valid_title(title) -> bool: + if not re.match(r"^(?![\W])[^\d_\s][\w -]+$", title, re.UNICODE): + print( + "App Title should start with a letter and it can only consist of letters, numbers, spaces and underscores" + ) + return False + return True + + def _create_app_boilerplate(dest, hooks, no_git=False): frappe.create_folder( os.path.join(dest, hooks.app_name, hooks.app_name, frappe.scrub(hooks.app_title)), with_init=True From 3fd4759dd4bee6e497c5830256944533c1243c11 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 29 Apr 2022 17:15:40 +0530 Subject: [PATCH 3/6] fix: gitignore node_modules in new frappe apps --- frappe/utils/boilerplate.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index b26aadb9d1..b5e49aa6b6 100644 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -408,7 +408,8 @@ gitignore_template = """.DS_Store *.egg-info *.swp tags -{app_name}/docs/current""" +{app_name}/docs/current +node_modules/""" docs_template = '''""" Configuration for docs From 42942f36a6d088ca97412b614a53843876cccb1f Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 29 Apr 2022 17:12:59 +0530 Subject: [PATCH 4/6] feat: provide github workflow for unittest in new app --- frappe/tests/test_boilerplate.py | 17 +++- frappe/utils/boilerplate.py | 129 +++++++++++++++++++++++++++++-- 2 files changed, 136 insertions(+), 10 deletions(-) diff --git a/frappe/tests/test_boilerplate.py b/frappe/tests/test_boilerplate.py index ef1f0a12dc..e4b8c680a9 100644 --- a/frappe/tests/test_boilerplate.py +++ b/frappe/tests/test_boilerplate.py @@ -7,8 +7,14 @@ import unittest from io import StringIO from unittest.mock import patch +import yaml + import frappe -from frappe.utils.boilerplate import _create_app_boilerplate, _get_inputs +from frappe.utils.boilerplate import ( + _create_app_boilerplate, + _get_user_inputs, + github_workflow_template, +) class TestBoilerPlate(unittest.TestCase): @@ -24,6 +30,7 @@ class TestBoilerPlate(unittest.TestCase): "app_icon": "octicon octicon-file-directory", "app_color": "grey", "app_license": "MIT", + "create_github_workflow": False, } ) @@ -36,6 +43,7 @@ class TestBoilerPlate(unittest.TestCase): "icon": "", # empty -> default "color": "", "app_license": "MIT", + "github_workflow": "n", } ) @@ -85,7 +93,7 @@ class TestBoilerPlate(unittest.TestCase): def test_simple_input_to_boilerplate(self): with patch("sys.stdin", self.get_user_input_stream(self.default_user_input)): - hooks = _get_inputs(self.default_hooks.app_name) + hooks = _get_user_inputs(self.default_hooks.app_name) self.assertDictEqual(hooks, self.default_hooks) def test_invalid_inputs(self): @@ -95,9 +103,12 @@ class TestBoilerPlate(unittest.TestCase): } ) with patch("sys.stdin", self.get_user_input_stream(invalid_inputs)): - hooks = _get_inputs(self.default_hooks.app_name) + hooks = _get_user_inputs(self.default_hooks.app_name) self.assertEqual(hooks.app_title, "valid title") + def test_valid_ci_yaml(self): + yaml.safe_load(github_workflow_template.format(**self.default_hooks)) + def test_create_app(self): app_name = "test_app" diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index b5e49aa6b6..12119037e0 100644 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -2,13 +2,14 @@ # License: MIT. See LICENSE import os +import pathlib import re import click import git import frappe -from frappe.utils import cstr, touch_file +from frappe.utils import touch_file def make_boilerplate(dest, app_name, no_git=False): @@ -18,11 +19,11 @@ def make_boilerplate(dest, app_name, no_git=False): # app_name should be in snake_case app_name = frappe.scrub(app_name) - hooks = _get_inputs(app_name) + hooks = _get_user_inputs(app_name) _create_app_boilerplate(dest, hooks, no_git=no_git) -def _get_inputs(app_name): +def _get_user_inputs(app_name): """Prompt user for various inputs related to new app and return config.""" app_name = frappe.scrub(app_name) @@ -32,7 +33,7 @@ def _get_inputs(app_name): new_app_config = { "app_title": { - "prompt": "App Title".format(app_title), + "prompt": "App Title", "default": app_title, "validator": is_valid_title, }, @@ -42,14 +43,23 @@ def _get_inputs(app_name): "app_icon": {"prompt": "App Icon", "default": "octicon octicon-file-directory"}, "app_color": {"prompt": "App Color", "default": "grey"}, "app_license": {"prompt": "App License", "default": "MIT"}, + "create_github_workflow": { + "prompt": "Create GitHub Workflow action for unittests", + "default": False, + "type": bool, + }, } for property, config in new_app_config.items(): value = None + input_type = config.get("type", str) + while value is None: - value = click.prompt( - config["prompt"], default=config.get("default"), type=config.get("type", str) - ) + if input_type == bool: + value = click.confirm(config["prompt"], default=config.get("default")) + else: + value = click.prompt(config["prompt"], default=config.get("default"), type=input_type) + if validator_function := config.get("validator"): if not validator_function(value): value = None @@ -133,6 +143,9 @@ def _create_app_boilerplate(dest, hooks, no_git=False): app_directory = os.path.join(dest, hooks.app_name) + if hooks.create_github_workflow: + _create_github_workflow_files(dest, hooks) + if not no_git: with open(os.path.join(dest, hooks.app_name, ".gitignore"), "w") as f: f.write(frappe.as_unicode(gitignore_template.format(app_name=hooks.app_name))) @@ -145,6 +158,15 @@ def _create_app_boilerplate(dest, hooks, no_git=False): print(f"'{hooks.app_name}' created at {app_directory}") +def _create_github_workflow_files(dest, hooks): + workflows_path = pathlib.Path(dest) / hooks.app_name / ".github" / "workflows" + workflows_path.mkdir(parents=True, exist_ok=True) + + ci_workflow = workflows_path / "ci.yml" + with open(ci_workflow, "w") as f: + f.write(github_workflow_template.format(**hooks)) + + manifest_template = """include MANIFEST.in include requirements.txt include *.json @@ -422,3 +444,96 @@ Configuration for docs def get_context(context): context.brand_html = "{app_title}" ''' + + +github_workflow_template = """ +name: CI + +on: + push: + branches: + - develop + pull_request: + +concurrency: + group: develop-{app_name}-${{{{ github.event.number }}}} + cancel-in-progress: true + +jobs: + tests: + runs-on: ubuntu-latest + strategy: + fail-fast: false + name: Server + + services: + mariadb: + image: mariadb:10.3 + env: + MYSQL_ROOT_PASSWORD: root + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 + + steps: + - name: Clone + uses: actions/checkout@v2 + + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: 3.9 + + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: 14 + check-latest: true + + - name: Cache pip + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{{{ runner.os }}}}-pip-${{{{ hashFiles('**/*requirements.txt') }}}} + restore-keys: | + ${{{{ runner.os }}}}-pip- + ${{{{ runner.os }}}}- + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: 'echo "::set-output name=dir::$(yarn cache dir)"' + + - uses: actions/cache@v2 + id: yarn-cache + with: + path: ${{{{ steps.yarn-cache-dir-path.outputs.dir }}}} + key: ${{{{ runner.os }}}}-yarn-${{{{ hashFiles('**/yarn.lock') }}}} + restore-keys: | + ${{{{ runner.os }}}}-yarn- + + - name: Setup + run: | + pip install frappe-bench + bench init --skip-redis-config-generation --skip-assets --python "$(which python)" ~/frappe-bench + mysql --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL character_set_server = 'utf8mb4'" + mysql --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'" + + - name: Install + working-directory: /home/runner/frappe-bench + run: | + bench get-app {app_name} $GITHUB_WORKSPACE + bench setup requirements --dev + bench new-site --db-root-password root --admin-password admin test_site + bench --site test_site install-app {app_name} + bench build + env: + CI: 'Yes' + + - name: Run Tests + working-directory: /home/runner/frappe-bench + run: | + bench --site test_site set-config allow_tests true + bench --site test_site run-tests --app {app_name} + env: + TYPE: server +""" From 665f871c09bc623a7fc91354c04f0ea61a42f4b3 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 1 May 2022 21:04:28 +0530 Subject: [PATCH 5/6] test: delete duplicate test --- frappe/tests/test_commands.py | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/frappe/tests/test_commands.py b/frappe/tests/test_commands.py index 67de6c6e41..d4a86bd111 100644 --- a/frappe/tests/test_commands.py +++ b/frappe/tests/test_commands.py @@ -413,26 +413,6 @@ class TestCommands(BaseTestCommands): self.assertEqual(self.returncode, 0) self.assertEqual(check_password("Administrator", "test2"), "Administrator") - def test_make_app(self): - user_input = [ - b"Test App", # title - b"This app's description contains 'single quotes' and \"double quotes\".", # description - b"Test Publisher", # publisher - b"example@example.org", # email - b"", # icon - b"", # color - b"MIT", # app_license - ] - app_name = "testapp0" - apps_path = os.path.join(get_bench_path(), "apps") - test_app_path = os.path.join(apps_path, app_name) - self.execute(f"bench make-app {apps_path} {app_name}", {"cmd_input": b"\n".join(user_input)}) - self.assertEqual(self.returncode, 0) - self.assertTrue(os.path.exists(test_app_path)) - - # cleanup - shutil.rmtree(test_app_path) - @skipIf( not ( frappe.conf.root_password and frappe.conf.admin_password and frappe.conf.db_type == "mariadb" From 8a1889301a85d74fa88f9fbb8f6f8d4e42069b6b Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 2 May 2022 11:27:05 +0530 Subject: [PATCH 6/6] chore!: remove dead hooks `app_icon` & `app_color` --- frappe/hooks.py | 2 -- frappe/tests/test_boilerplate.py | 6 ------ frappe/utils/boilerplate.py | 6 ------ hooks.md | 2 -- 4 files changed, 16 deletions(-) diff --git a/frappe/hooks.py b/frappe/hooks.py index f7a67dc7ec..ee8417a3ec 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -4,8 +4,6 @@ app_name = "frappe" app_title = "Frappe Framework" app_publisher = "Frappe Technologies" app_description = "Full stack web framework with Python, Javascript, MariaDB, Redis, Node" -app_icon = "octicon octicon-circuit-board" -app_color = "orange" source_link = "https://github.com/frappe/frappe" app_license = "MIT" app_logo_url = "/assets/frappe/images/frappe-framework-logo.svg" diff --git a/frappe/tests/test_boilerplate.py b/frappe/tests/test_boilerplate.py index e4b8c680a9..092a1ff126 100644 --- a/frappe/tests/test_boilerplate.py +++ b/frappe/tests/test_boilerplate.py @@ -27,8 +27,6 @@ class TestBoilerPlate(unittest.TestCase): "app_description": "This app's description contains 'single quotes' and \"double quotes\".", "app_publisher": "Test Publisher", "app_email": "example@example.org", - "app_icon": "octicon octicon-file-directory", - "app_color": "grey", "app_license": "MIT", "create_github_workflow": False, } @@ -119,8 +117,6 @@ class TestBoilerPlate(unittest.TestCase): "app_description": "This app's description contains 'single quotes' and \"double quotes\".", "app_publisher": "Test Publisher", "app_email": "example@example.org", - "app_icon": "octicon octicon-file-directory", - "app_color": "grey", "app_license": "MIT", } ) @@ -144,8 +140,6 @@ class TestBoilerPlate(unittest.TestCase): "app_description": "This app's description contains 'single quotes' and \"double quotes\".", "app_publisher": "Test Publisher", "app_email": "example@example.org", - "app_icon": "octicon octicon-file-directory", - "app_color": "grey", "app_license": "MIT", } ) diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index 12119037e0..22ca64eb1a 100644 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -40,8 +40,6 @@ def _get_user_inputs(app_name): "app_description": {"prompt": "App Description"}, "app_publisher": {"prompt": "App Publisher"}, "app_email": {"prompt": "App Email"}, - "app_icon": {"prompt": "App Icon", "default": "octicon octicon-file-directory"}, - "app_color": {"prompt": "App Color", "default": "grey"}, "app_license": {"prompt": "App License", "default": "MIT"}, "create_github_workflow": { "prompt": "Create GitHub Workflow action for unittests", @@ -197,8 +195,6 @@ app_name = "{app_name}" app_title = "{app_title}" app_publisher = "{app_publisher}" app_description = "{app_description}" -app_icon = "{app_icon}" -app_color = "{app_color}" app_email = "{app_email}" app_license = "{app_license}" @@ -396,8 +392,6 @@ def get_data(): return [ {{ "module_name": "{app_title}", - "color": "{app_color}", - "icon": "{app_icon}", "type": "module", "label": _("{app_title}") }} diff --git a/hooks.md b/hooks.md index 5ff70471c9..efb58f2645 100644 --- a/hooks.md +++ b/hooks.md @@ -7,8 +7,6 @@ 1. `app_publisher` 1. `app_description` 1. `app_version` -1. `app_icon` - font-awesome icon or image url -1. `app_color` - hex colour background of the app icon #### Install