Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
42 changes: 42 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Build the package, make sure it compiles OK

name: Build Package

on:
- push
- pull_request

jobs:

build:
name: Build Package
runs-on: ubuntu-latest

steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Install Python Dependencies
run: |
pip install --upgrade wheel setuptools twine build
pip install flake8 pep8-naming
- name: Build Package
run: |
pip install .
- name: Generate plugin
run: |
create-inventree-plugin --default --output output
test -d output || echo "Output directory not found"
test -d output/MyCustomPlugin || echo "Plugin directory not found"
test -d output/MyCustomPlugin/src || echo "Source directory not found"
test -f output/MyCustomPlugin/src/__init__.py || echo "__init__.py not found"
test -f output/MyCustomPlugin/src/plugin.py || echo "plugin.py not found"
test -f output/MyCustomPlugin/README.md || echo "README.md not found"
- name: Build and Install Plugin
run: |
cd output/MyCustomPlugin
flake8 .
pip install .
26 changes: 26 additions & 0 deletions .github/workflows/pep.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Style Checks

on: ["push", "pull_request"]

jobs:
style:
runs-on: ubuntu-latest

strategy:
max-parallel: 4
matrix:
python-version: [3.9]

steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install Deps
run: |
pip install flake8 pep8-naming
- name: Style Checks
run: |
flake8 .
44 changes: 44 additions & 0 deletions .github/workflows/pypi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Publish to PyPi package index

name: PIP Publish

on:
release:
types: [published]

jobs:

publish:
name: Publish to PyPi
runs-on: ubuntu-latest

steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Install Node.js
uses: actions/setup-node@v2
with:
node-version: "18"
- name: Install Python Dependencies
run: |
pip install --upgrade wheel setuptools twine build
- name: Build Frontend
run: |
cd frontend
npm install
npm run build --emptyOutDir
- name: Build Binary
run: |
python -m build
- name: Publish
run: |
python -m twine upload dist/*
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
TWINE_REPOSITORY: pypi

1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
recursive-include plugin_creator/template *
35 changes: 33 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,33 @@
# plugin-creator
Command line tool for scaffolding a new InvenTree plugin
# InvenTree Plugin Creator

Command line tool for scaffolding a new InvenTree plugin.

## Description

This is a command line tool which allows for rapid scaffolding of a new InvenTree plugin.

It uses the [cookiecutter project](https://cookiecutter.readthedocs.io/en/stable/) to generate a new project, based on a custom project template.

## Installation

To install the plugin creator, run:

```bash
pip install -U inventree-plugin-creator
```

## Usage

To create a new plugin, run:

```bash
create-inventree-plugin
```

This will prompt you for required information about the plugin you wish to create.

To view the available options, run:

```bash
create-inventree-plugin --help
```
3 changes: 3 additions & 0 deletions plugin_creator/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-

PLUGIN_CREATOR_VERSION = "1.0.0"
140 changes: 140 additions & 0 deletions plugin_creator/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@

import argparse
import json
import os

import license
import questionary
from cookiecutter.main import cookiecutter

from . import PLUGIN_CREATOR_VERSION
from . import mixins
from . import validators

from .helpers import info, success


def default_values() -> dict:
"""Read default values out from the cookiecutter.json file."""
fn = os.path.join(
os.path.dirname(__file__),
"template",
"cookiecutter.json"
)

with open(fn, "r") as f:
return json.load(f)


def gather_info(context: dict) -> dict:
"""Gather project information from the user."""

info("Enter project information:")

# Basic project information
context['plugin_title'] = questionary.text(
"Enter plugin name",
default=context['plugin_title'],
validate=validators.ProjectNameValidator,
).ask().strip()

context['plugin_description'] = questionary.text(
"Enter plugin description",
default=context['plugin_description'],
validate=validators.NotEmptyValidator,
).ask().strip()

context['plugin_name'] = context['plugin_title'].replace(" ", "")

# Convert the project name to a package name
# e.g. 'Custom Plugin' -> 'custom_plugin'
context['plugin_slug'] = context['plugin_title'].replace(" ", "-").lower()
context['package_name'] = context['plugin_slug'].replace("-", "_")

success(f"Generating plugin '{context['plugin_title']}' - {context['plugin_description']}")
info(f" - Package Name: {context['package_name']}")

info("Enter author information:")

context['author_name'] = questionary.text(
"Author name",
default=context['author_name'],
validate=validators.NotEmptyValidator,
).ask().strip()

context["author_email"] = questionary.text(
"Author email",
default=context["author_email"],
).ask().strip()

context["project_url"] = questionary.text(
"Project URL",
default=context['project_url'],
).ask().strip()

# Extract license information
available_licences = [lic for lic in license.iter()]
license_keys = [lic.id for lic in available_licences]

context['license_key'] = questionary.select(
"Select a license",
default="MIT",
choices=license_keys,
).ask()

context['license_text'] = license.find(
context['license_key']
).render(
name=context['author_name'],
email=context['author_email'],
)

# Plugin structure information
info("Enter plugin structure information:")

context['plugin_mixins'] = {
'mixin_list': mixins.get_mixins()
}

return context


def main():
"""Run plugin scaffolding."""

parser = argparse.ArgumentParser(description="InvenTree Plugin Creator Tool")
parser.add_argument("--default", action="store_true", help="Use default values for all prompts (non-interactive mode)")
parser.add_argument('--output', action='store', help='Specify output directory', default='.')

args = parser.parse_args()

info("InvenTree Plugin Creator Tool")

context = default_values()

context["plugin_creator_version"] = PLUGIN_CREATOR_VERSION

if not args.default:
context = gather_info(context)

src_path = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
"template"
)

output_dir = os.path.abspath(args.output)

# Run cookiecutter template
cookiecutter(
src_path,
no_input=True,
output_dir=output_dir,
extra_context=context,
overwrite_if_exists=True
)

success(f"Plugin created -> '{output_dir}'")


if __name__ == "__main__":
main()
30 changes: 30 additions & 0 deletions plugin_creator/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import questionary
import sys


def pretty_print(*args, color='green'):
"""Print a message with a color."""
questionary.print(" ".join(args), style=f'fg:{color}')


def error(*args, exit=True):
"""Print an error message."""
pretty_print(*args, color='red')

if exit:
sys.exit(1)


def warning(*args):
"""Print a warning message."""
pretty_print(*args, color='yellow')


def success(*args):
"""Print a success message."""
pretty_print(*args, color='green')


def info(*args):
"""Print an info message."""
pretty_print(*args, color='blue')
40 changes: 40 additions & 0 deletions plugin_creator/mixins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""InvenTree plugin mixin selection."""

import questionary


def available_mixins() -> list:
"""Return a list of available plugin mixin classes."""

# TODO: Support the commented out mixins

return [
# 'APICallMixin',
# 'ActionMixin',
# 'AppMixin',
# 'BarcodeMixin',
# 'BulkNotificationMethod',
# 'CurrencyExchangeMixin',
# 'EventMixin',
# 'IconPackMixin',
# 'LabelPrintingMixin',
# 'LocateMixin',
# 'NavigationMixin',
# 'ReportMixin',
# 'ScheduleMixin',
'SettingsMixin',
# 'SupplierBarcodeMixin',
# 'UrlsMixin',
# 'UserInterfaceMixin',
# 'ValidationMixin',
]


def get_mixins() -> list:
"""Ask user to select plugin mixins."""

return questionary.checkbox(
"Select plugin mixins",
choices=available_mixins(),
default="SettingsMixin"
).ask()
20 changes: 20 additions & 0 deletions plugin_creator/template/cookiecutter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"plugin_title": "My Custom Plugin",
"plugin_name": "MyCustomPlugin",
"plugin_slug": "my-custom-plugin",
"package_name": "my_custom_plugin",
"plugin_version": "0.1.0",
"plugin_mixins": {
"mixin_list": [
"SettingsMixin"
]
},
"plugin_description": "A short description of the project",
"project_url": "https://github.com/username/my-custom-plugin",
"author_name": "John Doe",
"author_email": "email@admin.org",
"license_key": "MIT",
"license_text": "...",
"plugin_creator_version": "<version>",
"plugin_creator_url": "https://github.com/inventree/plugin_creator"
}
1 change: 1 addition & 0 deletions plugin_creator/template/hooks/post_gen_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Custom hook which runs after the project has been generated
Loading