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

Use copier instead of cookiecutter #1

Closed
wants to merge 62 commits into from
Closed
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
22db8c7
cookiecutter -> copier transition
GenevieveBuckley Aug 16, 2023
14cda53
Remove old cookiecutter.json file
GenevieveBuckley Aug 16, 2023
ea10864
Folder rename for copier / cookiecutter transition
GenevieveBuckley Aug 16, 2023
2cc65ae
copier template
GenevieveBuckley Aug 21, 2023
c500b73
Exclude unnecessary license files
GenevieveBuckley Aug 21, 2023
4d538be
Conditionally generate files, depending on user input
GenevieveBuckley Aug 21, 2023
53a57be
Combine cookiecutter hooks into tasks for copier to run (validate and…
GenevieveBuckley Aug 23, 2023
e5bd087
Be more careful about how we install pre-commit with pip
GenevieveBuckley Aug 23, 2023
a67ea69
README swap cookiecutter/copier references, plus add extra links
GenevieveBuckley Aug 23, 2023
3f7385c
Describe requirements better
GenevieveBuckley Aug 23, 2023
328257e
Must use --trust for copier tasks & jinja extensions
GenevieveBuckley Aug 23, 2023
ca0f505
Merge main branch
GenevieveBuckley Aug 23, 2023
895f7b5
Add copier dependencies to requirements.txt
GenevieveBuckley Oct 18, 2023
a3c196d
Update tests to use True/False, not 'y'/'n' in pytest parameters.
GenevieveBuckley Oct 18, 2023
501bbe6
Merge main into copier PR
GenevieveBuckley Oct 27, 2023
3f227aa
Swap pytest-cookies to pytest-copie instead for testing
GenevieveBuckley Oct 27, 2023
c86e011
Changeover from pytest-cookies to pytest-copie in tests
GenevieveBuckley Oct 27, 2023
4df0efd
Wrap python versions as strings in github actions, so python 3.10 is …
GenevieveBuckley Oct 27, 2023
56a19be
pytest-copie requires kwarg extra_answers, not extra_context like pyt…
GenevieveBuckley Oct 27, 2023
d32ee29
Replace result.project_path with result.project_dir to adapt tests to…
GenevieveBuckley Oct 27, 2023
b4075f0
Bug: pytest-copie does not recognise .yml extensions, only .yaml
GenevieveBuckley Oct 30, 2023
f06642e
Replace 'cookiecutter' refrerences with 'copier'
GenevieveBuckley Oct 30, 2023
fb50199
Fix imports
GenevieveBuckley Oct 30, 2023
d4768bc
Update requirements
GenevieveBuckley Oct 30, 2023
3011259
Only include precommit config file where user has selected install_pr…
GenevieveBuckley Oct 30, 2023
5efc140
Try installing all test dependencies in github actions environment
GenevieveBuckley Oct 30, 2023
4739d17
initial commit
GenevieveBuckley Oct 30, 2023
18b16d0
Is the CI problem to do with our _tasks.py file?
GenevieveBuckley Oct 30, 2023
4dcae85
Restore repository initialization tasks
GenevieveBuckley Oct 30, 2023
3763939
Update setup.cfg.jinja (pydantic v2 needs napari>=0.4.19rc1)
GenevieveBuckley Nov 1, 2023
22557b2
Fix git line ending problem cuasing issues on Windows CI
GenevieveBuckley Nov 1, 2023
22dc45b
Can we fix the Windows github actions CI file permissions error
GenevieveBuckley Nov 1, 2023
5451181
Try fixing github actions windows CI file permission error with attri…
GenevieveBuckley Nov 1, 2023
4761716
Fix for boolean handling of install_precommit user answer
GenevieveBuckley Nov 1, 2023
95dfd7b
Update _tasks.py (attempt fix for windows tox CI)
GenevieveBuckley Nov 1, 2023
76e32e8
Use pytest-copie main branch, pending https://github.com/12rambau/pyt…
GenevieveBuckley Nov 2, 2023
563109d
Merge branch 'copier' of github.com:GenevieveBuckley/napari-plugin-te…
GenevieveBuckley Nov 2, 2023
a534b22
Update tests/test_create_template.py
GenevieveBuckley Nov 2, 2023
79957ef
Update test.yml, add python 3.11 to test matrix
GenevieveBuckley May 10, 2024
80f6544
Update dependency requirements (will fix tox CI failure)
GenevieveBuckley May 10, 2024
ea50761
Merge main
GenevieveBuckley May 16, 2024
826e3dc
Remvoe references to 'cookiecutter', accidentally introduced with mer…
GenevieveBuckley May 16, 2024
cc0f130
Fix rename error in project_path -> project_dir
GenevieveBuckley May 16, 2024
7e58a12
typo: add missing verb
jni May 22, 2024
6221737
Replace default with placeholder for freeform string input
jni May 22, 2024
12fd445
Add empty defaults
jni May 22, 2024
7111dca
Revert "Add empty defaults"
jni May 22, 2024
f42d90e
Use non-empty names in tests now that defaults are null
jni May 22, 2024
f7d9bb0
Remove duplicate jinja2-time dependency from requirements.txt list
GenevieveBuckley May 24, 2024
e54e76b
Bump ruff target python version
GenevieveBuckley May 24, 2024
642f8ac
Remove unnecessary setup.cfg file, all info is in pyrpoject.toml
GenevieveBuckley May 24, 2024
46fa82b
Use dynamic version only without setuptools_scm to avoid install erro…
Czaki Jun 6, 2024
4502070
Update aganders/headless-gui to silence nodejs warning (#188)
GenevieveBuckley Jun 6, 2024
00297a2
Dependabot for plugin template and child plugins (#184)
GenevieveBuckley Jun 6, 2024
c6eed38
Do not create special case for plugins named napari-foobar (#187)
GenevieveBuckley Jun 7, 2024
50317cc
Bump python versions used for CI tests (drop python 3.8, add python 3…
GenevieveBuckley Jun 7, 2024
cfc5509
Merge main, synch with latest cookiecutter PRs
GenevieveBuckley Jun 7, 2024
cc4838a
Ruff formatting updates for type checking
GenevieveBuckley Jun 7, 2024
a459ea4
Ruff target python 3.9
GenevieveBuckley Jun 7, 2024
be9de6e
Copier args plugin_name, module_name, and display_name cannot be blan…
GenevieveBuckley Jun 7, 2024
0905780
Update ruff code formatting
GenevieveBuckley Jun 10, 2024
8b172df
fix typo
GenevieveBuckley Jun 10, 2024
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
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Test cookiecutter
name: Test plugin template

on:
pull_request:
Expand Down Expand Up @@ -33,7 +33,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install pytest pytest-cookies tox
python -m pip install -r requirements.txt

- name: Test
uses: aganders3/headless-gui@v1
Expand Down
4 changes: 2 additions & 2 deletions PROMPTS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# napari Plugin Prompt Reference

When you first run cookiecutter to build a napari plugin, you will be prompted
When you first run the template to build a napari plugin, you will be prompted
for some configuration options. Your answers to these prompts will determine
some aspects of your plugin package including its name, versioning behaviour,
license, etc. None of these configuration options are set in stone - you
Expand Down Expand Up @@ -127,7 +127,7 @@ add `version = 0.0.1` to your `setup.cfg`.
If you choose `"y"` for this prompt, your package will be set up to have
[`setuptools_scm`](https://github.com/pypa/setuptools_scm) manage versions for
you based on your git tags. See the
[readme](https://github.com/napari/cookiecutter-napari-plugin#automatic-deployment-and-version-management)
[readme](https://github.com/napari/napari-plugin-template#automatic-deployment-and-version-management)
for details.

This option typically requires the least effort to manage versioning for your
Expand Down
41 changes: 22 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
# cookiecutter-napari-plugin
# napari-plugin-template

[Cookiecutter] template for authoring ([npe2]-based) [napari] plugins.
[Copier](https://copier.readthedocs.io/en/stable/) template for authoring ([npe2](https://github.com/napari/npe2)-based) [napari](https://napari.org/) plugins.

**NOTE: This repo is not meant to be cloned/forked directly! Please read "Getting Started" below**

## Getting Started

### Create your plugin package

Install [Cookiecutter] and generate a new napari plugin project:
Install [Copier](https://copier.readthedocs.io/en/stable/) and the [jinja2-time](https://pypi.org/project/jinja2-time/) extension.
Optionally install the napari plugin engine [npe2](https://github.com/napari/npe2), to help validate your new plugin is configured correctly.

Then you can generate a new napari plugin project:

```bash
pip install cookiecutter
cookiecutter https://github.com/napari/cookiecutter-napari-plugin
python -m pip install copier jinja2-time
python -m pip install npe2
copier copy --trust https://github.com/napari/napari-plugin-template new-plugin-name
```

Cookiecutter prompts you for information regarding your plugin
Copier prompts you for information regarding your plugin
(A new folder will be created in your current working directory):

```bash
Expand Down Expand Up @@ -192,8 +196,7 @@ pytest
### Create your documentation

Documentation generation is not included in this template.
We recommend following the getting started guides for one of the following
documentation generation tools:
We recommend following the getting started guides for one of the following documentation generation tools:

1. [Sphinx]
2. [MkDocs]
Expand Down Expand Up @@ -236,27 +239,28 @@ Details on why this plugin template is using the `src` layout can be found [here

## Issues

If you encounter any problems with this cookiecutter template, please [file an
issue] along with a detailed description.
If you encounter any problems with this template, please
[file an issue](https://github.com/napari/napari-plugin-template/issues/new)
along with a detailed description.

## License

Distributed under the terms of the [BSD-3] license, `cookiecutter-napari-plugin`
Distributed under the terms of the [BSD-3] license, `napari-plugin-template`
is free and open source software.

[napari organization]: https://github.com/napari/
[gitter_badge]: https://badges.gitter.im/Join%20Chat.svg
[gitter]: https://gitter.im/napari/cookiecutter-napari-plugin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge "Join Chat on Gitter.im"
[travis_badge]: https://travis-ci.org/napari/cookiecutter-napari-plugin.svg?branch=main
[travis]: https://travis-ci.org/napari/cookiecutter-napari-plugin "See Build Status on Travis CI"
[docs_badge]: https://readthedocs.org/projects/cookiecutter-napari-plugin/badge/?version=latest
[documentation]: https://cookiecutter-napari-plugin.readthedocs.io/en/latest/ "Documentation"
[cookiecutter]: https://github.com/audreyr/cookiecutter
[gitter]: https://gitter.im/napari/napari-plugin-template?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge "Join Chat on Gitter.im"
[travis_badge]: https://travis-ci.org/napari/napari-plugin-template.svg?branch=main
[travis]: https://travis-ci.org/napari/napari-plugin-template "See Build Status on Travis CI"
[docs_badge]: https://readthedocs.org/projects/napari-plugin-template/badge/?version=latest
[documentation]: https://napari-plugin-template.readthedocs.io/en/latest/ "Documentation"
[copier]: https://github.com/copier-org/copier
[napari]: https://github.com/napari/napari
[npe2]: https://github.com/napari/npe2
[pypi]: https://pypi.org/
[tox]: https://tox.readthedocs.io/en/latest/
[file an issue]: https://github.com/napari/cookiecutter-napari-plugin/issues
[file an issue]: https://github.com/napari/napari-plugin-template/issues
[sphinx]: https://www.sphinx-doc.org/en/master/usage/quickstart.html
[mkdocs]: https://www.mkdocs.org/getting-started/
[jupyterbook]: https://jupyterbook.org/en/stable/start/your-first-book.html
Expand All @@ -269,7 +273,6 @@ is free and open source software.
[travis ci]: https://travis-ci.com/
[appveyor]: http://www.appveyor.com/
[pypa code of conduct]: https://www.pypa.io/en/latest/code-of-conduct/
[shortbread]: https://github.com/audreyr/cookiecutter/releases/tag/1.4.0
[osi_certified]: https://opensource.org/trademarks/osi-certified/web/osi-certified-120x100.png
[osi]: https://opensource.org/
[github actions]: https://github.com/features/actions
Expand Down
235 changes: 235 additions & 0 deletions _tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
from argparse import ArgumentParser
import logging
import os
from pathlib import Path
import re
import subprocess
import sys


def module_name_pep8_compliance(module_name):
"""Validate that the plugin module name is PEP8 compliant."""
if not re.match(r"^[a-z][_a-z0-9]+$", module_name):
link = "https://www.python.org/dev/peps/pep-0008/#package-and-module-names"
logger.error("Module name should be pep-8 compliant.")
logger.error(f" More info: {link}")
sys.exit(1)


def pypi_package_name_compliance(plugin_name):
"""Check there are no underscores in the plugin name"""
if re.search(r"_", plugin_name):
logger.error("PyPI.org and pip discourage package names with underscores.")
sys.exit(1)


def validate_manifest(module_name, project_directory):
"""Validate the new plugin repository against napari requirements."""
try:
from npe2 import PluginManifest
except ImportError as e:
logger.error("npe2 is not installed. Skipping manifest validation.")
return True

current_directory = Path('.').absolute()
if (current_directory.match(project_directory) and not Path(project_directory).is_absolute()):
project_directory = current_directory

path=Path(project_directory) / "src" / Path(module_name) / "napari.yaml"

valid = False
try:
pm = PluginManifest.from_file(path)
msg = f"✔ Manifest for {(pm.display_name or pm.name)!r} valid!"
valid = True
except PluginManifest.ValidationError as err:
msg = f"🅇 Invalid! {err}"
logger.error(msg.encode("utf-8"))
sys.exit(1)
except Exception as err:
msg = f"🅇 Failed to read {path!r}. {type(err).__name__}: {err}"
logger.error(msg.encode("utf-8"))
sys.exit(1)
else:
logger.info(msg.encode("utf-8"))
return valid


def initialize_new_repository(
install_precommit=False,
plugin_name="napari-foobar",
github_repository_url="provide later",
github_username_or_organization="githubuser",
):
"""Initialize new plugin repository with git, and optionally pre-commit."""

msg = ""

# Configure git line ending settings
# https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration
if os.name == 'nt': # if on Windows, configure git line ending characters
subprocess.run(["git", "config", "--global", "core.autocrlf", "true"])
else: # for Linux and Mac
subprocess.run(["git", "config", "--global", "core.autocrlf", "input"])

# try to run git init
try:
subprocess.run(["git", "init", "-q"])
subprocess.run(["git", "checkout", "-b", "main"])
except Exception:
logger.error("Error in git initialization.")

if install_precommit is True:
# try to install and update pre-commit
try:
print("install pre-commit ...")
subprocess.run(["python", "-m", "pip", "install", "pre-commit"], stdout=subprocess.DEVNULL)
print("updating pre-commit...")
subprocess.run(["pre-commit", "autoupdate"], stdout=subprocess.DEVNULL)
subprocess.run(["git", "add", "."])
subprocess.run(["pre-commit", "run", "black", "-a"], capture_output=True)
except Exception:
logger.error("Error pip installing then running pre-commit.")

try:
subprocess.run(["git", "add", "."])
subprocess.run(["git", "commit", "-q", "-m", "initial commit"])
except Exception:
logger.error("Error creating initial git commit.")
msg += f"""
Your plugin template is ready! Next steps:

1. `cd` into your new directory and initialize a git repo
(this is also important for version control!)

cd {plugin_name}
git init -b main
git add .
git commit -m 'initial commit'

# you probably want to install your new package into your environment
pip install -e .
"""
else:
msg +=f"""
Your plugin template is ready! Next steps:

1. `cd` into your new directory

cd {plugin_name}
# you probably want to install your new package into your env
pip install -e .
"""
# Ensure full reqd/write/execute permissions for .git files
if os.name == 'nt': # if on Windows OS
# Avoid permission denied errors on Github Actions CI
subprocess.run(["attrib", "-h", "rr", ".git", "/s", "/d"])

if install_precommit is True:
# try to install and update pre-commit
# installing after commit to avoid problem with comments in setup.cfg.
try:
print("install pre-commit hook...")
subprocess.run(["pre-commit", "install"])
except Exception:
logger.error("Error at pre-commit install, skipping pre-commit")

if github_repository_url != 'provide later':
msg += f"""
2. Create a github repository with the name '{plugin_name}':
https://github.com/{github_username_or_organization}/{plugin_name}.git

3. Add your newly created github repo as a remote and push:

git remote add origin https://github.com/{github_username_or_organization}/{plugin_name}.git
git push -u origin main

4. The following default URLs have been added to `setup.cfg`:

Bug Tracker = https://github.com/{github_username_or_organization}/{plugin_name}/issues
Documentation = https://github.com/{github_username_or_organization}/{plugin_name}#README.md
Source Code = https://github.com/{github_username_or_organization}/{plugin_name}
User Support = https://github.com/{github_username_or_organization}/{plugin_name}/issues

These URLs will be displayed on your plugin's napari hub page.
You may wish to change these before publishing your plugin!"""
else:
msg += """
2. Create a github repository for your plugin:
https://github.com/new

3. Add your newly created github repo as a remote and push:

git remote add origin https://github.com/your-repo-username/your-repo-name.git
git push -u origin main

Don't forget to add this url to setup.cfg!

[metadata]
url = https://github.com/your-repo-username/your-repo-name.git

4. Consider adding additional links for documentation and user support to setup.cfg
using the project_urls key e.g.

[metadata]
project_urls =
Bug Tracker = https://github.com/your-repo-username/your-repo-name/issues
Documentation = https://github.com/your-repo-username/your-repo-name#README.md
Source Code = https://github.com/your-repo-username/your-repo-name
User Support = https://github.com/your-repo-username/your-repo-name/issues"""

msg += """
5. Read the README for more info: https://github.com/napari/napari-plugin-template

6. We've provided a template description for your plugin page on the napari hub at `.napari-hub/DESCRIPTION.md`.
You'll likely want to edit this before you publish your plugin.

7. Consider customizing the rest of your plugin metadata for display on the napari hub:
https://github.com/chanzuckerberg/napari-hub/blob/main/docs/customizing-plugin-listing.md
"""
return msg


if __name__=="__main__":
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("pre_gen_project")
parser = ArgumentParser()
parser.add_argument("--plugin_name",
dest="plugin_name",
help="The name of your plugin")
parser.add_argument("--module_name",
dest="module_name",
help="Plugin module name")
parser.add_argument("--project_directory",
dest="project_directory",
help="Project directory")
parser.add_argument("--install_precommit",
dest="install_precommit",
help="Install pre-commit",
default="False")
parser.add_argument("--github_repository_url",
dest="github_repository_url",
help="Github repository URL",
default='provide later')
parser.add_argument("--github_username_or_organization",
dest="github_username_or_organization",
help="Github user or organisation name",
default='githubuser')
args = parser.parse_args()

# Since bool("False") returns True, we need to check the actual string value
if args.install_precommit.lower() == "true":
install_precommit = True
else:
install_precommit = False

module_name_pep8_compliance(args.module_name)
pypi_package_name_compliance(args.plugin_name)
validate_manifest(args.module_name, args.project_directory)
msg = initialize_new_repository(
install_precommit=install_precommit,
plugin_name=args.plugin_name,
github_repository_url=args.github_repository_url,
github_username_or_organization=args.github_username_or_organization,
)
print(msg)
24 changes: 0 additions & 24 deletions cookiecutter.json

This file was deleted.

Loading
Loading