diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index f4b433e..452dcdd 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -47,7 +47,7 @@ jobs: run: | python3 -m pip install --user copier>=8.3.0 - - name: create plugin with default answers and run check + - name: create projects with default answers and run check env: CMEM_BASE_URI: ${{ secrets.CMEM_BASE_URI }} OAUTH_CLIENT_SECRET: ${{ secrets.OAUTH_CLIENT_SECRET }} @@ -59,12 +59,12 @@ jobs: uses: mikepenz/action-junit-report@v4 if: always() # always run even if the previous step fails with: - report_paths: cmem-plugin-awesome/dist/junit-*.xml + report_paths: '**/dist/junit-*.xml' - - name: Publish Test and Coverage Report as PR comment + - name: Publish Test and Coverage Report of ONE test case as PR comment uses: xportation/junit-coverage-report@main if: github.event_name == 'pull_request' with: - junit-path: cmem-plugin-awesome/dist/junit-pytest.xml - coverage-path: cmem-plugin-awesome/dist/coverage.xml + junit-path: plugin_dir/dist/junit-pytest.xml + coverage-path: plugin_dir/dist/coverage.xml diff --git a/.gitignore b/.gitignore index de0929d..76b20f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -cmem-plugin-awesome - +*_dir diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ee85da..26a7cb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](https://semver.org/) +## [7.0.0] 2024-09-09 + +### Changed + +- Generalization of the template + - You can create now projects of the following types: + - eccenca Corporate Memory plugins (same as before) + - Generic Python Projects (this is new) + - The first template question will ask you for the project type. + - Most features depend on this project type and will adapt to the decision. + +### Added + +- more shields + +### Fixed + +- limitations of the 6.x template version regarding project name + + ## [6.4.0] 2024-08-18 ### Changed diff --git a/README.md b/README.md index e470a60..4126398 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,18 @@ # cmem-plugin-template [![workflow][build-shield-main]][github-actions] [![workflow][build-shield-develop]][github-actions] [![version][version-shield]][changelog] ![python-shield] -[![eccenca Corporate Memory][cmem-shield]][cmem] [![copier][copier-shield]][copier] +[![poetry][poetry-shield]][poetry-link] [![ruff][ruff-shield]][ruff-link] [![mypy][mypy-shield]][mypy-link] [![copier][copier-shield]][copier] +[![eccenca Corporate Memory][cmem-shield]][cmem] This repository contains a [copier](https://copier.readthedocs.io/) template. -You can use it to bootstrap an [eccenca Corporate Memory](https://documentation.eccenca.com) [python plugin](https://documentation.eccenca.com/latest/develop/python-plugins/). +You can use it to bootstrap the following types of project: +- **[eccenca Corporate Memory](https://documentation.eccenca.com) [Python Plugin](https://documentation.eccenca.com/latest/develop/python-plugins/)**: Bootstrapping and keeping plugin repositories up-to-date was the initial idea of this template. +- **Generic Python Project**: After tons of commits, we wanted to use this template not only for plugins, but for all kinds of python projects. +
+ Table of contents * [Features](#features) @@ -18,17 +23,18 @@ You can use it to bootstrap an [eccenca Corporate Memory](https://documentation. * [Setup](#setup) * [Local Requirements](#local-requirements) * [Integration Tests](#integration-tests) + * [Plugins only: Corporate Memory Environment](#plugins-only-corporate-memory-environment) * [CI Build Plan](#ci-build-plan) * [Editor / IDE Support](#editor--ide-support) * [PyCharm](#pycharm) - +
## Features - [Python / poetry](https://python-poetry.org/) project with - - [pytest](https://www.pytest.org/) (incl. [memray](https://bloomberg.github.io/memray/) + [pytest-dotenv](https://github.com/quiqua/pytest-dotenv)) as testing framework, + - [pytest](https://www.pytest.org/) (incl. [memray](https://bloomberg.github.io/memray/) + [pytest-dotenv](https://github.com/quiqua/pytest-dotenv) + [code coverage](https://github.com/pytest-dev/pytest-cov)) as the testing framework, - [ruff](https://docs.astral.sh/ruff/) as all-hands linter and formatter, - [mypy](http://mypy-lang.org/) as type checker, and - [safety](https://pyup.io/safety/) as dependency vulnerability scanner. @@ -48,6 +54,8 @@ You can use it to bootstrap an [eccenca Corporate Memory](https://documentation. The following command will create a new project directory with the latest released template. This produces a plugin which is compatible the [latest release of eccenca Corporate Memory](https://documentation.eccenca.com/latest/). +Note: Select 'Generic Python Project' as an answer to the initial question to skip creation of plugin specific code. + ```shell-session $ copier copy gh:eccenca/cmem-plugin-template cmem-plugin-my ``` @@ -59,17 +67,15 @@ This produces a plugin which is compatible the latest development snapshot of ec $ copier copy -r develop gh:eccenca/cmem-plugin-template cmem-plugin-my ``` -After that, you can initialize the repository and install git hooks: +After that, you need to initialize the repository and optionally install the git pre-commit hooks: ```shell-session $ cd cmem-plugin-my -$ git init -$ git add . -$ git commit -m "init" +$ git init; git add .; git commit -m "init" $ pre-commit install ``` -Then you can run the local test suite an build a first deployment artefact: +Then you can run the local test suite and build a first deployment artefact: ```shell-session $ task check build @@ -80,13 +86,13 @@ $ task check build We [continuously update](https://github.com/eccenca/cmem-plugin-template/graphs/code-frequency) this repository. This includes maintenance of dependencies, build plan updates and the adoption of new features from the [plugin base library](https://github.com/eccenca/cmem-plugin-base). -In order to upgrade your plugin project to the latest template release, use the following command: +In order to upgrade your project to the latest template release, use the following command: ```shell-session $ copier update ``` -In order to prepare your plugin project for the upcoming next release, use this command: +In order to prepare your project for the upcoming next release, use this command: ```shell-session $ copier update -r develop @@ -96,7 +102,7 @@ Please also have a look at the [copier documentation](https://copier.readthedocs ### Other Tasks -All available tasks for your project can be listed like this: +The available tasks for your project can be listed like this (note that there are more tasks, prefixed with `plugin:` in case you started a plugin project): ```shell-session ∴ task @@ -104,7 +110,6 @@ task: Available tasks for this project: * build: Build a tarball and a wheel package * check: Run whole test suite incl. unit and integration tests * clean: Removes dist, *.pyc and some caches -* deploy: Install plugin package in Corporate Memory * check:linters: Run all linter and static code analysis tests * check:mypy: Complain about typing errors * check:pytest: Run unit and integration tests @@ -136,22 +141,20 @@ tasks: The following tools are needed for local task execution: -- Python 3.11 -- [copier](https://copier.readthedocs.io/) (>= v9) for project template rendering +- Python 3.11+ +- [copier](https://copier.readthedocs.io/) (>= v9) for project template rendering and updating +- [task](https://taskfile.dev/) (>= v3.29) for running build tasks (make sure to follow the installation instructions to avoid confusion with taskwarrior) - [poetry](https://python-poetry.org/) (>= v1.7) for packaging and dependency managing (+ [dynamic versioning plugin](https://github.com/mtkennerly/poetry-dynamic-versioning)) -- [pre-commit](https://pre-commit.com/) (>= v2.20) - managing and maintaining pre-commit hooks -- [task](https://taskfile.dev/) (>= v3.29) for build task running (make sure to follow the installation instructions to avoid confusion with taskwarrior) -- [cmemc](https://eccenca.com/go/cmemc) (>= v23.1) for interacting with eccenca Corporate Memory +- [pre-commit](https://pre-commit.com/) (>= v2.20) for managing pre-commit hooks (optional) -Example installation of the requirements with [pipx](https://pypa.github.io/pipx/) on Ubuntu: +Example installation of the requirements with [pipx](https://pipx.pypa.io/) on Ubuntu: -``` +``` shell-session $ sudo sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin $ python3 -m pip install --user pipx $ python3 -m pipx ensurepath $ pipx install copier $ pipx install pre-commit -$ pipx install cmem-cmemc $ pipx install poetry $ poetry self add "poetry-dynamic-versioning[plugin]" ``` @@ -164,13 +167,15 @@ Testing your plugin is crucial and should be done locally as well as integrated In order to setup access to a Corporate Memory deployment, you need to provide correct environment variables. Without these variables, only standalone tests can be executed (see `1 skipped`): -```shell-session +``` shell-session $ task check:pytest ... ... ===== 3 passed, 1 skipped in 0.09s ===== ``` -By providing the correct [cmemc](https://eccenca.com/go/cmemc) [environment variables](https://documentation.eccenca.com/latest/automate/cmemc-command-line-interface/installation-and-configuration/file-based-configuration/#configuration-variables) in a `.env` file or directly in your environment, your plugin can be tested in an integrated way: +### Plugins only: Corporate Memory Environment + +By providing the correct [cmemc](https://eccenca.com/go/cmemc) [environment variables](https://documentation.eccenca.com/latest/automate/cmemc-command-line-interface/configuration/environment-based-configuration/) in an `.env` file or directly in your environment, your plugin can be tested in an integrated way: ``` shell-session # Environment as direct variables: @@ -196,7 +201,7 @@ The gitlab workflow as well as the github action pipelines need the same environ - For github, go to Settings > Secret > Actions > [New Repository Secret](https://docs.github.com/en/actions/security-guides/encrypted-secrets) - For gitlab, go to Settings > CI/CD > Variables (Expand) > [Add Variable (protected, masked, all environments)](https://docs.gitlab.com/ee/ci/variables/) -An example github pipeline can be seen [here](https://github.com/eccenca/cmem-plugin-kafka/actions). +An example github pipeline can be seen [here](https://github.com/eccenca/cmem-plugin-yaml/actions). In addition to the eccenca Corporate Memory credential secrets, a `PYPI_TOKEN` secret can be set in order to use the `publish` task/workflow. @@ -204,7 +209,7 @@ In addition to the eccenca Corporate Memory credential secrets, a `PYPI_TOKEN` s #### PyCharm -In order to have the best PyCharm experience when starting a project with this template, we suggest the following PyCharm plugins: +In order to have the best PyCharm experience, when starting a project with this template, we suggest the following PyCharm plugins: - [Ruff](https://plugins.jetbrains.com/plugin/20574-ruff) will provide the linting hints which will be raised by the pipeline anyway. - [Taskfile](https://plugins.jetbrains.com/plugin/17058-taskfile) will allow for starting tasks. @@ -215,8 +220,14 @@ In order to have the best PyCharm experience when starting a project with this t [build-shield-main]: https://img.shields.io/github/actions/workflow/status/eccenca/cmem-plugin-template/check.yml?logo=github&branch=main&label=main [build-shield-develop]: https://img.shields.io/github/actions/workflow/status/eccenca/cmem-plugin-template/check.yml?logo=github&branch=develop&label=develop [copier]: https://copier.readthedocs.io/ -[copier-shield]: https://img.shields.io/badge/made%20with-copier-orange +[copier-shield]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/copier-org/copier/master/img/badge/badge-grayscale-inverted-border-purple.json [cmem]: https://documentation.eccenca.com -[cmem-shield]: https://img.shields.io/badge/made%20for-eccenca%20Corporate%20Memory-blue?logo=data:image/svg%2bxml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgaWQ9IkxheWVyXzEiCiAgIGRhdGEtbmFtZT0iTGF5ZXIgMSIKICAgdmlld0JveD0iMCAwIDgxLjI5MDAwMSA4Mi4yODk4NiIKICAgdmVyc2lvbj0iMS4xIgogICB3aWR0aD0iODEuMjkwMDAxIgogICBoZWlnaHQ9IjgyLjI4OTg2NCIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzODI2Ij4KICAgIDxzdHlsZQogICAgICAgaWQ9InN0eWxlODI0Ij4KICAgICAgLmNscy0xIHsKICAgICAgICBmaWxsOiAjZjM5MjAwOwogICAgICB9CgogICAgICAuY2xzLTIgewogICAgICAgIGZpbGw6IG5vbmU7CiAgICAgICAgc3Ryb2tlOiAjZjM5MjAwOwogICAgICAgIHN0cm9rZS13aWR0aDogMS41cHg7CiAgICAgIH0KICAgIDwvc3R5bGU+CiAgPC9kZWZzPgogIDxnCiAgICAgaWQ9Imc4NDAiCiAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTMwLjc2LC0zMS4xNDAxMzkpIj4KICAgIDxwYXRoCiAgICAgICBjbGFzcz0iY2xzLTEiCiAgICAgICBkPSJNIDU1LjksODUuMTkgQSAyMC4xNCwyMC4xNCAwIDEgMCAzNS43Niw2NS4wNSAyMC4xNCwyMC4xNCAwIDAgMCA1NS45LDg1LjE5IFoiCiAgICAgICBpZD0icGF0aDgyOCIgLz4KICAgIDxwYXRoCiAgICAgICBjbGFzcz0iY2xzLTEiCiAgICAgICBkPSJtIDk4LDU0LjE0IGEgOSw5IDAgMSAwIC04Ljk1LC05IDguOTUsOC45NSAwIDAgMCA4Ljk1LDkgeiIKICAgICAgIGlkPSJwYXRoODMwIiAvPgogICAgPHBhdGgKICAgICAgIGNsYXNzPSJjbHMtMSIKICAgICAgIGQ9Ik0gODguMzUsMTA4LjQzIEEgMTIuMzEsMTIuMzEgMCAxIDAgNzYsOTYuMTIgMTIuMzEsMTIuMzEgMCAwIDAgODguMzEsMTA4LjQzIFoiCiAgICAgICBpZD0icGF0aDgzMiIgLz4KICAgIDxsaW5lCiAgICAgICBjbGFzcz0iY2xzLTIiCiAgICAgICB4MT0iODYuOTcwMDAxIgogICAgICAgeTE9IjkyLjA1OTk5OCIKICAgICAgIHgyPSI1OC43Nzk5OTkiCiAgICAgICB5Mj0iNjcuMzYwMDAxIgogICAgICAgaWQ9ImxpbmU4MzQiIC8+CiAgICA8bGluZQogICAgICAgY2xhc3M9ImNscy0yIgogICAgICAgeDE9Ijk5LjE4IgogICAgICAgeTE9IjQ1Ljg0IgogICAgICAgeDI9IjU1LjQ4IgogICAgICAgeTI9IjY2LjEyMDAwMyIKICAgICAgIGlkPSJsaW5lODM2IiAvPgogICAgPGxpbmUKICAgICAgIGNsYXNzPSJjbHMtMiIKICAgICAgIHgxPSI5Ny45ODk5OTgiCiAgICAgICB5MT0iNDQuNjUwMDAyIgogICAgICAgeDI9Ijg4LjM0OTk5OCIKICAgICAgIHkyPSI5Mi44Mzk5OTYiCiAgICAgICBpZD0ibGluZTgzOCIgLz4KICA8L2c+Cjwvc3ZnPgo= +[cmem-shield]: https://img.shields.io/endpoint?url=https://dev.documentation.eccenca.com/badge.json [python-shield]: https://img.shields.io/badge/python-v3.11-blue +[mypy-link]: https://mypy-lang.org/ +[mypy-shield]: https://www.mypy-lang.org/static/mypy_badge.svg +[ruff-link]: https://docs.astral.sh/ruff/ +[ruff-shield]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json&label=Code%20Style +[poetry-link]: https://python-poetry.org/ +[poetry-shield]: https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json diff --git a/Taskfile.yaml b/Taskfile.yaml index ba7dbae..0cf3980 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -3,7 +3,8 @@ version: '3' vars: - PLUGIN_DIR: cmem-plugin-awesome + TEMPLATE_REVISION: + sh: git rev-parse HEAD tasks: @@ -17,34 +18,75 @@ tasks: clean: desc: clean up working directory cmds: - - rm -rf {{.PLUGIN_DIR}} + - rm -rf *_dir create: - desc: create plugin directory with current version and ask for answers + desc: create a project with the current version and ask for answers deps: - clean cmds: - - copier copy --vcs-ref {{.TEMPLATE_REVISION}} . {{.PLUGIN_DIR}} - vars: - TEMPLATE_REVISION: - sh: git rev-parse HEAD + - copier copy --vcs-ref {{.TEMPLATE_REVISION}} . new_dir - check: - desc: create plugin with default answers and run check + check:generate:case: + desc: generate a project with the current version from a TEST_CASE + preconditions: + - sh: "[[ -v TEST_CASE ]]" + msg: > + Environment needs 'TEST_CASE' variable. + See tests directory - all yaml files without suffix are test cases. + - sh: "[ -f tests/${TEST_CASE}.yml ]" + msg: Test case file ${TEST_CASE}.yml does not exist. + cmds: + - rm -rf {{.TEST_CASE}}_dir + - mkdir {{.TEST_CASE}}_dir + - cp tests/{{.TEST_CASE}}.yml {{.TEST_CASE}}_dir/.copier-answers.yml + - copier copy --vcs-ref {{.TEMPLATE_REVISION}} --defaults . {{.TEST_CASE}}_dir + - git config --global init.defaultBranch develop + - cd {{.TEST_CASE}}_dir && git init . + - cd {{.TEST_CASE}}_dir && git add . + - cd {{.TEST_CASE}}_dir && git config init.defaultBranch main + - cd {{.TEST_CASE}}_dir && git config user.name "Anonymous Person" + - cd {{.TEST_CASE}}_dir && git config user.email "anonymous@example.org" + - cd {{.TEST_CASE}}_dir && git commit -m "init from template" + + check:generate:cases: + desc: generate all test cases with the current template version deps: - clean + vars: + TEST_CASES: + sh: find tests -type f -name '*.yml' | sed 's/^tests\///g' | sed 's/\.yml$//g' cmds: - - copier copy --vcs-ref {{.TEMPLATE_REVISION}} --defaults . {{.PLUGIN_DIR}} - - git config --global init.defaultBranch develop - - git init {{.PLUGIN_DIR}} - - cd {{.PLUGIN_DIR}} && git add . - - cd {{.PLUGIN_DIR}} && git config init.defaultBranch main - - cd {{.PLUGIN_DIR}} && git config user.name "Anonymous Person" - - cd {{.PLUGIN_DIR}} && git config user.email "anonymous@example.org" - - cd {{.PLUGIN_DIR}} && git commit -m "init from template" - - cd {{.PLUGIN_DIR}} && poetry update - - cd {{.PLUGIN_DIR}} && task check + - for: { var: TEST_CASES } + cmd: TEST_CASE={{.ITEM}} task check:generate:case + + check:validate:case: + desc: validate a project test case + preconditions: + - sh: "[[ -v TEST_CASE ]]" + msg: > + Environment needs 'TEST_CASE' variable. + See tests directory - all yaml files without suffix are test cases. + - sh: "[ -d ${TEST_CASE}_dir ]" + msg: > + Test case directory ${TEST_CASE}.yml does not exist. + Please use check:generate* tasks to create directories. + cmds: + - cd {{.TEST_CASE}}_dir && poetry update + - cd {{.TEST_CASE}}_dir && task check + + check:validate:cases: + desc: validate all test cases vars: - TEMPLATE_REVISION: - sh: git rev-parse HEAD + TEST_CASES: + sh: find tests -type f -name '*.yml' | sed 's/^tests\///g' | sed 's/\.yml$//g' + cmds: + - for: { var: TEST_CASES } + cmd: TEST_CASE={{.ITEM}} task check:validate:case + + check: + desc: First generate, the validate all test cases + cmds: + - task: check:generate:cases + - task: check:validate:cases diff --git a/copier.yml b/copier.yml index 2b14629..82cc8d8 100644 --- a/copier.yml +++ b/copier.yml @@ -1,28 +1,75 @@ --- +project_type: + type: str + help: | + + > project_type: + > + > Which type of project is this? + > + > - Plugins are eccenca Corporate Memory Plugins installable with cmemc. + > - Generic projects are just using the build plan and the config. + > + choices: + eccenca Corporate Memory Plugin: "plugin" + Generic Python Project: "generic" + default: plugin + project_slug: type: str help: | - > project_slug: Will be used as part of the package name. + > project_slug: > - > Example: You enter 'awesome' and the name will be 'cmem-plugin-awesome'. + {% if project_type == 'plugin' -%} + > Will be used as part of the package name. > - > Currently, only single lower-case words are allowed here ... + > Example: You enter 'awesome' and the name will be 'cmem-plugin-awesome'. + {%- else -%} + > Will be used as package name. + {%- endif %} > default: awesome + validator: >- + {% if not (project_slug | regex_search('^[a-z][a-z0-9\-]+$')) %} + project_slug must start with a letter, followed one or more letters, digits or dashes all lowercase. + {% endif %} + +package_name: + type: str + when: false + default: |- + {% if project_type == 'plugin' -%} + cmem-plugin-{{ project_slug }} + {%- else -%} + {{ project_slug }} + {%- endif %} + +package_dir: + type: str + when: false + default: |- + {% if project_type == 'plugin' -%} + cmem_plugin_{{ project_slug | replace("-", "_") }} + {%- else -%} + {{ project_slug | replace("-", "_") }} + {%- endif %} project_description: type: str help: | - > project_description: Will be used as part of the README file and the - > package info. + > project_description: + > + > Will be used as part of the README file and the package info. > + {% if project_type == 'plugin' -%} > Use an imperative form to describe what a user can do. > > Example descriptions can be listed here: > https://pypi.org/search/?q=%22cmem-plugin-%22 > + {%- endif %} default: Create awesome Knowledge Graphs with eccenca Corporate Memory :-) author_name: @@ -31,7 +78,7 @@ author_name: > author_name: Will be used as part of the package info. > - default: Anonymous Person + default: eccenca GmbH author_mail: type: str @@ -39,7 +86,7 @@ author_mail: > author_mail: Will be used as part of the package info. > - default: anonymous@example.org + default: cmempy-developer@eccenca.com github_page: type: str diff --git a/src/.copier-answers.env.jinja b/src/.copier-answers.env.jinja index e43357d..da66a08 100644 --- a/src/.copier-answers.env.jinja +++ b/src/.copier-answers.env.jinja @@ -1,3 +1,3 @@ # Changes here will be overwritten by Copier -project_slug={{ project_slug }} +package_dir={{ package_dir }} diff --git a/src/README-public.md.jinja b/src/README-public.md.jinja index e1730ce..c0f2eef 100644 --- a/src/README-public.md.jinja +++ b/src/README-public.md.jinja @@ -1,13 +1,26 @@ -# cmem-plugin-{{ project_slug }} +# {{ package_name }} {{ project_description }} -This is a plugin for [eccenca](https://eccenca.com) [Corporate Memory](https://documentation.eccenca.com). +{% if project_type == "plugin" -%}[![eccenca Corporate Memory][cmem-shield]][cmem-link] -You can install it with the [cmemc](https://eccenca.com/go/cmemc) command line -clients like this: +This is a plugin for [eccenca](https://eccenca.com) [Corporate Memory](https://documentation.eccenca.com). You can install it with the [cmemc](https://eccenca.com/go/cmemc) command line clients like this: ``` -cmemc admin workspace python install cmem-plugin-{{ project_slug }} +cmemc admin workspace python install {{ package_name }} ``` +{%- endif %} +{% if github_page -%}[![workflow]({{ github_page }}/actions/workflows/check.yml/badge.svg)]({{ github_page}}/actions){%- endif %} {% if pypi -%}[![pypi version](https://img.shields.io/pypi/v/{{ package_name }})](https://pypi.org/project/{{ package_name }}){%- endif %} {% if pypi -%}[![license](https://img.shields.io/pypi/l/{{ package_name }})](https://pypi.org/project/{{ package_name }}){%- endif %} +[![poetry][poetry-shield]][poetry-link] [![ruff][ruff-shield]][ruff-link] [![mypy][mypy-shield]][mypy-link] [![copier][copier-shield]][copier] + +{% if project_type == 'plugin' -%}[cmem-link]: https://documentation.eccenca.com +[cmem-shield]: https://img.shields.io/endpoint?url=https://dev.documentation.eccenca.com/badge.json{%- endif %} +[poetry-link]: https://python-poetry.org/ +[poetry-shield]: https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json +[ruff-link]: https://docs.astral.sh/ruff/ +[ruff-shield]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json&label=Code%20Style +[mypy-link]: https://mypy-lang.org/ +[mypy-shield]: https://www.mypy-lang.org/static/mypy_badge.svg +[copier]: https://copier.readthedocs.io/ +[copier-shield]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/copier-org/copier/master/img/badge/badge-grayscale-inverted-border-purple.json diff --git a/src/README.md.jinja b/src/README.md.jinja index e73e027..83508cc 100644 --- a/src/README.md.jinja +++ b/src/README.md.jinja @@ -1,8 +1,9 @@ -# cmem-plugin-{{ project_slug }} +# {{ package_name }} {{ project_description }} -[![eccenca Corporate Memory](https://img.shields.io/badge/eccenca-Corporate%20Memory-orange)](https://documentation.eccenca.com) {% if github_page -%}[![workflow]({{ github_page }}/actions/workflows/check.yml/badge.svg)]({{ github_page}}/actions){%- endif %} {% if pypi -%}[![pypi version](https://img.shields.io/pypi/v/cmem-plugin-{{ project_slug }})](https://pypi.org/project/{{ project_slug}}){%- endif %} {% if pypi -%}[![license](https://img.shields.io/pypi/l/cmem-plugin-{{ project_slug }})](https://pypi.org/project/cmem-plugin-{{ project_slug}}){%- endif %} +{% if project_type == 'plugin' -%}[![eccenca Corporate Memory][cmem-shield]][cmem-link] {%- endif %}{% if github_page -%}[![workflow]({{ github_page }}/actions/workflows/check.yml/badge.svg)]({{ github_page}}/actions){%- endif %} {% if pypi -%}[![pypi version](https://img.shields.io/pypi/v/{{ package_name }})](https://pypi.org/project/{{ package_name}}){%- endif %} {% if pypi -%}[![license](https://img.shields.io/pypi/l/{{ package_name }})](https://pypi.org/project/{{ package_name}}){%- endif %} +[![poetry][poetry-shield]][poetry-link] [![ruff][ruff-shield]][ruff-link] [![mypy][mypy-shield]][mypy-link] [![copier][copier-shield]][copier] ## Development @@ -10,3 +11,13 @@ - Use [pre-commit](https://pre-commit.com/) to avoid errors before commit. - This repository was created with [this copier template](https://github.com/eccenca/cmem-plugin-template). +{% if project_type == 'plugin' -%}[cmem-link]: https://documentation.eccenca.com +[cmem-shield]: https://img.shields.io/endpoint?url=https://dev.documentation.eccenca.com/badge.json{%- endif %} +[poetry-link]: https://python-poetry.org/ +[poetry-shield]: https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json +[ruff-link]: https://docs.astral.sh/ruff/ +[ruff-shield]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json&label=Code%20Style +[mypy-link]: https://mypy-lang.org/ +[mypy-shield]: https://www.mypy-lang.org/static/mypy_badge.svg +[copier]: https://copier.readthedocs.io/ +[copier-shield]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/copier-org/copier/master/img/badge/badge-grayscale-inverted-border-purple.json diff --git a/src/Taskfile.yaml b/src/Taskfile.yaml index a0712c5..3f3835b 100644 --- a/src/Taskfile.yaml +++ b/src/Taskfile.yaml @@ -1,4 +1,7 @@ # https://taskfile.dev +# +# This is a generated file. We dot not suggest to edit it. +# Instead, create a file `TaskfileCustom.yml` and add your additions there. --- version: '3' @@ -10,13 +13,16 @@ dotenv: ['.copier-answers.env', '.env'] - check:prepare vars: - PACKAGE: cmem_plugin_$project_slug + PACKAGE: $package_dir DIST_DIR: dist includes: custom: taskfile: ./TaskfileCustom.yaml optional: true + plugin: + taskfile: .tasks-plugin.yml + optional: true tasks: @@ -43,6 +49,10 @@ tasks: Check poetry versioning plugin. Currently not under Windows run: once preconditions: + - sh: '[ -d .git ]' + msg: > + Your newly created project directory needs to be initialized + as a git repository. - sh: '[[ {{.PDV_VERSION}} > {{.PDV_VERSION_MIN}} ]]' msg: > This project needs the poetry-dynamic-versioning @@ -163,15 +173,6 @@ tasks: XML_PARAMS: --output-format junit --output-file {{.JUNIT_FILE}} # }}} - # {{{ build and deploy tasks - - deploy: - desc: Install plugin package in Corporate Memory - deps: - - build - cmds: - - cmemc admin workspace python install dist/*.tar.gz - - cmemc admin workspace python list-plugins build: desc: Build a tarball and a wheel package @@ -182,5 +183,3 @@ tasks: cmds: - poetry build -# }}} - diff --git a/src/cmem_plugin_{{ project_slug }}/__init__.py.jinja b/src/cmem_plugin_{{ project_slug }}/__init__.py.jinja deleted file mode 100644 index 1da29f9..0000000 --- a/src/cmem_plugin_{{ project_slug }}/__init__.py.jinja +++ /dev/null @@ -1 +0,0 @@ -"""{{ project_slug }} - main package""" diff --git a/src/pyproject.toml.jinja b/src/pyproject.toml.jinja index ca3daf6..cb47853 100644 --- a/src/pyproject.toml.jinja +++ b/src/pyproject.toml.jinja @@ -1,28 +1,31 @@ [tool.poetry] -name = "cmem-plugin-{{ project_slug }}" +name = "{{ package_name }}" version = "0.0.0" license = "Apache-2.0" description = "{{ project_description }}" authors = ["{{ author_name }} <{{ author_mail }}>"] classifiers = [ - "Development Status :: 4 - Beta", - "Environment :: Plugins", - "Topic :: Software Development :: Libraries :: Python Modules" + "Development Status :: 4 - Beta",{% if project_type == 'plugin' -%} + "Environment :: Plugins",{%- endif %} ] readme = "README-public.md" -keywords = [ +{% if project_type == 'plugin' -%}keywords = [ "eccenca Corporate Memory", "plugin" -] +]{%- endif %} {% if github_page -%}homepage = "{{ github_page }}"{%- endif %} -[tool.poetry.dependencies] +[tool.poetry.dependencies]{% if project_type == 'plugin' -%} # if you need to change python version here, change it also in .python-version -python = "^3.11" +python = "^3.11"{%- else %} +python = ">=3.11, ^3"{%- endif %} -[tool.poetry.dependencies.cmem-plugin-base] +{% if project_type == 'plugin' -%}[tool.poetry.dependencies.cmem-plugin-base] version = "^4.7.0" allow-prereleases = false +[tool.poetry.group.dev.dependencies.cmem-cmemc] +version = "^24.2.0"{%- endif %} + [tool.poetry.group.dev.dependencies] genbadge = {extras = ["coverage"], version = "^1.1.1"} mypy = "^1.11.1" diff --git a/src/tests/{% if project_type == 'generic' %}test_example.py{% endif %}.jinja b/src/tests/{% if project_type == 'generic' %}test_example.py{% endif %}.jinja new file mode 100644 index 0000000..4e9be1d --- /dev/null +++ b/src/tests/{% if project_type == 'generic' %}test_example.py{% endif %}.jinja @@ -0,0 +1,11 @@ +"""Example tests. + +Remove this and other example files after bootstrapping your project. +""" + +from {{ package_dir }}.example import double + + +def test_example() -> None: + """Example Test""" + assert double(10) == 10 * 2 diff --git a/src/tests/test_example.py.jinja b/src/tests/{% if project_type == 'plugin' %}test_example.py{% endif %}.jinja similarity index 87% rename from src/tests/test_example.py.jinja rename to src/tests/{% if project_type == 'plugin' %}test_example.py{% endif %}.jinja index 2db61c1..ba9e497 100644 --- a/src/tests/test_example.py.jinja +++ b/src/tests/{% if project_type == 'plugin' %}test_example.py{% endif %}.jinja @@ -1,4 +1,7 @@ -"""Plugin tests.""" +"""Plugin tests. + +Remove this and other example files after bootstrapping your project. +""" import io @@ -10,11 +13,11 @@ from cmem.cmempy.workspace.projects.resources.resource import ( get_resource_response, ) -from cmem_plugin_{{ project_slug }}.example_transform import Lifetime -from cmem_plugin_{{ project_slug }}.example_workflow import DollyPlugin +from {{ package_dir }}.example_transform import Lifetime +from {{ package_dir }}.example_workflow import DollyPlugin from tests.utils import TestExecutionContext, needs_cmem -PROJECT_NAME = "{{ project_slug }}_test_project" +PROJECT_NAME = "{{ package_dir }}_test_project" DATASET_NAME = "sample_dataset" RESOURCE_NAME = "sample_dataset.txt" DATASET_TYPE = "text" @@ -31,7 +34,7 @@ def di_environment() -> object: parameters={"file": RESOURCE_NAME}, autoconfigure=False, ) - with io.StringIO("{{ project_slug }} plugin sample file.") as response_file: + with io.StringIO("{{ package_name }} plugin sample file.") as response_file: create_resource( project_name=PROJECT_NAME, resource_name=RESOURCE_NAME, diff --git a/src/tests/utils.py b/src/tests/{% if project_type == 'plugin' %}utils.py{% endif %}.jinja similarity index 95% rename from src/tests/utils.py rename to src/tests/{% if project_type == 'plugin' %}utils.py{% endif %}.jinja index f389888..1a1c381 100644 --- a/src/tests/utils.py +++ b/src/tests/{% if project_type == 'plugin' %}utils.py{% endif %}.jinja @@ -1,4 +1,7 @@ -"""Testing utilities.""" +"""Testing utilities. + +Remove this and other example files after bootstrapping your project. +""" import os from typing import ClassVar diff --git a/src/.python-version b/src/{% if project_type == 'plugin' %}.python-version{% endif %}.jinja similarity index 100% rename from src/.python-version rename to src/{% if project_type == 'plugin' %}.python-version{% endif %}.jinja diff --git a/src/{% if project_type == 'plugin' %}.tasks-plugin.yml{% endif %}.jinja b/src/{% if project_type == 'plugin' %}.tasks-plugin.yml{% endif %}.jinja new file mode 100644 index 0000000..92aeef6 --- /dev/null +++ b/src/{% if project_type == 'plugin' %}.tasks-plugin.yml{% endif %}.jinja @@ -0,0 +1,19 @@ +# https://taskfile.dev +--- +version: '3' + +tasks: + + install: + desc: Install plugin package in Corporate Memory + cmds: + - task build + - poetry run cmemc admin workspace python install dist/{{package_dir}}*.tar.gz + - poetry run cmemc admin workspace python list-plugins + + uninstall: + desc: Unnstall plugin package in Corporate Memory + cmds: + - task build + - poetry run cmemc admin workspace python uninstall {{ package_name }} + - poetry run cmemc admin workspace python list-plugins diff --git a/src/{{ package_dir }}/__init__.py.jinja b/src/{{ package_dir }}/__init__.py.jinja new file mode 100644 index 0000000..8953c89 --- /dev/null +++ b/src/{{ package_dir }}/__init__.py.jinja @@ -0,0 +1 @@ +"""{{ package_name }}""" diff --git a/src/{{ package_dir }}/{% if project_type == 'generic' %}example.py{% endif %}.jinja b/src/{{ package_dir }}/{% if project_type == 'generic' %}example.py{% endif %}.jinja new file mode 100644 index 0000000..ce9466b --- /dev/null +++ b/src/{{ package_dir }}/{% if project_type == 'generic' %}example.py{% endif %}.jinja @@ -0,0 +1,9 @@ +"""Example module + +Remove this and other example files after bootstrapping your project. +""" + + +def double(value: int) -> int: + """Get a value""" + return value * 2 diff --git a/src/cmem_plugin_{{ project_slug }}/example_icon.svg b/src/{{ package_dir }}/{% if project_type == 'plugin' %}example_icon.svg{% endif %}.jinja similarity index 100% rename from src/cmem_plugin_{{ project_slug }}/example_icon.svg rename to src/{{ package_dir }}/{% if project_type == 'plugin' %}example_icon.svg{% endif %}.jinja diff --git a/src/cmem_plugin_{{ project_slug }}/example_transform.py b/src/{{ package_dir }}/{% if project_type == 'plugin' %}example_transform.py{% endif %}.jinja similarity index 95% rename from src/cmem_plugin_{{ project_slug }}/example_transform.py rename to src/{{ package_dir }}/{% if project_type == 'plugin' %}example_transform.py{% endif %}.jinja index a4d2923..ec5d461 100644 --- a/src/cmem_plugin_{{ project_slug }}/example_transform.py +++ b/src/{{ package_dir }}/{% if project_type == 'plugin' %}example_transform.py{% endif %}.jinja @@ -1,4 +1,7 @@ -"""lifetime(age) transform plugin module""" +"""lifetime(age) transform plugin module + +Remove this and other example files after bootstrapping your project. +""" import datetime from collections.abc import Sequence diff --git a/src/cmem_plugin_{{ project_slug }}/example_workflow.py b/src/{{ package_dir }}/{% if project_type == 'plugin' %}example_workflow.py{% endif %}.jinja similarity index 96% rename from src/cmem_plugin_{{ project_slug }}/example_workflow.py rename to src/{{ package_dir }}/{% if project_type == 'plugin' %}example_workflow.py{% endif %}.jinja index 228adf7..5609480 100644 --- a/src/cmem_plugin_{{ project_slug }}/example_workflow.py +++ b/src/{{ package_dir }}/{% if project_type == 'plugin' %}example_workflow.py{% endif %}.jinja @@ -1,4 +1,7 @@ -"""Random values workflow plugin module""" +"""Random values workflow plugin module + +Remove this and other example files after bootstrapping your project. +""" import uuid from collections.abc import Sequence diff --git a/tests/generic-project.yml b/tests/generic-project.yml new file mode 100644 index 0000000..d8c3f95 --- /dev/null +++ b/tests/generic-project.yml @@ -0,0 +1,11 @@ +# Changes here will be overwritten by Copier +_commit: v6.4.0-12-ge025b98 +_src_path: . +author_mail: anonymous@example.org +author_name: Anonymous Person +github_page: '' +project_description: My generic project. +project_slug: generic-project +project_type: generic +pypi: false + diff --git a/tests/plugin-github-pypi.yml b/tests/plugin-github-pypi.yml new file mode 100644 index 0000000..c7fbeaf --- /dev/null +++ b/tests/plugin-github-pypi.yml @@ -0,0 +1,12 @@ +# Changes here will be overwritten by Copier +_commit: v6.4.0-16-gff7d5d3 +_src_path: . +author_mail: anonymous@example.org +author_name: Anonymous Person +github_page: https://github.com/eccenca/cmem-plugin-kafka +project_description: Create awesome Knowledge Graphs with eccenca Corporate Memory + :-) +project_slug: kafka +project_type: plugin +pypi: true + diff --git a/tests/plugin.yml b/tests/plugin.yml new file mode 100644 index 0000000..22958a8 --- /dev/null +++ b/tests/plugin.yml @@ -0,0 +1,12 @@ +# Changes here will be overwritten by Copier +_commit: v6.4.0-8-gedec671 +_src_path: . +author_mail: anonymous@example.org +author_name: Anonymous Person +github_page: '' +project_description: Create awesome Knowledge Graphs with eccenca Corporate Memory + :-) +project_slug: awesome +project_type: plugin +pypi: false +