Skip to content

Commit

Permalink
Support creation of a project without an addon
Browse files Browse the repository at this point in the history
  • Loading branch information
ericof committed May 16, 2024
1 parent cf7bdb5 commit 36e1f85
Show file tree
Hide file tree
Showing 16 changed files with 409 additions and 12 deletions.
48 changes: 48 additions & 0 deletions .github/workflows/sub_frontend_project.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Plone Frontend Project CI
on:
push:
paths:
- "sub/frontend_project/**"
- ".github/workflows/sub_frontend_project.yml"
workflow_dispatch:

env:
NODE_VERSION: 20.x
PYTHON_VERSION: "3.10"

jobs:

generation:

runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
python-version:
- "3.10"
- "3.11"
- "3.12"

steps:
# git checkout
- name: Checkout codebase
uses: actions/checkout@v4

# python setup
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'

# python install
- name: Install dependencies
run: |
pip install -r requirements.txt
# Test
- name: Run tests
run: |
cd sub/frontend_project
python -m pytest tests
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,14 @@ format: bin/cookieplone ## Format code
bin/isort hooks .scripts
$(MAKE) -C "./backend_addon/" format
$(MAKE) -C "./frontend_addon/" format
$(MAKE) -C "./sub/frontend_project/" format

.PHONY: test
test: bin/cookieplone ## Test all cookiecutters
@echo "$(GREEN)==> Test all cookiecutters$(RESET)"
$(MAKE) -C "./backend_addon/" test
$(MAKE) -C "./frontend_addon/" test
$(MAKE) -C "./sub/frontend_project/" test

.PHONY: report-context
report-context: bin/cookieplone ## Generate a report of all context options
Expand Down
4 changes: 1 addition & 3 deletions frontend_addon/hooks/pre_gen_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@
def check_errors(context: dict) -> data.ContextValidatorResult:
"""Check for errors in the provided data."""
validations = [
data.ItemValidator(
"frontend_addon_name", validators.validate_volto_addon_name
),
data.ItemValidator("frontend_addon_name", validators.validate_volto_addon_name),
data.ItemValidator("npm_package_name", validators.validate_npm_package_name),
]
result = validators.run_context_validations(context, validations)
Expand Down
2 changes: 1 addition & 1 deletion frontend_addon/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def context() -> dict:
"email": "[email protected]",
"github_organization": "collective",
"npm_package_name": "@plone-collective/volto-addon",
"volto_version": "18.0.0-alpha.31"
"volto_version": "18.0.0-alpha.31",
}


Expand Down
44 changes: 44 additions & 0 deletions sub/frontend_project/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
SHELL := /bin/bash
CURRENT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))


# We like colors
# From: https://coderwall.com/p/izxssa/colored-makefile-for-golang-projects
RED=`tput setaf 1`
GREEN=`tput setaf 2`
RESET=`tput sgr0`
YELLOW=`tput setaf 3`

.PHONY: all
all: build


# Add the following 'help' target to your Makefile
# And add help text after each target name starting with '\#\#'
.PHONY: help
help: ## This help message
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

.PHONY: clean
clean: ## Clean
rm -rf volto-addon

../../bin/cookieplone: ## cookieplone installation
$(MAKE) -C ".." bin/cookieplone

.PHONY: format
format: ../../bin/cookieplone ## Format code
@echo "$(GREEN)==> Formatting codebase $(RESET)"
../../bin/black hooks tests
../../bin/isort hooks tests

.PHONY: generate
generate: ../../bin/cookieplone ## Create a sample package
@echo "$(GREEN)==> Creating new test package$(RESET)"
rm -rf volto-addon
../../bin/cookiecutter . --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
6 changes: 5 additions & 1 deletion sub/frontend_project/cookiecutter.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"title": "Frontend Project",
"volto_version": "{{ 'Yes' | latest_volto }}",
"author": "Plone Community",
"email": "[email protected]",
"__folder_name": "app",
"__gha_enable": true,
"__version_plone_volto": "{{ cookiecutter.volto_version }}",
Expand All @@ -11,7 +13,9 @@
"title": "Project name",
"volto_version": "Volto version"
},
"_copy_without_render": [],
"_copy_without_render": [
"_project_files"
],
"_extensions": [
"cookieplone.filters.latest_volto"
]
Expand Down
23 changes: 17 additions & 6 deletions sub/frontend_project/hooks/post_gen_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
context = {{cookiecutter}}


TO_REMOVE = [
".github",
"packages/volto-addon"
]
LOCAL_FILES_FOLDER_NAME = "_project_files"


TO_REMOVE = [".github", "packages/volto-addon"]


def generate_addon(context, output_dir):
Expand All @@ -21,12 +21,22 @@ def generate_addon(context, output_dir):
output_dir = output_dir.parent
context["frontend_addon_name"] = "volto-addon"
generator.generate_subtemplate(
"volto_addon", output_dir, folder_name, context, TO_REMOVE
"../../frontend_addon", output_dir, folder_name, context, TO_REMOVE
)


def cleanup(context, output_dir):
"""Remove references to volto-addon."""
pass
project_files_folder = output_dir / LOCAL_FILES_FOLDER_NAME
project_files: list[Path] = [path for path in project_files_folder.glob("*")]
filenames = [path.name for path in project_files]
# Remove old files
files.remove_files(output_dir, filenames)
for path in project_files:
name = path.name
path.rename(output_dir / name)
# Remove templates folder
files.remove_files(output_dir, [LOCAL_FILES_FOLDER_NAME])


def main():
Expand All @@ -51,5 +61,6 @@ def main():
url="https://plone.org/",
)


if __name__ == "__main__":
main()
3 changes: 2 additions & 1 deletion sub/frontend_project/hooks/pre_gen_project.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""Pre generation hook."""

import sys
from collections import OrderedDict # noQA
from pathlib import Path
from textwrap import dedent
from collections import OrderedDict # noQA

from cookieplone import data
from cookieplone.utils import console, validators

Expand Down
File renamed without changes.
50 changes: 50 additions & 0 deletions sub/frontend_project/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Pytest configuration."""

import re
from copy import deepcopy
from pathlib import Path
from typing import List

import pytest


@pytest.fixture(scope="session")
def variable_pattern():
return re.compile("{{( ?cookiecutter)[.](.*?)}}")


@pytest.fixture(scope="session")
def context() -> dict:
"""Cookiecutter context."""
return {
"title": "Frontend project",
"author": "Plone Collective",
"email": "[email protected]",
"volto_version": "18.0.0-alpha.31",
}


@pytest.fixture(scope="session")
def bad_context() -> dict:
"""Cookiecutter context with invalid data."""
return {
"title": "Frontend project",
"author": "Plone Collective",
"email": "[email protected]",
"volto_version": "---",
}


@pytest.fixture
def build_files_list():
def func(root_dir: Path) -> List[Path]:
"""Build a list containing absolute paths to the generated files."""
return [path for path in Path(root_dir).glob("*") if path.is_file()]

return func


@pytest.fixture(scope="session")
def cutter_result(cookies_session, context):
"""Cookiecutter result."""
return cookies_session.bake(extra_context=context)
44 changes: 44 additions & 0 deletions sub/frontend_project/tests/test_cutter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""Test cookiecutter generation with all features enabled."""

from pathlib import Path

import pytest


def test_creation(cookies, context: dict):
"""Generated project should match provided value."""
result = cookies.bake(extra_context=context)
assert result.exception is None
assert result.exit_code == 0
assert result.project_path.name == "app"
assert result.project_path.is_dir()


def test_variable_substitution(build_files_list, variable_pattern, cutter_result):
"""Check if no file was unprocessed."""
paths = build_files_list(cutter_result.project_path)
for path in paths:
for line in open(path):
match = variable_pattern.search(line)
msg = f"cookiecutter variable not replaced in {path}"
assert match is None, msg


@pytest.mark.parametrize(
"file_path,text,expected",
[
[".eslintrc.js", "volto-addon", False],
["Makefile", "volto-addon", False],
["package.json", "volto-addon-dev", False],
["package.json", "project-dev", True],
["volto.config.js", "volto-addon", False],
],
)
def test_root_files_do_not_mention_addon(
cutter_result, file_path: Path, text: str, expected: bool
):
"""Check if root files were generated and have no reference to the addon."""
path = cutter_result.project_path / file_path
assert path.exists()
assert path.is_file()
assert (text in path.read_text()) is expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const fs = require('fs');
const projectRootPath = __dirname;

let coreLocation;
if (fs.existsSync(`${projectRootPath}/core`))
coreLocation = `${projectRootPath}/core`;
else if (fs.existsSync(`${projectRootPath}/../../core`))
coreLocation = `${projectRootPath}/../../core`;

module.exports = {
extends: `${coreLocation}/packages/volto/.eslintrc`,
rules: {
'import/no-unresolved': 1,
},
settings: {
'import/resolver': {
alias: {
map: [
['@plone/volto', `${coreLocation}/packages/volto/src`],
[
'@plone/volto-slate',
`${coreLocation}/core/packages/volto-slate/src`,
],
['@plone/registry', `${coreLocation}/packages/registry/src`],
],
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
},
},
},
};
Loading

0 comments on commit 36e1f85

Please sign in to comment.