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

New cookiecutter #29

Merged
merged 14 commits into from
Feb 26, 2024
Merged
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/tutor-contrib-myplugin
/tutor-contrib-*
__pycache__
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ Please respect the following instructions:

# Changelog

## 2024-01-01

- [Improvement] Happy New Year!
- Fix compatibility issue with Python 3.12 by removing dependency on `pkg_resources`.
- Cookiecutter hooks to check input data validation.
- Various licenses support.
- New documentation format.
- GitHub Actions for new plugins.
- `dev` mode added to extra entries.
(by @CodeWithEmad).

## 2023-11-21

- [Improvement] Mark compatibility with python 3.11 and 3.12 (by @CodeWithEmad).
Expand Down
1 change: 0 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ test-plugin-install: ## Smoke-test that the default plugin works with Tutor.
@echo "$(MSG)Testing that the generated plugin can be installed, enabled, and used in Tutor...$(END_MSG)"
pip install -e tutor-contrib-myplugin
tutor plugins enable myplugin
tutor config save
tutor myplugin example-command # This should just print a line and exit 0.
@echo "$(MSG)It seems like the generated plugin works with Tutor.$(END_MSG)"

Expand Down
168 changes: 23 additions & 145 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,176 +1,54 @@
Tutor plugin cookiecutter 🍪
============================
############################
regisb marked this conversation as resolved.
Show resolved Hide resolved

This is a `cookiecutter <https://cookiecutter.readthedocs.io/en/latest/tutorials/tutorial2.html>`__ for getting started with `Tutor plugins <https://docs.tutor.overhang.io/plugins/index.html>`__. It will generate a base scaffold for an empty tutor plugin that does, well, nothing.
This is a `cookiecutter <https://cookiecutter.readthedocs.io/en/latest/README.html>`__ for getting started with `Tutor plugins <https://docs.tutor.edly.io/plugins/index.html>`__. It will generate a base scaffold for an empty tutor plugin that does, well, nothing.

Requirements
------------
************

::
.. code-block:: bash

pip install cookiecutter
pip install -U cookiecutter

Usage
-----
*****

::
.. code-block:: bash

cookiecutter https://github.com/overhangio/cookiecutter-tutor-plugin.git

Please keep the "contrib" part in your generated package name to differentiate from official plugins.

Once you have generated your plugin, you can start using it right away (even if it won't do anything)::
Once you have generated your plugin, you can start using it right away (even if it won't do anything)

pip install -e ./tutor-myplugin
tutor plugins list # your plugin should appear here
tutor plugins enable myplugin # hack at it!
.. code-block:: bash

pip install -e ./tutor-contrib-myplugin
tutor plugins list # Your plugin should appear here
tutor plugins enable myplugin # Have fun!

Migrating from v0 plugins
-------------------------

The plugin API was upgraded from v0 to v1 in Tutor v13.2.0. This cookiecutter generates plugin scaffolds for v1. The v0 API will be supported for some time, but you are encouraged to upgrade your plugins. To upgrade a v0 plugin that was generated previously with this cookiecutter, perform the following steps:

- In setup.py: replace "tutor.plugin.v0" by "tutor.plugin.v1".

- In the templates folder: rename the "hooks" folder to "tasks".

- In plugin.py:

- At the top of the file, add the following line::

from tutor import hooks

- Modify the ``config`` object:

- If present, replace the "add" key by "unique".
- If present, replace the "set" key by "overrides".

- Delete the `templates` object.

- Replace the ``hooks`` object:

- Declare a "MY_INIT_TASKS" variable::

MY_INIT_TASKS = []

- If present, replace each "myservice" item in "init" by::

MY_INIT_TASKS.append((
"myservice",
("yourplugin", "tasks", "myservice", "init"),
10, # default task priority
))

- If present, replace each "myservice" item in "pre-init" by::

MY_INIT_TASKS.append((
"myservice",
("yourplugin", "tasks", "myservice", "pre-init"),
1, # high task priority (for pre-initialization)
))

- If present, replace each ``"myimage": "myimage:latest"`` key/value in "build-image" by::

hooks.Filters.IMAGES_BUILD.add_item((
"myimage",
("plugins", "yourplugin", "build", "myimage"),
"myimage:latest",
(),
))

- If present, replace each ``"myimage": "myimage:latest"`` key/value in "remote-image" by::

hooks.Filters.IMAGES_PULL.add_item((
"myimage",
"myimage:latest",
))
hooks.Filters.IMAGES_PUSH.add_item((
"myimage",
"myimage:latest",
))

- Delete the ``patches`` function.

- Add the following piece of code at the bottom of your file::

####### Boilerplate code
# Add the "templates" folder as a template root
hooks.Filters.ENV_TEMPLATE_ROOTS.add_item(
pkg_resources.resource_filename("tutoryourplugin", "templates")
)
# Render the "build" and "apps" folders
hooks.Filters.ENV_TEMPLATE_TARGETS.add_items(
[
("yourplugin/build", "plugins"),
("yourplugin/apps", "plugins"),
],
)
# Load patches from files
for path in glob(
os.path.join(
pkg_resources.resource_filename("tutoryourplugin", "patches"),
"*",
)
):
with open(path, encoding="utf-8") as patch_file:
hooks.Filters.ENV_PATCHES.add_item((os.path.basename(path), patch_file.read()))
# Add configuration entries
hooks.Filters.CONFIG_DEFAULTS.add_items(
[
(f"YOUR_PLUGIN_{key}", value)
for key, value in config.get("defaults", {}).items()
]
)
hooks.Filters.CONFIG_UNIQUE.add_items(
[
(f"YOUR_PLUGIN_{key}", value)
for key, value in config.get("unique", {}).items()
]
)
hooks.Filters.CONFIG_OVERRIDES.add_items(list(config.get("overrides", {}).items()))
# For each task added to MY_INIT_TASKS, load the task template and add it to the
# CLI_DO_INIT_TASKS filter, which tells Tutor to run it as part of the `init` job.
for service, template_path, priority in MY_INIT_TASKS:
full_path: str = pkg_resources.resource_filename(
"tutoryourplugin", os.path.join("templates", *template_path)
)
with open(full_path, encoding="utf-8") as init_task_file:
init_task: str = init_task_file.read()
hooks.Filters.CLI_DO_INIT_TASKS.add_item((service, init_task), priority=priority)


- In case the plugin has custom commands to be available from CLI, you will need to implement the CLI_COMMANDS filter according
to `Tutor's reference documentation <https://docs.tutor.overhang.io/reference/api/hooks/consts.html#tutor.hooks.Filters.CLI_COMMANDS>`__.
You can implement this filter by adding the following code line to plugin.py::
tutor_hooks.Filters.CLI_COMMANDS.add_item(command)

- Also, you will either need to rename the command function or use click's ``name=<plugin>`` argument.
For example, to ensure your plugin command(s) are available under ``tutor xqueue ...``, you could write::
@click.group(help="Interact with the Xqueue server", name="xqueue")
def command():
...

- Verify that the file contains no instance of "yourplugin" or "YOUR_PLUGIN". If it does, replace by your plugin name.

- Re-install your plugin.
- Verify that the plugin is listed when you run ``tutor plugins list``.
*************************

.. _Migrating from v0 plugins: docs/migrating-from-v0-plugins.rst
regisb marked this conversation as resolved.
Show resolved Hide resolved

The plugin API was upgraded from ``v0`` to ``v1`` in `Tutor v13.2.0 <https://github.com/overhangio/tutor/releases/tag/v13.2.0>`__. This cookiecutter generates plugin scaffolds for ``v1``. The ``v0`` API will be supported for some time, but you are encouraged to upgrade your plugins. To upgrade a ``v0`` plugin that was generated previously with this cookiecutter, please follow the instructions in the `Migrating from v0 plugins`_ section.

Troubleshooting
---------------
***************

This Tutor plugin template is maintained by `Emad Rad <https://github.com/CodeWithEmad>`_ from `edSPIRIT <https://edspirit.com>`_. Community support is available from the official `Open edX forum <https://discuss.openedx.org>`_.

Do you need help using this template? See the `troubleshooting <https://docs.tutor.overhang.io/troubleshooting.html>`__ section from the Tutor documentation.
Do you need help using this template? See the `troubleshooting <https://docs.tutor.edly.io/troubleshooting.html>`__ section from the Tutor documentation.

Contributing
------------
************

Pull requests are welcome! Please read the `"contributing" section from the Tutor documentation <https://docs.tutor.overhang.io/tutor.html#contributing>`__.
Pull requests are welcome! Please read the `"contributing" section from the Tutor documentation <https://docs.tutor.edly.io/tutor.html#contributing>`__.

Unlike other Tutor repositories, you do not need to run ``make changelog-entry``. Instead, simply edit CHANGELOG.md to note any changes that might affect plugin developers using the cookiecutter.
Unlike other Tutor repositories, you do not need to run ``make changelog-entry``. Instead, simply edit ``CHANGELOG.md`` to note any changes that might affect plugin developers using the cookiecutter.

License
-------
*******

This software is licensed under the terms of the `AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.en.html>`__.
28 changes: 24 additions & 4 deletions cookiecutter.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
{
regisb marked this conversation as resolved.
Show resolved Hide resolved
"plugin_name": "myplugin",
"package_name": "tutor-contrib-{{ cookiecutter.plugin_name }}",
"module_name": "tutor{{ cookiecutter.plugin_name.lower().replace('-', '_') }}",
"git_repo": "https://github.com/myusername/{{cookiecutter.package_name }}",
"package_name": "tutor-contrib-{{ cookiecutter.plugin_name.lower() | trim }}",
"module_name": "tutor{{ cookiecutter.plugin_name.lower().replace('-', '_') | trim }}",
"description": "{{ cookiecutter.plugin_name}} plugin for Tutor",
"git_repo": "https://github.com/myusername/{{ cookiecutter.package_name | trim }}",
"author": "John Doe",
"license": "AGPLv3"
"email": "john.doe@example.com",
"tutor_version": [17, 16, 15, 14, 13],
"version": "{{ cookiecutter.tutor_version }}.0.0",
"license": ["AGPLv3", "Apache 2.0", "BSDv3", "MIT", "Not open source"],
"init_git": "y",
"include_ci": "y",
regisb marked this conversation as resolved.
Show resolved Hide resolved
"__prompts__": {
regisb marked this conversation as resolved.
Show resolved Hide resolved
"plugin_name": "Plugin name",
"package_name": "Package name",
"module_name": "Module name",
"description": "Short description about the plugin",
"git_repo": "Git repository URL",
"author": "Author's full name",
"email": "Author's email",
"tutor_version": "Tutor minimal required version",
"version": "Plugin version",
"license": "Package license",
"init_git": "Initialize a git repository (y/n)",
"include_ci": "Include continuous integration files for GitHub CI (y/n)"
}
}
Loading