diff --git a/backend_addon/Makefile b/backend_addon/Makefile
index f1124d7..cdfece5 100644
--- a/backend_addon/Makefile
+++ b/backend_addon/Makefile
@@ -12,6 +12,11 @@ YELLOW=`tput setaf 3`
.PHONY: all
all: build
+TEMPLATE = $(shell basename $(CURRENT_DIR))
+ADDON_FOLDER_NAME = collective.addon
+BASE_FOLDER = ../
+BIN_FOLDER = ${BASE_FOLDER}/bin
+
# Add the following 'help' target to your Makefile
# And add help text after each target name starting with '\#\#'
@@ -21,24 +26,29 @@ help: ## This help message
.PHONY: clean
clean: ## Clean
- rm -rf collective.addon
+ rm -rf volto-addon
-../bin/cookieplone: ## cookieplone installation
- $(MAKE) -C ".." bin/cookieplone
+$(BIN_FOLDER)/cookieplone: ## cookieplone installation
+ $(MAKE) -C $(BASE_FOLDER) bin/cookieplone
.PHONY: format
-format: ../bin/cookieplone ## Format code
+format: $(BIN_FOLDER)/cookieplone ## Format code
@echo "$(GREEN)==> Formatting codebase $(RESET)"
- ../bin/black hooks tests
- ../bin/isort hooks tests
+ $(BIN_FOLDER)/black hooks tests
+ $(BIN_FOLDER)/isort hooks tests
.PHONY: generate
-generate: ../bin/cookieplone ## Create a sample package
+generate: $(BIN_FOLDER)/cookieplone ## Create a sample package
@echo "$(GREEN)==> Creating new test package$(RESET)"
- rm -rf collective.addon
- ../bin/cookieplone . --no-input
+ rm -rf $(ADDON_FOLDER_NAME)
+ COOKIEPLONE_REPOSITORY=$(BASE_FOLDER) $(BIN_FOLDER)/cookieplone $(TEMPLATE) --no_input
.PHONY: test
-test: ../bin/cookieplone ## Create a sample package and tests it
- @echo "$(GREEN)==> Creating new test package$(RESET)"
- ../bin/python -m pytest tests
+test: $(BIN_FOLDER)/cookieplone ## Create a sample package and tests it
+ @echo "$(GREEN)==> Test template$(RESET)"
+ $(BIN_FOLDER)/python -m pytest tests
+
+.PHONY: test-pdb
+test-pdb: $(BIN_FOLDER)/cookieplone ## Stop on the first failed test
+ @echo "$(GREEN)==> Test template, stop on first error$(RESET)"
+ $(BIN_FOLDER)/python -m pytest tests -x --pdb
diff --git a/backend_addon/cookiecutter.json b/backend_addon/cookiecutter.json
index 8485539..42ee090 100644
--- a/backend_addon/cookiecutter.json
+++ b/backend_addon/cookiecutter.json
@@ -13,6 +13,7 @@
"__package_namespace": "{{ cookiecutter.python_package_name | package_namespace }}",
"__folder_name": "{{ cookiecutter.python_package_name }}",
"__python_package_name_upper": "{{ cookiecutter.python_package_name | pascal_case }}",
+ "__profile_language": "en",
"__version_package": "1.0.0a0",
"__profile_version": "1000",
"__gha_enable": true,
diff --git a/backend_addon/hooks/post_gen_project.py b/backend_addon/hooks/post_gen_project.py
index 1c1d11f..0950614 100644
--- a/backend_addon/hooks/post_gen_project.py
+++ b/backend_addon/hooks/post_gen_project.py
@@ -1,65 +1,63 @@
"""Post generation hook."""
-import subprocess
-import sys
+from copy import deepcopy
from collections import OrderedDict
from pathlib import Path
-from cookieplone.utils import console, files
+from cookieplone.utils import console, files, git
+
context: OrderedDict = {{cookiecutter}}
+
# PATH OF CONTENT TO BE REMOVED
-TO_REMOVE_PATHS = {
+FEATURES_TO_REMOVE = {
"feature_headless": [
"serializers",
]
}
+def handle_feature_headless(context: OrderedDict, output_dir: Path):
+ package_namespace = context.get("__package_namespace")
+ package_name = context.get("__package_name")
+ output_dir = output_dir / "src" / package_namespace / package_name
+ files.remove_files(output_dir, FEATURES_TO_REMOVE["feature_headless"])
-def run_cmd(command: str, shell: bool, cwd: str) -> bool:
- proc = subprocess.run(command, shell=shell, cwd=cwd, capture_output=True)
- if proc.returncode:
- # Write errors to the main process stderr
- console.error(f"Error while running {command}")
- return False if proc.returncode else True
-
-
-def remove_files(category: str):
- to_remove = TO_REMOVE_PATHS.get(category, [])
- package_namespace = "{{ cookiecutter.__package_namespace }}"
- package_name = "{{ cookiecutter.__package_name }}"
- base_path = Path("src") / package_namespace / package_name
- # Remove all files
- files.remove_files(base_path, to_remove)
-
-def initialize_git():
- """Apply black and isort to the generated codebase."""
- console.info("Git repository")
- steps = [
- ["Initialize", ["git", "init", "."], False, "."],
- ["Add files", ["git", "add", "."], False, "."],
- ]
- for step in steps:
- msg, command, shell, cwd = step
- console.info(f" - {msg}")
- result = run_cmd(command, shell=shell, cwd=cwd)
- if not result:
- sys.exit(1)
+def handle_git_initialization(context: OrderedDict, output_dir: Path):
+ """Initialize a GIT repository for the project codebase."""
+ git.initialize_repository(output_dir)
def main():
"""Final fixes."""
- keep_headless = int(context.get("feature_headless"))
- if not keep_headless:
- remove_files("feature_headless")
- if int(context.get("__backend_addon_git_initialize")):
- initialize_git()
+ output_dir = Path().cwd()
+ remove_headless = not int(context.get("feature_headless"))
+ initialize_git = bool(int(context.get("__backend_addon_git_initialize")))
+ # Cleanup / Git
+ actions = [
+ [
+ handle_feature_headless,
+ "Remove files used in headless setup",
+ remove_headless,
+ ],
+ [
+ handle_git_initialization,
+ "Initialize Git repository",
+ initialize_git,
+ ],
+ ]
+ for func, title, enabled in actions:
+ if not int(enabled):
+ continue
+ new_context = deepcopy(context)
+ console.print(f" -> {title}")
+ func(new_context, output_dir)
+
msg = """
[bold blue]{{ cookiecutter.title }}[/bold blue]
- Now, enter the repositorym run the code formatter with:
+ Now, enter the repository run the code formatter with:
make format
diff --git a/backend_addon/tests/conftest.py b/backend_addon/tests/conftest.py
index 94f1e13..12a2f29 100644
--- a/backend_addon/tests/conftest.py
+++ b/backend_addon/tests/conftest.py
@@ -25,6 +25,7 @@
"pyproject.toml",
"README.md",
"requirements.txt",
+ "scripts/create_site.py",
"setup.py",
"tox.ini",
]
@@ -88,6 +89,7 @@ def context(cookieplone_root) -> dict:
"author": "Plone Collective",
"email": "collective@plone.org",
"feature_headless": "1",
+ "__backend_addon_git_initialize": "1",
"__cookieplone_repository_path": f"{cookieplone_root}",
}
@@ -100,6 +102,14 @@ def context_no_headless(context) -> dict:
new_context["feature_headless"] = "0"
return new_context
+@pytest.fixture(scope="session")
+def context_no_git(context) -> dict:
+ """Cookiecutter context without Git repository."""
+ new_context = deepcopy(context)
+ new_context["python_package_name"] = "collective.addonnogit"
+ new_context["__backend_addon_git_initialize"] = "0"
+ return new_context
+
@pytest.fixture(scope="session")
def bad_context() -> dict:
diff --git a/backend_addon/tests/test_cutter.py b/backend_addon/tests/test_cutter.py
index b9ba1be..246f8fc 100644
--- a/backend_addon/tests/test_cutter.py
+++ b/backend_addon/tests/test_cutter.py
@@ -2,6 +2,7 @@
import pytest
+from pathlib import Path
from .conftest import PKG_SRC_FEATURE_HEADLESS, PKG_SRC_FILES, ROOT_FILES
@@ -56,3 +57,34 @@ def test_pkg_src_feature_files_generated(cutter_result, file_path: str):
path = src_path / file_path
assert path.exists()
assert path.is_file()
+
+
+@pytest.mark.parametrize(
+ "file_path,schema_name",
+ [
+ [".github/workflows/meta.yml", "github-workflow"],
+ [".pre-commit-config.yaml", "pre-commit-config"],
+ ["pyproject.toml", "pyproject"],
+ ],
+)
+def test_json_schema(
+ cutter_result, schema_validate_file, file_path: str, schema_name: str
+):
+ path = cutter_result.project_path / file_path
+ assert schema_validate_file(path, schema_name)
+
+
+def test_git_initialization(cutter_result):
+ from cookieplone.utils import git
+
+ path = cutter_result.project_path
+ repo = git.repo_from_path(path)
+ assert Path(repo.working_dir) == path
+
+
+def test_git_initialization_not_set(cookies, context_no_git):
+ from cookieplone.utils import git
+
+ cutter_result = cookies.bake(extra_context=context_no_git)
+ path = cutter_result.project_path
+ assert git.check_path_is_repository(path) is False
diff --git a/backend_addon/{{ cookiecutter.__folder_name }}/.github/workflows/meta.yml b/backend_addon/{{ cookiecutter.__folder_name }}/.github/workflows/meta.yml
index 39a164d..96a81a4 100644
--- a/backend_addon/{{ cookiecutter.__folder_name }}/.github/workflows/meta.yml
+++ b/backend_addon/{{ cookiecutter.__folder_name }}/.github/workflows/meta.yml
@@ -1,5 +1,5 @@
# Generated from:
-# https://github.com/plone/meta/tree/master/config/default
+# https://github.com/plone/meta/tree/main/config/default
# See the inline comments on how to expand/tweak this configuration file
name: Meta
on:
@@ -28,14 +28,15 @@ jobs:
uses: plone/meta/.github/workflows/qa.yml@main
test:
uses: plone/meta/.github/workflows/test.yml@main
+ with:
+
+ py-versions: '["3.12", "3.11", "3.10"]'
coverage:
uses: plone/meta/.github/workflows/coverage.yml@main
dependencies:
uses: plone/meta/.github/workflows/dependencies.yml@main
release_ready:
uses: plone/meta/.github/workflows/release_ready.yml@main
- circular:
- uses: plone/meta/.github/workflows/circular.yml@main
##
# To modify the list of default jobs being created add in .meta.toml:
@@ -57,6 +58,13 @@ jobs:
# os_dependencies = "git libxml2 libxslt"
##
+##
+# To test against a specific matrix of python versions
+# when running tests jobs, add in .meta.toml:
+# [github]
+# py_versions = "['3.12', '3.11']"
+##
+
##
# Specify additional jobs in .meta.toml:
diff --git a/backend_addon/{{ cookiecutter.__folder_name }}/.meta.toml b/backend_addon/{{ cookiecutter.__folder_name }}/.meta.toml
index 8cb7797..133695b 100644
--- a/backend_addon/{{ cookiecutter.__folder_name }}/.meta.toml
+++ b/backend_addon/{{ cookiecutter.__folder_name }}/.meta.toml
@@ -1,19 +1,30 @@
# Generated from:
-# https://github.com/plone/meta/tree/master/config/default
+# https://github.com/plone/meta/tree/main/config/default
# See the inline comments on how to expand/tweak this configuration file
[meta]
template = "default"
-commit-id = "25d2fa7f"
+commit-id = "71d0218b"
[pyproject]
codespell_skip = "*.min.js"
codespell_ignores = "vew"
-dependencies_ignores = "['plone.volto', 'zestreleaser.towncrier', 'zest.releaser', 'pytest', 'pytest-cov', 'pytest-plone']"
dependencies_mappings = [
- "Plone = ['Products.CMFPlone', 'Products.CMFCore', 'Products.GenericSetup']",
- ]
+ "pytest-plone = ['pytest', 'plone.testing', 'plone.app.testing']",
+]
+dependencies_ignores = "['plone.app.iterate', 'plone.app.upgrade', 'plone.volto', 'zestreleaser.towncrier', 'zest.releaser', 'pytest-cov']"
[tox]
-use_mxdev = true
test_runner = "pytest"
test_path = "/tests"
+use_mxdev = true
+test_deps_additional = ""
+
+[github]
+py_versions = "[\"3.12\", \"3.11\", \"3.10\"]"
+jobs = [
+ "qa",
+ "test",
+ "coverage",
+ "dependencies",
+ "release_ready",
+ ]
diff --git a/backend_addon/{{ cookiecutter.__folder_name }}/MANIFEST.in b/backend_addon/{{ cookiecutter.__folder_name }}/MANIFEST.in
index 40ac789..3123abd 100644
--- a/backend_addon/{{ cookiecutter.__folder_name }}/MANIFEST.in
+++ b/backend_addon/{{ cookiecutter.__folder_name }}/MANIFEST.in
@@ -2,6 +2,8 @@ graft src/{{ cookiecutter.__package_namespace }}
graft docs
graft news
graft tests
+graft scripts
+include *.acceptance
include .coveragerc
include .dockerignore
include .editorconfig
diff --git a/backend_addon/{{ cookiecutter.__folder_name }}/Makefile b/backend_addon/{{ cookiecutter.__folder_name }}/Makefile
index 1d7c8a3..aeea158 100644
--- a/backend_addon/{{ cookiecutter.__folder_name }}/Makefile
+++ b/backend_addon/{{ cookiecutter.__folder_name }}/Makefile
@@ -51,11 +51,13 @@ bin/pip bin/tox bin/mxdev:
bin/pip install -U "pip" "wheel" "cookiecutter" "mxdev" "tox" "pre-commit"
if [ -d $(GIT_FOLDER) ]; then bin/pre-commit install; else echo "$(RED) Not installing pre-commit$(RESET)";fi
-.PHONY: config
-config: bin/pip ## Create instance configuration
+instance/etc/zope.ini: bin/pip ## Create instance configuration
@echo "$(GREEN)==> Create instance configuration$(RESET)"
bin/cookiecutter -f --no-input --config-file instance.yaml gh:plone/cookiecutter-zope-instance
+.PHONY: config
+config: instance/etc/zope.ini
+
.PHONY: build-dev
build-dev: config ## pip install Plone packages
@echo "$(GREEN)==> Setup Build$(RESET)"
@@ -65,11 +67,9 @@ build-dev: config ## pip install Plone packages
.PHONY: install
install: build-dev ## Install Plone 6.0
-
.PHONY: build
build: build-dev ## Install Plone 6.0
-
.PHONY: clean
clean: ## Remove old virtualenv and creates a new one
@echo "$(RED)==> Cleaning environment and build$(RESET)"
@@ -80,9 +80,13 @@ start: ## Start a Plone instance on localhost:8080
PYTHONWARNINGS=ignore ./bin/runwsgi instance/etc/zope.ini
.PHONY: console
-console: ## Start a zope console
+console: instance/etc/zope.ini ## Start a zope console
PYTHONWARNINGS=ignore ./bin/zconsole debug instance/etc/zope.conf
+.PHONY: create-site
+create-site: instance/etc/zope.ini ## Create a new site from scratch
+ PYTHONWARNINGS=ignore ./bin/zconsole run instance/etc/zope.conf ./scripts/create_site.py
+
.PHONY: format
format: bin/tox ## Format the codebase according to our standards
@echo "$(GREEN)==> Format codebase$(RESET)"
@@ -100,7 +104,7 @@ bin/i18ndude: bin/pip
.PHONY: i18n
i18n: bin/i18ndude ## Update locales
@echo "$(GREEN)==> Updating locales$(RESET)"
- bin/update_dist_locale
+ bin/update_locale
# Tests
.PHONY: test
diff --git a/backend_addon/{{ cookiecutter.__folder_name }}/pyproject.toml b/backend_addon/{{ cookiecutter.__folder_name }}/pyproject.toml
index e9b79b5..c982aa9 100644
--- a/backend_addon/{{ cookiecutter.__folder_name }}/pyproject.toml
+++ b/backend_addon/{{ cookiecutter.__folder_name }}/pyproject.toml
@@ -1,6 +1,9 @@
# Generated from:
-# https://github.com/plone/meta/tree/master/config/default
+# https://github.com/plone/meta/tree/main/config/default
# See the inline comments on how to expand/tweak this configuration file
+[build-system]
+requires = ["setuptools>=68.2"]
+
[tool.towncrier]
directory = "news/"
filename = "CHANGES.md"
@@ -118,8 +121,8 @@ Zope = [
'Products.CMFCore', 'Products.CMFDynamicViewFTI',
]
python-dateutil = ['dateutil']
-ignore-packages = ['plone.volto', 'zestreleaser.towncrier', 'zest.releaser', 'pytest', 'pytest-cov', 'pytest-plone']
-Plone = ['Products.CMFPlone', 'Products.CMFCore', 'Products.GenericSetup']
+pytest-plone = ['pytest', 'plone.testing', 'plone.app.testing']
+ignore-packages = ['plone.app.iterate', 'plone.app.upgrade', 'plone.volto', 'zestreleaser.towncrier', 'zest.releaser', 'pytest-cov']
##
# Add extra configuration options in .meta.toml:
@@ -129,19 +132,20 @@ Plone = ['Products.CMFPlone', 'Products.CMFCore', 'Products.GenericSetup']
# "gitpython = ['git']",
# "pygithub = ['github']",
# ]
-# """
##
[tool.check-manifest]
ignore = [
".editorconfig",
+ ".flake8",
".meta.toml",
".pre-commit-config.yaml",
- "tox.ini",
- ".flake8",
+ "dependabot.yml",
"mx.ini",
+ "tox.ini",
]
+
##
# Add extra configuration options in .meta.toml:
# [pyproject]
@@ -149,6 +153,11 @@ ignore = [
# "*.map.js",
# "*.pyc",
# """
+# check_manifest_extra_lines = """
+# ignore-bad-ideas = [
+# "some/test/file/PKG-INFO",
+# ]
+# """
##
diff --git a/project/{{ cookiecutter.__folder_name }}/backend/scripts/create_site.py b/backend_addon/{{ cookiecutter.__folder_name }}/scripts/create_site.py
similarity index 81%
rename from project/{{ cookiecutter.__folder_name }}/backend/scripts/create_site.py
rename to backend_addon/{{ cookiecutter.__folder_name }}/scripts/create_site.py
index 00a4e15..e4e19f0 100644
--- a/project/{{ cookiecutter.__folder_name }}/backend/scripts/create_site.py
+++ b/backend_addon/{{ cookiecutter.__folder_name }}/scripts/create_site.py
@@ -1,5 +1,5 @@
from AccessControl.SecurityManagement import newSecurityManager
-from {{ cookiecutter.python_package_name }}.interfaces import I{{ cookiecutter.__python_package_name_upper }}Layer
+from {{ cookiecutter.python_package_name }}.interfaces import IBrowserLayer
from Products.CMFPlone.factory import _DEFAULT_PROFILE
from Products.CMFPlone.factory import addPloneSite
from Testing.makerequest import makerequest
@@ -27,13 +27,11 @@ def asbool(s):
DELETE_EXISTING = asbool(os.getenv("DELETE_EXISTING"))
-app = makerequest(app) # noQA
+app = makerequest(globals()["app"])
request = app.REQUEST
-ifaces = [
- I{{ cookiecutter.__python_package_name_upper }}Layer,
-] + list(directlyProvidedBy(request))
+ifaces = [IBrowserLayer] + list(directlyProvidedBy(request))
directlyProvides(request, *ifaces)
@@ -47,11 +45,10 @@ def asbool(s):
"profile_id": _DEFAULT_PROFILE,
"extension_ids": [
"{{ cookiecutter.python_package_name }}:default",
- "{{ cookiecutter.python_package_name }}:initial",
],
"setup_content": False,
"default_language": "{{ cookiecutter.__profile_language }}",
- "portal_timezone": "America/Sao_Paulo",
+ "portal_timezone": "UTC",
}
if site_id in app.objectIds() and DELETE_EXISTING:
diff --git a/backend_addon/{{ cookiecutter.__folder_name }}/setup.py b/backend_addon/{{ cookiecutter.__folder_name }}/setup.py
index 15eafc3..6d81f6c 100644
--- a/backend_addon/{{ cookiecutter.__folder_name }}/setup.py
+++ b/backend_addon/{{ cookiecutter.__folder_name }}/setup.py
@@ -54,6 +54,7 @@
"plone.api",
{%- if cookiecutter.feature_headless == '1' %}
"plone.restapi",
+ "plone.volto",
{%- endif %}
],
extras_require={
@@ -64,13 +65,13 @@
"plone.restapi[test]",
"pytest",
"pytest-cov",
- "pytest-plone>=0.2.0",
+ "pytest-plone>=0.5.0",
],
},
entry_points="""
[z3c.autoinclude.plugin]
target = plone
[console_scripts]
- update_dist_locale = {{ cookiecutter.python_package_name }}.locales.update:update_locale
+ update_locale = {{ cookiecutter.python_package_name }}.locales.update:update_locale
""",
)
diff --git a/backend_addon/{{ cookiecutter.__folder_name }}/src/{{ cookiecutter.__package_namespace }}/{{ cookiecutter.__package_name }}/profiles/default/metadata.xml b/backend_addon/{{ cookiecutter.__folder_name }}/src/{{ cookiecutter.__package_namespace }}/{{ cookiecutter.__package_name }}/profiles/default/metadata.xml
index 9f3dc35..8d8f114 100644
--- a/backend_addon/{{ cookiecutter.__folder_name }}/src/{{ cookiecutter.__package_namespace }}/{{ cookiecutter.__package_name }}/profiles/default/metadata.xml
+++ b/backend_addon/{{ cookiecutter.__folder_name }}/src/{{ cookiecutter.__package_namespace }}/{{ cookiecutter.__package_name }}/profiles/default/metadata.xml
@@ -2,6 +2,9 @@
{{ cookiecutter.__profile_version }}
-
+ {%- if cookiecutter.feature_headless == '1' %}
+ profile-plone.restapi:default
+ profile-plone.volto:default
+ {%- endif %}
diff --git a/project/cookiecutter.json b/project/cookiecutter.json
index 2fe704a..03af39f 100644
--- a/project/cookiecutter.json
+++ b/project/cookiecutter.json
@@ -69,6 +69,9 @@
"__devops_varnish_version": "7.4",
"__devops_db_version": "14",
"__devops_db_password": "{{ random_ascii_string(12) }}",
+ "__backend_addon_git_initialize": "0",
+ "__frontend_addon_git_initialize": "0",
+ "__project_git_initialize": "1",
"__prompts__": {
"title": "Project Title",
"project_slug": "Project Slug (Used for repository id)",
diff --git a/project/hooks/post_gen_project.py b/project/hooks/post_gen_project.py
index a4e1900..86badaa 100644
--- a/project/hooks/post_gen_project.py
+++ b/project/hooks/post_gen_project.py
@@ -5,12 +5,16 @@
from pathlib import Path
from cookieplone import generator
-from cookieplone.utils import console, files
+from cookieplone.utils import console, files, git
context: OrderedDict = {{cookiecutter}}
-BACKEND_ADDON_REMOVE = [".github", ".git"]
+BACKEND_ADDON_REMOVE = [
+ ".github",
+ ".git",
+ ".meta.toml",
+]
FRONTEND_ADDON_REMOVE = [".github"]
@@ -35,24 +39,27 @@
}
-def prepare_devops(context: OrderedDict, output_dir: Path):
- """Clean up devops."""
- keep_ansible = int(context.get("devops_ansible"))
- keep_gha_manual_deploy = int(context.get("devops_gha_deploy"))
- to_remove = []
- if not keep_ansible:
- to_remove.extend(DEVOPS_TO_REMOVE["ansible"])
- if not keep_gha_manual_deploy:
- to_remove.extend(DEVOPS_TO_REMOVE["gha"])
- files.remove_files(output_dir, to_remove)
+def handle_devops_ansible(context: OrderedDict, output_dir: Path):
+ """Clean up ansible."""
+ files.remove_files(output_dir, DEVOPS_TO_REMOVE["ansible"])
+
+
+def handle_devops_gha_deploy(context: OrderedDict, output_dir: Path):
+ """Clean up ansible."""
+ files.remove_files(output_dir, DEVOPS_TO_REMOVE["gha"])
+
+
+def handle_git_initialization(context: OrderedDict, output_dir: Path):
+ """Initialize a GIT repository for the project codebase."""
+ git.initialize_repository(output_dir)
def generate_backend_addon(context, output_dir):
"""Run Plone Addon generator."""
output_dir = output_dir
folder_name = "backend"
- # Do not initialize the repository
- context["__backend_addon_git_initialize"] = "0"
+ # Headless
+ context["feature_headless"] = "1"
generator.generate_subtemplate(
"backend_addon", output_dir, folder_name, context, BACKEND_ADDON_REMOVE
)
@@ -87,6 +94,32 @@ def generate_sub_project_settings(context: OrderedDict, output_dir: Path):
def main():
"""Final fixes."""
output_dir = Path().cwd()
+
+ # Cleanup / Git
+ actions = [
+ [
+ handle_devops_ansible,
+ "Remove Ansible files",
+ not int(context.get("devops_ansible")),
+ ],
+ [
+ handle_devops_gha_deploy,
+ "Remove GHA deployment files",
+ not int(context.get("devops_gha_deploy")),
+ ],
+ [
+ handle_git_initialization,
+ "Remove GHA deployment files",
+ bool(int(context.get("__project_git_initialize"))),
+ ],
+ ]
+ for func, title, enabled in actions:
+ if not int(enabled):
+ continue
+ new_context = deepcopy(context)
+ console.print(f" -> {title}")
+ func(new_context, output_dir)
+
subtemplates = context.get("__cookieplone_subtemplates", [])
funcs = {k: v for k, v in globals().items() if k.startswith("generate_")}
for template_id, title, enabled in subtemplates:
@@ -102,8 +135,6 @@ def main():
console.print(f" -> {title}")
func(new_context, output_dir)
- # Run devops
- prepare_devops(context, output_dir)
msg = """
[bold blue]{{ cookiecutter.title }}[/bold blue]
diff --git a/project/tests/conftest.py b/project/tests/conftest.py
index 766f0ed..fbd3647 100644
--- a/project/tests/conftest.py
+++ b/project/tests/conftest.py
@@ -33,6 +33,7 @@ def context(cookieplone_root) -> dict:
"frontend_addon_name": "volto-ploneorgbr",
"language_code": "en",
"github_organization": "plonegovbr",
+ "__project_git_initialize": "1",
"container_registry": "github",
"__cookieplone_repository_path": f"{cookieplone_root}",
}
@@ -46,6 +47,14 @@ def context_devops_cache(context) -> dict:
return new_context
+@pytest.fixture(scope="session")
+def context_no_git(context) -> dict:
+ """Cookiecutter context."""
+ new_context = deepcopy(context)
+ new_context["__project_git_initialize"] = "0"
+ return new_context
+
+
@pytest.fixture(scope="session")
def context_devops_no_cache(context) -> dict:
"""Cookiecutter context."""
diff --git a/project/tests/test_cutter.py b/project/tests/test_cutter.py
index 8ed7acf..526c8d9 100644
--- a/project/tests/test_cutter.py
+++ b/project/tests/test_cutter.py
@@ -48,3 +48,19 @@ def test_root_folders(cutter_result, folder_name: str):
"""Test folders were created."""
folder = cutter_result.project_path / folder_name
assert folder.is_dir()
+
+
+def test_git_initialization(cutter_result):
+ from cookieplone.utils import git
+
+ path = cutter_result.project_path
+ repo = git.repo_from_path(path)
+ assert Path(repo.working_dir) == path
+
+
+def test_git_initialization_not_set(cookies, context_no_git):
+ from cookieplone.utils import git
+
+ cutter_result = cookies.bake(extra_context=context_no_git)
+ path = cutter_result.project_path
+ assert git.check_path_is_repository(path) is False
diff --git a/project/tests/test_project_backend.py b/project/tests/test_project_backend.py
index 9595640..8063e46 100644
--- a/project/tests/test_project_backend.py
+++ b/project/tests/test_project_backend.py
@@ -1,5 +1,7 @@
"""Test Generator: /backend."""
+from pathlib import Path
+
import pytest
BACKEND_FILES = [
@@ -26,7 +28,7 @@ def test_backend_top_level_files(cutter_result, filename: str):
BACKEND_PACKAGE_FILES_PYTEST = [
- "src/ploneorgbr/setup.py",
+ "setup.py",
"src/plonegov/ploneorgbr/configure.zcml",
"src/plonegov/ploneorgbr/dependencies.zcml",
"src/plonegov/ploneorgbr/permissions.zcml",
@@ -49,6 +51,7 @@ def test_backend_package_files_pytest(cutter_result, filename: str):
FILES_TO_BE_REMOVED = [
".github",
".git",
+ ".meta.toml",
]
@@ -59,3 +62,32 @@ def test_backend_package_files_removed(cutter_result, filename: str):
path = backend_folder / filename
assert path.exists() is False
assert path.parent.exists()
+
+
+BACKEND_HEADLESS_FILE_CHECKS = [
+ ["setup.py", "plone.volto"],
+ ["setup.py", "plone.restapi"],
+ ["src/plonegov/ploneorgbr/dependencies.zcml", "plone.volto"],
+ ["src/plonegov/ploneorgbr/dependencies.zcml", "plone.restapi"],
+ ["src/plonegov/ploneorgbr/profiles/default/metadata.xml", "plone.restapi:default"],
+ ["src/plonegov/ploneorgbr/profiles/default/metadata.xml", "plone.volto:default"],
+]
+
+
+@pytest.mark.parametrize("filename,content", BACKEND_HEADLESS_FILE_CHECKS)
+def test_backend_headless_support(cutter_result, filename: str, content: str):
+ """Test backend files contain headless support."""
+ backend_folder = cutter_result.project_path / "backend"
+ path = backend_folder / filename
+ assert path.is_file()
+ assert content in path.read_text()
+
+
+def test_git_repo_is_the_project(cutter_result):
+ from cookieplone.utils import git
+
+ path = cutter_result.project_path
+ backend_path = path / "backend"
+ repo = git.repo_from_path(path)
+ assert Path(repo.working_dir) != backend_path
+ assert Path(repo.working_dir) == path
diff --git a/project/tests/test_project_cache.py b/project/tests/test_project_cache.py
index cc5b982..59d63da 100644
--- a/project/tests/test_project_cache.py
+++ b/project/tests/test_project_cache.py
@@ -31,3 +31,34 @@ def test_project_no_cache(cutter_result_devops_no_cache, filepath: str):
folder = cutter_result_devops_no_cache.project_path
path = folder / filepath
assert path.exists() is False
+
+
+CACHE_CONFIGURATION = [
+ [
+ "backend/src/plonegov/ploneorgbr/profiles/default/metadata.xml",
+ "plone.app.caching:default",
+ ],
+ [
+ "backend/src/plonegov/ploneorgbr/profiles/default/metadata.xml",
+ "plone.app.caching:with-caching-proxy",
+ ],
+ ["backend/src/plonegov/ploneorgbr/dependencies.zcml", "plone.app.caching"],
+]
+
+
+@pytest.mark.parametrize("filepath,content", CACHE_CONFIGURATION)
+def test_project_no_cache_no_config(
+ cutter_result_devops_no_cache, filepath: str, content: str
+):
+ """Test Cache-related configurations are not present."""
+ folder = cutter_result_devops_no_cache.project_path
+ file_content = (folder / filepath).read_text()
+ assert content not in file_content
+
+
+@pytest.mark.parametrize("filepath,content", CACHE_CONFIGURATION)
+def test_project_no_cache_config(cutter_result, filepath: str, content: str):
+ """Test Cache-related configurations are not present."""
+ folder = cutter_result.project_path
+ file_content = (folder / filepath).read_text()
+ assert content in file_content
diff --git a/project/{{ cookiecutter.__folder_name }}/backend/Dockerfile b/project/{{ cookiecutter.__folder_name }}/backend/Dockerfile
index 4b996a6..f89f61f 100644
--- a/project/{{ cookiecutter.__folder_name }}/backend/Dockerfile
+++ b/project/{{ cookiecutter.__folder_name }}/backend/Dockerfile
@@ -12,7 +12,7 @@ RUN <=2.0.0
diff --git a/project/{{ cookiecutter.__folder_name }}/backend/instance.yaml b/project/{{ cookiecutter.__folder_name }}/backend/instance.yaml
deleted file mode 100644
index 3dc4038..0000000
--- a/project/{{ cookiecutter.__folder_name }}/backend/instance.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-default_context:
- initial_user_name: 'admin'
- initial_user_password: 'admin'
- zcml_package_includes: '{{ cookiecutter.python_package_name }}'
-
- db_storage: direct
diff --git a/requirements.txt b/requirements.txt
index 27e8647..31b9499 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,6 +4,6 @@ isort
pytest
pytest-cookies
pytest-jsonschema >= 1.0.0a2
-cookieplone>=0.5.6
+cookieplone>=0.6.1
GitPython
wheel
diff --git a/sub/cache/hooks/post_gen_project.py b/sub/cache/hooks/post_gen_project.py
new file mode 100644
index 0000000..f7d8660
--- /dev/null
+++ b/sub/cache/hooks/post_gen_project.py
@@ -0,0 +1,49 @@
+"""Post generation hook."""
+
+from collections import OrderedDict
+from pathlib import Path
+from typing import Callable
+
+from cookieplone.utils import console, plone
+
+context: OrderedDict = {{cookiecutter}}
+
+
+def update_file(filepath: Path, func: Callable, content: str) -> Path:
+ src_data = filepath.read_text()
+ filepath.write_text(func(content, src_data))
+ return filepath
+
+
+def set_configurations(package_root: Path, context: OrderedDict):
+ """Adjust dependencies.zcml and profiles/default/metadata.xml."""
+ info = [
+ (
+ "profiles/default/metadata.xml",
+ plone.add_dependency_profile_to_metadata,
+ "plone.app.caching:default",
+ ),
+ (
+ "profiles/default/metadata.xml",
+ plone.add_dependency_profile_to_metadata,
+ "plone.app.caching:with-caching-proxy",
+ ),
+ ("dependencies.zcml", plone.add_dependency_to_zcml, "plone.app.caching"),
+ ]
+ for path, func, content in info:
+ filepath: Path = package_root / path
+ if filepath.exists():
+ filepath = update_file(filepath, func, content)
+
+
+def main():
+ """Final fixes."""
+ output_dir = Path().cwd()
+ namespace = context.get("__package_namespace")
+ package_name = context.get("__package_name")
+ package_root = output_dir / "backend/src" / namespace / package_name
+ set_configurations(package_root, context)
+
+
+if __name__ == "__main__":
+ main()