Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial commit for the Seven addon #128

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions seven_addon/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
volto-addon
44 changes: 44 additions & 0 deletions seven_addon/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
67 changes: 67 additions & 0 deletions seven_addon/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
[![Cookieplone Frontend Add-on CI](https://github.com/plone/cookieplone-templates/actions/workflows/frontend_addon.yml/badge.svg)](https://github.com/plone/cookieplone-templates/actions/workflows/frontend_addon.yml)
[![Built with Cookiecutter](https://img.shields.io/badge/built%20with-Cookiecutter-ff69b4.svg?logo=cookiecutter)](https://github.com/plone/cookieplone-templates/)
![GitHub](https://img.shields.io/github/license/plone/cookiecutter-plone)
[![Black code style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)

# Cookieplone Frontend Add-on

Powered by [cookieplone](https://github.com/plone/cookieplone) and [Cookiecutter](https://github.com/cookiecutter/cookiecutter), [Cookieplone Frontend Add-on](https://github.com/plone/cookieplone-templates/frontend_addon) is intended to be used by Plone developers to create new add-on packages for Volto.

## Getting Started 🏁

### Prerequisites

- **pipx**: A handy tool for installing and running Python applications.

### Installation Guide 🛠️

1. **pipx**

```shell
pip install pipx
```

### Generate Your Plone Add-on 🎉

```shell
pipx run cookieplone frontend_addon
```

## Project Generation Options

These are all the template options that will be prompted by the [Cookiecutter CLI](https://github.com/cookiecutter/cookiecutter) before generating your project.

| Option | Description | Example |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
| `frontend_addon_name` | Your addon's short name. | **volto-weather-block** |
| `title` | Your addon's human-readable name, capitals and spaces allowed. | **Weather Block for Volto** |
| `description` | Describes your add-on and gets used in places like ``README.md`` and such. | **Add a weather block to your site.** |
| `author` | This is you! The value goes into places like ``LICENSE``, ``package.json`` and such. | **Our Company** |
| `email` | The email address you want to identify yourself in the project. | **[email protected]** |
| `github_organization` | Used for GitHub repositories. | **collective** |
| `npm_package_name` | Name of the Node package, including the organization (if any). | **@plone-collective/volto-weather-block** |
| `volto_version` | Volto version to be used. | **18.0.0-alpha.31** |

## Code Quality Assurance 🧐

Your package comes equipped with linters to ensure code quality. Run the following to automatically format your code:

```shell
make format
```

## Internationalization 🌐

Generate translation files with ease:

```shell
make i18n
```

## License 📜

This project is licensed under the [MIT License](/LICENSE).

## Let's Get Building! 🚀

Happy coding!
41 changes: 41 additions & 0 deletions seven_addon/cookiecutter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"title": "Seven Add-on",
"frontend_addon_name": "{{ cookiecutter.title | slugify }}",
"description": "A new add-on for Seven",
"author": "Plone Community",
"email": "[email protected]",
"github_organization": "collective",
"npm_package_name": "{{ cookiecutter.frontend_addon_name }}",
"volto_version": "{{ 'Yes' | latest_volto }}",
"__folder_name": "{{ cookiecutter.frontend_addon_name }}",
"__npm_package_name": "{{ cookiecutter.npm_package_name }}",
"__version_package": "1.0.0",
"__version_plone_volto": "{{ cookiecutter.volto_version }}",
"__version_mrs_developer": "^2.2.0",
"__version_pnpm": "10.4.1",
"__version_release_it": "^17.1.1",
"__version_pre_commit": "3.7.1",
"__gha_version_node": "22.x",
"__gha_version_checkout": "v4",
"__gha_version_setup_node": "v4",
"__gha_version_cache": "v4",
"__gha_version_background_action": "v1",
"__gha_version_upload_artifact": "v4",
"__gha_version_pages_deploy": "v4",
"__generator_date_long": "{% now 'utc', '%Y-%m-%d %H:%M:%S' %}",
"__generator_signature": "This was generated by [cookiecutter-volto](https://github.com/plone/cookiecutter-volto/frontend_addon) on {{ cookiecutter.__generator_date_long }}",
"__prompts__": {
"frontend_addon_name": "Add-on (Short name of the addon)",
"title": "Add-on Title",
"description": "A short description of your addon",
"github_organization": "GitHub Username or Organization",
"npm_package_name": "Package name on NPM",
"volto_version": "Volto version",
"author": "Author",
"email": "Author E-mail"
},
"_copy_without_render": [],
"_extensions": ["cookieplone.filters.latest_volto"],
"__cookieplone_repository_path": "",
"__cookieplone_template": ""
}
30 changes: 30 additions & 0 deletions seven_addon/hooks/post_gen_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""Post generation hook."""

from cookieplone.utils import console


def main():
"""Final fixes."""
msg = """
[bold blue]{{ cookiecutter.frontend_addon_name }}[/bold blue]

Now, enter the generated directory and finish the install:

cd {{ cookiecutter.frontend_addon_name }}
make install

start coding, and push to your organization.

Sorry for the convenience,
The Plone Community.
"""
console.panel(
title=":tada: New addon was generated :tada:",
subtitle="",
msg=msg,
url="https://plone.org/",
)


if __name__ == "__main__":
main()
69 changes: 69 additions & 0 deletions seven_addon/hooks/pre_gen_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""Pre generation hook."""

import sys
from pathlib import Path
from textwrap import dedent

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

output_path = Path().resolve()

context = {
"frontend_addon_name": "{{ cookiecutter.frontend_addon_name }}",
"title": "{{ cookiecutter.title }}",
"description": "{{ cookiecutter.description }}",
"author": "{{ cookiecutter.author }}",
"email": "{{ cookiecutter.email }}",
"github_organization": "{{ cookiecutter.github_organization }}",
"npm_package_name": "{{ cookiecutter.__npm_package_name }}",
}


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("npm_package_name", validators.validate_npm_package_name),
]
result = validators.run_context_validations(context, validations)
return result


def main():
"""Validate context."""
validation_result = check_errors(context)
success = validation_result.status
if not success:
msg = dedent(
"""
[bold red]Error[/bold red]
It will not be possible to generate the addon.

Please review the errors:
"""
)
for validation in validation_result.validations:
if validation.status:
continue
label = "red"
msg = (
f"{msg}\n - {validation.key}: [{label}]{validation.message}[/{label}]"
)
else:
msg = dedent(
f"""
Summary:

- Volto version: [bold blue]{{ cookiecutter.__version_plone_volto }}[/bold blue]
- Output folder: [bold blue]{output_path}[/bold blue]

"""
)
console.panel(title="{{ cookiecutter.title }} generation", msg=msg)
if not success:
sys.exit(1)


if __name__ == "__main__":
main()
63 changes: 63 additions & 0 deletions seven_addon/hooks/pre_prompt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""Pre Prompt hook."""

import sys
from textwrap import dedent

try:
from cookieplone import data
from cookieplone.utils import commands, console, sanity

HAS_COOKIEPLONE = True
except ModuleNotFoundError:
HAS_COOKIEPLONE = False


SUPPORTED_NODE_VERSIONS = [
"18",
"19",
"20",
"21",
"22",
]


def sanity_check() -> data.SanityCheckResults:
"""Run sanity checks on the system."""
checks = [
data.SanityCheck(
"Node",
commands.check_node_version,
[SUPPORTED_NODE_VERSIONS],
"error",
),
data.SanityCheck("git", commands.check_command_is_available, ["git"], "error"),
]
result = sanity.run_sanity_checks(checks)
return result


def main():
"""Validate context."""
if not HAS_COOKIEPLONE:
print("This template should be run with cookieplone")
sys.exit(1)

check_results = sanity_check()
msg = dedent(
"""
Creating a new Seven Addon

Sanity check results:

"""
)
for check in check_results.checks:
label = "green" if check.status else "red"
msg = f"{msg}\n - {check.name}: [{label}]{check.message}[/{label}]"
console.panel(title="Volto Addon Generator", msg=f"{msg}\n")
if not check_results.status:
sys.exit(1)


if __name__ == "__main__":
main()
Empty file added seven_addon/tests/__init__.py
Empty file.
67 changes: 67 additions & 0 deletions seven_addon/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""Pytest configuration."""

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

import pytest


@pytest.fixture(scope="session")
def cookieplone_root() -> dict:
"""Cookieplone root dir."""
parent = Path().cwd().resolve().parent
return parent


@pytest.fixture(scope="session")
def context(cookieplone_root) -> dict:
"""Cookiecutter context."""
return {
"frontend_addon_name": "volto-addon",
"title": "Volto Add-on",
"description": "Add new features to your Volto Project.",
"author": "Plone Collective",
"email": "[email protected]",
"github_organization": "collective",
"npm_package_name": "@plone-collective/volto-addon",
"volto_version": "18.0.0-alpha.31",
"__cookieplone_repository_path": f"{cookieplone_root}",
}


@pytest.fixture(scope="session")
def context_no_npm_organization(context) -> dict:
"""Cookiecutter context without a NPM organization."""
new_context = deepcopy(context)
new_context["npm_package_name"] = "volto-addon"
return new_context


@pytest.fixture(scope="session")
def bad_context() -> dict:
"""Cookiecutter context with invalid data."""
return {
"frontend_addon_name": "volto addon",
"title": "Volto Add-on",
"description": "Add new features to your Volto Project.",
"github_organization": "collective",
"npm_package_name": "plone-collective/volto-addon",
"author": "Plone Collective",
"email": "[email protected]",
}


@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)
Loading