From 842c072751eb946b08c51ccc63d6d3501142680a Mon Sep 17 00:00:00 2001 From: David Rojas Date: Wed, 13 Nov 2024 18:31:16 -0500 Subject: [PATCH 1/5] Added task to copier to warn that template is deprecated and updated README --- README.md | 4 ++++ copier.yaml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/README.md b/README.md index befc3ec..9dff1d9 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,10 @@

+--- +# DEPRECATED +This template has been deprecated. Beaker for Algorand Smart Contract development is no longer supported. Please use Algorand Python instead. The Algorand Python template can be found at https://github.com/algorandfoundation/algokit-python-template. + --- This template provides a production-ready baseline for developing and deploying [Beaker](https://github.com/algorand-devrel/beaker) smart contracts. diff --git a/copier.yaml b/copier.yaml index d9f7c11..0d1d637 100644 --- a/copier.yaml +++ b/copier.yaml @@ -1,6 +1,10 @@ _subdirectory: template_content _templates_suffix: ".jinja" +_tasks: + - "python -c \"print('WARNING: This template has been deprecated. Beaker for Algorand Smart Contract development is no longer supported.\\nPlease use Algorand Python instead. The Algorand Python template can be found at https://github.com/algorandfoundation/algokit-python-template')\"" + - "python -c \"exit(1)\"" + use_workspace: type: bool when: false # never prompted to user explicitly, instead expect cli to auto fill (supported cli versions > v1.13.x) From 375b54f6d4099d495fafbd7d8cfa8e06ea36eb58 Mon Sep 17 00:00:00 2001 From: David Rojas Date: Mon, 18 Nov 2024 16:06:09 -0500 Subject: [PATCH 2/5] chore: deprecated tests and created a test for a failed init --- tests/test_generators.py | 16 ++++++++++++++++ tests/test_templates.py | 1 + 2 files changed, 17 insertions(+) diff --git a/tests/test_generators.py b/tests/test_generators.py index bb503bb..fd08ceb 100644 --- a/tests/test_generators.py +++ b/tests/test_generators.py @@ -176,6 +176,7 @@ def run_generator( @pytest.mark.parametrize("language", ["python", "typescript"]) +@pytest.mark.skip(reason="This test is deprecated since the template is deprecated") def test_smart_contract_generator_default_starter_preset( language: str, working_dir: Path ) -> None: @@ -207,6 +208,7 @@ def test_smart_contract_generator_default_starter_preset( @pytest.mark.parametrize("language", ["python", "typescript"]) +@pytest.mark.skip(reason="This test is deprecated since the template is deprecated") def test_smart_contract_generator_default_production_preset( language: str, working_dir: Path ) -> None: @@ -235,3 +237,17 @@ def test_smart_contract_generator_default_production_preset( response = check_codebase(working_dir, test_name) assert response.returncode == 0, response.stdout + + +def test_template_fail() -> None: + test_name = "production_beaker_smart_contract_fail" + + response = run_init( + root, + test_name, + answers={ + "preset_name": "starter", + "deployment_language": "python", + }, + ) + assert response.returncode == 1, response.stdout diff --git a/tests/test_templates.py b/tests/test_templates.py index 2dfa162..fcc8da7 100644 --- a/tests/test_templates.py +++ b/tests/test_templates.py @@ -186,6 +186,7 @@ def get_questions_from_copier_yaml( @pytest.mark.parametrize(("question_name", "answer"), get_questions_from_copier_yaml()) +@pytest.mark.skip(reason="This test is deprecated since the template is deprecated") def test_parameters(working_dir: Path, question_name: str, answer: str | bool) -> None: response = run_init_kwargs(working_dir, **{question_name: answer}) assert response.returncode == 0, response.stdout From 8f7cccdb44d56997226db86cd2e1637c6b9912b9 Mon Sep 17 00:00:00 2001 From: Altynbek Orumbayev Date: Fri, 22 Nov 2024 10:11:55 +0500 Subject: [PATCH 3/5] chore: deprecate beaker template with explicit question + warning & exit task --- copier.yaml | 53 ++++++++++++++++++++++++----------- template_content/post_init.py | 35 +++++++++++++++++++++++ 2 files changed, 72 insertions(+), 16 deletions(-) create mode 100644 template_content/post_init.py diff --git a/copier.yaml b/copier.yaml index 0d1d637..8e7c2c0 100644 --- a/copier.yaml +++ b/copier.yaml @@ -1,33 +1,50 @@ _subdirectory: template_content _templates_suffix: ".jinja" -_tasks: - - "python -c \"print('WARNING: This template has been deprecated. Beaker for Algorand Smart Contract development is no longer supported.\\nPlease use Algorand Python instead. The Algorand Python template can be found at https://github.com/algorandfoundation/algokit-python-template')\"" - - "python -c \"exit(1)\"" +use_deprecated_template: + type: bool + help: | + WARNING: This template has been deprecated. Beaker for Algorand Smart Contract development is no longer supported. + Please use Algorand Python instead. The Algorand Python template can be found at https://github.com/algorandfoundation/algokit-python-template + Do you still want to proceed with using the deprecated template? + default: no +_tasks: + - '"{{ python_path if python_path else _copier_python }}" post_init.py {{ use_deprecated_template }} {{ use_workspace }}' + use_workspace: type: bool - when: false # never prompted to user explicitly, instead expect cli to auto fill (supported cli versions > v1.13.x) + when: false # never prompted to user explicitly, expect CLI to auto-fill help: Automatically filled by AlgoKit CLI (>1.13.x) - passes the --workspace/--no-workspace flag's value, can be used to reason whether this template is currently being instantiated as part of a workspace or not. default: no +# Auto determined by algokit-cli from v1.11.3 to allow execution of python script +# in binary mode. +python_path: + type: str + help: Path to the sys.executable. + when: false + # questions project_name: type: str help: Name for this project. placeholder: "algorand-app" + when: "{{ use_deprecated_template }}" author_name: type: str help: Package author name placeholder: "Your Name" default: "Your Name" + when: "{{ use_deprecated_template }}" author_email: type: str help: Package author email placeholder: "your@email.tld" default: "your@email.tld" + when: "{{ use_deprecated_template }}" contract_name: type: str @@ -38,6 +55,7 @@ contract_name: {% if not (contract_name | regex_search('^[a-z]+(?:_[a-z]+)*$')) %} contract_name must be formatted in snake case. {% endif %} + when: "{{ use_deprecated_template }}" preset_name: type: str @@ -47,6 +65,7 @@ preset_name: "Production - for confidently deploying to MainNet and/or more complex projects": "production" "Custom - for tailoring the template output to your needs": "custom" default: "starter" + when: "{{ use_deprecated_template }}" deployment_language: type: str @@ -55,41 +74,43 @@ deployment_language: Python: "python" TypeScript: "typescript" default: "python" + when: "{{ use_deprecated_template }}" ide_vscode: type: bool help: Do you want to add VSCode configuration? - when: "{{ preset_name == 'custom' }}" + when: "{{ preset_name == 'custom' and use_deprecated_template }}" default: yes code_tours: type: bool help: Do you want to add interactive VSCode CodeTour walkthrough? - when: "{{ preset_name == 'custom' }}" + when: "{{ preset_name == 'custom' and use_deprecated_template }}" default: yes ide_jetbrains: type: bool help: Do you want to add JetBrains configuration (primarily optimized for PyCharm CE)? - when: "{{ preset_name == 'custom' }}" + when: "{{ preset_name == 'custom' and use_deprecated_template }}" default: "{{ 'yes' if preset_name == 'production' else 'no' }}" + when: "{{ use_deprecated_template }}" use_python_pytest: type: bool - when: "{{ deployment_language == 'python' and preset_name == 'custom' }}" + when: "{{ deployment_language == 'python' and preset_name == 'custom' and use_deprecated_template }}" help: Do you want to include unit tests (via pytest)? default: "{{ 'yes' if preset_name == 'production' and deployment_language == 'python' else 'no' }}" use_typescript_jest: type: bool - when: "{{ deployment_language == 'typescript' and preset_name == 'custom' }}" + when: "{{ deployment_language == 'typescript' and preset_name == 'custom' and use_deprecated_template }}" help: Do you want to include unit tests (via jest)? default: "{{ 'yes' if preset_name == 'production' and deployment_language == 'typescript' else 'no' }}" python_linter: type: str help: Do you want to use a Python linter? - when: "{{ preset_name == 'custom' }}" + when: "{{ preset_name == 'custom' and use_deprecated_template }}" choices: Ruff: "ruff" Flake8: "flake8" @@ -99,35 +120,35 @@ python_linter: use_python_black: type: bool help: Do you want to use a Python formatter (via Black)? - when: "{{ preset_name == 'custom' }}" + when: "{{ preset_name == 'custom' and use_deprecated_template }}" default: "{{ 'yes' if preset_name == 'production' else 'no' }}" use_python_mypy: type: bool - when: "{{ preset_name == 'custom' }}" + when: "{{ preset_name == 'custom' and use_deprecated_template }}" help: Do you want to use a Python type checker (via mypy)? default: "{{ 'yes' if preset_name == 'production' else 'no' }}" use_python_pip_audit: type: bool - when: "{{ preset_name == 'custom' }}" + when: "{{ preset_name == 'custom' and use_deprecated_template }}" help: Do you want to include Python dependency vulnerability scanning (via pip-audit)? default: "{{ 'yes' if preset_name == 'production' else 'no' }}" use_github_actions: type: bool - when: "{{ preset_name == 'custom' }}" + when: "{{ preset_name == 'custom' and use_deprecated_template }}" help: Do you want to include Github Actions workflows for build and testnet deployment? default: "{{ 'yes' if preset_name == 'production' else 'no' }}" use_pre_commit: type: bool - when: "{{ preset_name == 'custom' }}" + when: "{{ preset_name == 'custom' and use_deprecated_template }}" help: Do you want to include pre-commit for linting, type checking and formatting? default: "{{ 'yes' if preset_name == 'production' else 'no' }}" use_dispenser: type: bool - when: "{{ preset_name == 'custom' }}" + when: "{{ preset_name == 'custom' and use_deprecated_template }}" help: Do you want to fund your deployment account using an optional dispenser account? default: "{{ 'yes' if preset_name == 'production' else 'no' }}" diff --git a/template_content/post_init.py b/template_content/post_init.py new file mode 100644 index 0000000..56a4400 --- /dev/null +++ b/template_content/post_init.py @@ -0,0 +1,35 @@ +import shutil +import sys +from pathlib import Path + + +def main(): + # Get the use_deprecated_template argument + use_deprecated_template = sys.argv[1].lower() in ("true", "yes", "1", "t", "y") + use_workspace = sys.argv[2].lower() in ("true", "yes", "1", "t", "y") + + if not use_deprecated_template: + # Get the parent directory of this script which should be the generated project root + project_dir = Path(__file__).parent + project_dir = project_dir.parent.parent if use_workspace else project_dir + + # Print warning + print("WARNING: Template generation cancelled!\n") + print( + "This template is deprecated. Use Algorand Python instead: https://github.com/algorandfoundation/algokit-python-template\n" + ) + + if project_dir.exists(): + try: + shutil.rmtree(project_dir) + except: + pass + + sys.exit(1) + + # If we get here, template was approved to be used + print("Proceeding with deprecated template generation...") + + +if __name__ == "__main__": + main() From e9e7e373e256b4091a09a4093e96c7e201b2a819 Mon Sep 17 00:00:00 2001 From: David Rojas Date: Fri, 22 Nov 2024 14:21:15 -0500 Subject: [PATCH 4/5] chore: changed working dir before deleting template dir and added more err handling --- template_content/post_init.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/template_content/post_init.py b/template_content/post_init.py index 56a4400..1d21c43 100644 --- a/template_content/post_init.py +++ b/template_content/post_init.py @@ -1,6 +1,7 @@ import shutil import sys from pathlib import Path +import os def main(): @@ -21,9 +22,28 @@ def main(): if project_dir.exists(): try: + # Change working directory to parent before deletion + os.chdir(project_dir.parent) shutil.rmtree(project_dir) - except: - pass + except PermissionError as e: + print( + f"Failed to clean up {project_dir}: Unable to remove directory due to permissions: {e}", + file=sys.stderr, + ) + print( + "Please ensure no files are open in the directory and try again.", + file=sys.stderr, + ) + sys.exit(1) + except OSError as e: + print(f"Failed to clean up {project_dir}: {str(e)}", file=sys.stderr) + print( + "Please ensure no files are open in the directory and try again.", + file=sys.stderr, + ) + sys.exit(1) + except Exception as e: + print(f"Failed to clean up {project_dir}: {str(e)}", file=sys.stderr) sys.exit(1) From 159fe6472290f6cdc6c4c1cd55d3dbde250ea7c0 Mon Sep 17 00:00:00 2001 From: David Rojas Date: Tue, 26 Nov 2024 15:19:27 -0500 Subject: [PATCH 5/5] chore: Removed other exceptions. Kept generic exception --- template_content/post_init.py | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/template_content/post_init.py b/template_content/post_init.py index 1d21c43..b312e50 100644 --- a/template_content/post_init.py +++ b/template_content/post_init.py @@ -22,28 +22,13 @@ def main(): if project_dir.exists(): try: - # Change working directory to parent before deletion os.chdir(project_dir.parent) shutil.rmtree(project_dir) - except PermissionError as e: - print( - f"Failed to clean up {project_dir}: Unable to remove directory due to permissions: {e}", - file=sys.stderr, - ) - print( - "Please ensure no files are open in the directory and try again.", - file=sys.stderr, - ) - sys.exit(1) - except OSError as e: - print(f"Failed to clean up {project_dir}: {str(e)}", file=sys.stderr) + except Exception as e: print( - "Please ensure no files are open in the directory and try again.", + f"Failed to clean up {project_dir}. You will have to manually delete the project folder. Error: {str(e)}", file=sys.stderr, ) - sys.exit(1) - except Exception as e: - print(f"Failed to clean up {project_dir}: {str(e)}", file=sys.stderr) sys.exit(1)