From b347acbfd18552be8a84cb5a18aa57f011ac0b69 Mon Sep 17 00:00:00 2001 From: Jean-Marie Mineau Date: Fri, 24 Mar 2023 18:46:12 +0100 Subject: [PATCH 01/24] first commit --- cookiecutter.json | 13 ++ hooks/post_gen_project.py | 11 ++ {{ cookiecutter.project_name }}/.gitignore | 32 +++++ {{ cookiecutter.project_name }}/LICENSE | 111 ++++++++++++++++++ .../pyproject.toml | 42 +++++++ 5 files changed, 209 insertions(+) create mode 100644 cookiecutter.json create mode 100644 hooks/post_gen_project.py create mode 100644 {{ cookiecutter.project_name }}/.gitignore create mode 100644 {{ cookiecutter.project_name }}/LICENSE create mode 100644 {{ cookiecutter.project_name }}/pyproject.toml diff --git a/cookiecutter.json b/cookiecutter.json new file mode 100644 index 0000000..86b806c --- /dev/null +++ b/cookiecutter.json @@ -0,0 +1,13 @@ +{ + "project_name": "", + "project_short_description": "", + "full_name": "Jean-Marie 'Histausse' Mineau", + "email": "histausse@protonmail.com", + "git_user": "histausse", + "project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_').replace('-', '_') }}", + "project_url": "https://git.mineau.eu/{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}", + "git_ogirin": "git@git.mineau.eu/{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}.git", + "version": "0.1.0", + "open_source_license": ["GNU General Public License v3", "MIT license", "BSD license", "ISC license", "Apache Software License 2.0", "Not open source"], + "python_min_version": "3.10" +} diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py new file mode 100644 index 0000000..e01a4e3 --- /dev/null +++ b/hooks/post_gen_project.py @@ -0,0 +1,11 @@ +import subprocess + +subprocess.call(["git", "init"]) +subprocess.call(["git", "add", "*"]) +subprocess.call(["git", "commit", "-m", "Initial commit"]) +subprocess.call(["git", "config", "user.name", "{{ cookiecutter.git_user }}"]) +subprocess.call(["git", "config", "user.email", "{{ cookiecutter.email }}"]) +subprocess.call(["git", "remote", "add", "origin", "{{ cookiecutter.git_ogirin }}"]) +subprocess.call(["git", "branch", "-u", "origin/master"]) + +subprocess.call(["python", "-m", "venv", "venv"]) diff --git a/{{ cookiecutter.project_name }}/.gitignore b/{{ cookiecutter.project_name }}/.gitignore new file mode 100644 index 0000000..a23a015 --- /dev/null +++ b/{{ cookiecutter.project_name }}/.gitignore @@ -0,0 +1,32 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# virtualenv +venv/ + +# mypy +.mypy_cache/ diff --git a/{{ cookiecutter.project_name }}/LICENSE b/{{ cookiecutter.project_name }}/LICENSE new file mode 100644 index 0000000..24b2600 --- /dev/null +++ b/{{ cookiecutter.project_name }}/LICENSE @@ -0,0 +1,111 @@ +{% if cookiecutter.open_source_license == 'MIT license' -%} +MIT License + +Copyright (c) {% now 'local', '%Y' %}, {{ cookiecutter.full_name }} + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +{% elif cookiecutter.open_source_license == 'BSD license' %} + +BSD License + +Copyright (c) {% now 'local', '%Y' %}, {{ cookiecutter.full_name }} +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. +{% elif cookiecutter.open_source_license == 'ISC license' -%} +ISC License + +Copyright (c) {% now 'local', '%Y' %}, {{ cookiecutter.full_name }} + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +{% elif cookiecutter.open_source_license == 'Apache Software License 2.0' -%} +Apache Software License 2.0 + +Copyright (c) {% now 'local', '%Y' %}, {{ cookiecutter.full_name }} + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +{% elif cookiecutter.open_source_license == 'GNU General Public License v3' -%} +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + {{ cookiecutter.project_short_description }} + Copyright (C) {% now 'local', '%Y' %} {{ cookiecutter.full_name }} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. +{% endif %} diff --git a/{{ cookiecutter.project_name }}/pyproject.toml b/{{ cookiecutter.project_name }}/pyproject.toml new file mode 100644 index 0000000..2f8ce77 --- /dev/null +++ b/{{ cookiecutter.project_name }}/pyproject.toml @@ -0,0 +1,42 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "{{ cookiecutter.project_slug }}" +version = "{{ cookiecutter.version }}" +authors = [ + { name="{{ cookiecutter.full_name }}", email="{{ cookiecutter.email }}" }, +] +description = "{{ cookiecutter.project_short_description }}" +readme = "README.md" + +requires-python = ">={{ cookiecutter.python_min_version }}" +dependencies = [] + +[project.urls] +"Homepage" = "{{ cookiecutter.project_url }}" +"Bug Tracker" = "{{ cookiecutter.project_url }}/issues" +[histausse@grace-hopper {{ cookiecutter.project_name }}]$ cat ../../pyproject.toml +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "{{ cookiecutter.project_slug }}" +version = "{{ cookiecutter.version }}" +authors = [ + { name="{{ cookiecutter.full_name }}", email="{{ cookiecutter.email }}" }, +] +description = "{{ cookiecutter.project_short_description }}" +readme = "README.md" + +requires-python = ">={{ cookiecutter.python_min_version }}" +dependencies = [] + +[project.urls] +"Homepage" = "{{ cookiecutter.project_url }}" +"Bug Tracker" = "{{ cookiecutter.project_url }}/issues" + +[project.scripts] +analyse_artifact = "{{ cookiecutter.project_slug }}.cli:main" From 997726d4a0639d223595066722f533f329a7afa7 Mon Sep 17 00:00:00 2001 From: Histausse Date: Sat, 25 Mar 2023 19:11:17 +0100 Subject: [PATCH 02/24] Fix folder name --- TODO.md | 6 +++ .../pyproject.toml | 42 ------------------- .../.gitignore | 0 .../LICENSE | 0 .../pyproject.toml | 22 ++++++++++ .../__init__.py | 3 ++ .../{{ cookiecutter.project_slug }}/cli.py | 9 ++++ 7 files changed, 40 insertions(+), 42 deletions(-) create mode 100644 TODO.md delete mode 100644 {{ cookiecutter.project_name }}/pyproject.toml rename {{{ cookiecutter.project_name }} => {{ cookiecutter.project_slug }}}/.gitignore (100%) rename {{{ cookiecutter.project_name }} => {{ cookiecutter.project_slug }}}/LICENSE (100%) create mode 100644 {{ cookiecutter.project_slug }}/pyproject.toml create mode 100644 {{ cookiecutter.project_slug }}/src/{{ cookiecutter.project_slug }}/__init__.py create mode 100644 {{ cookiecutter.project_slug }}/src/{{ cookiecutter.project_slug }}/cli.py diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..c8e6121 --- /dev/null +++ b/TODO.md @@ -0,0 +1,6 @@ +# TODO: + +- readme +- tests +- pyenv +- mypy/black/etc diff --git a/{{ cookiecutter.project_name }}/pyproject.toml b/{{ cookiecutter.project_name }}/pyproject.toml deleted file mode 100644 index 2f8ce77..0000000 --- a/{{ cookiecutter.project_name }}/pyproject.toml +++ /dev/null @@ -1,42 +0,0 @@ -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[project] -name = "{{ cookiecutter.project_slug }}" -version = "{{ cookiecutter.version }}" -authors = [ - { name="{{ cookiecutter.full_name }}", email="{{ cookiecutter.email }}" }, -] -description = "{{ cookiecutter.project_short_description }}" -readme = "README.md" - -requires-python = ">={{ cookiecutter.python_min_version }}" -dependencies = [] - -[project.urls] -"Homepage" = "{{ cookiecutter.project_url }}" -"Bug Tracker" = "{{ cookiecutter.project_url }}/issues" -[histausse@grace-hopper {{ cookiecutter.project_name }}]$ cat ../../pyproject.toml -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[project] -name = "{{ cookiecutter.project_slug }}" -version = "{{ cookiecutter.version }}" -authors = [ - { name="{{ cookiecutter.full_name }}", email="{{ cookiecutter.email }}" }, -] -description = "{{ cookiecutter.project_short_description }}" -readme = "README.md" - -requires-python = ">={{ cookiecutter.python_min_version }}" -dependencies = [] - -[project.urls] -"Homepage" = "{{ cookiecutter.project_url }}" -"Bug Tracker" = "{{ cookiecutter.project_url }}/issues" - -[project.scripts] -analyse_artifact = "{{ cookiecutter.project_slug }}.cli:main" diff --git a/{{ cookiecutter.project_name }}/.gitignore b/{{ cookiecutter.project_slug }}/.gitignore similarity index 100% rename from {{ cookiecutter.project_name }}/.gitignore rename to {{ cookiecutter.project_slug }}/.gitignore diff --git a/{{ cookiecutter.project_name }}/LICENSE b/{{ cookiecutter.project_slug }}/LICENSE similarity index 100% rename from {{ cookiecutter.project_name }}/LICENSE rename to {{ cookiecutter.project_slug }}/LICENSE diff --git a/{{ cookiecutter.project_slug }}/pyproject.toml b/{{ cookiecutter.project_slug }}/pyproject.toml new file mode 100644 index 0000000..cab525d --- /dev/null +++ b/{{ cookiecutter.project_slug }}/pyproject.toml @@ -0,0 +1,22 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "{{ cookiecutter.project_slug }}" +version = "{{ cookiecutter.version }}" +authors = [ + { name="{{ cookiecutter.full_name }}", email="{{ cookiecutter.email }}" }, +] +description = "{{ cookiecutter.project_short_description }}" +readme = "README.md" + +requires-python = ">={{ cookiecutter.python_min_version }}" +dependencies = [] + +[project.urls] +"Homepage" = "{{ cookiecutter.project_url }}" +"Bug Tracker" = "{{ cookiecutter.project_url }}/issues" + +[project.scripts] +analyse_artifact = "{{ cookiecutter.project_slug }}.cli:main" diff --git a/{{ cookiecutter.project_slug }}/src/{{ cookiecutter.project_slug }}/__init__.py b/{{ cookiecutter.project_slug }}/src/{{ cookiecutter.project_slug }}/__init__.py new file mode 100644 index 0000000..594e5b7 --- /dev/null +++ b/{{ cookiecutter.project_slug }}/src/{{ cookiecutter.project_slug }}/__init__.py @@ -0,0 +1,3 @@ +__author__ = """{{ cookiecutter.full_name }}""" +__email__ = '{{ cookiecutter.email }}' +__version__ = '{{ cookiecutter.version }}' diff --git a/{{ cookiecutter.project_slug }}/src/{{ cookiecutter.project_slug }}/cli.py b/{{ cookiecutter.project_slug }}/src/{{ cookiecutter.project_slug }}/cli.py new file mode 100644 index 0000000..5bc4b0a --- /dev/null +++ b/{{ cookiecutter.project_slug }}/src/{{ cookiecutter.project_slug }}/cli.py @@ -0,0 +1,9 @@ +import argparse + +def main(): + """ Console entrypoint for {{cookiecutter.project_slug}}.""" + parser = argparse.ArgumentParser() + parser.add_argument('_', nargs='*') + args = parser.parse_args() + print("Hello word!") + From d008bf01bef790c9efb7e01a67d6aaafd9ddd2e5 Mon Sep 17 00:00:00 2001 From: Histausse Date: Sat, 25 Mar 2023 19:40:37 +0100 Subject: [PATCH 03/24] add .md files and pyenv --- TODO.md | 5 ++-- .../.python-version | 1 + {{ cookiecutter.project_slug }}/README.md | 26 +++++++++++++++++++ {{ cookiecutter.project_slug }}/SECURITY.md | 3 +++ 4 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 {{ cookiecutter.project_slug }}/.python-version create mode 100644 {{ cookiecutter.project_slug }}/README.md create mode 100644 {{ cookiecutter.project_slug }}/SECURITY.md diff --git a/TODO.md b/TODO.md index c8e6121..0b026f6 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,5 @@ # TODO: -- readme +- generate gitea project - tests -- pyenv -- mypy/black/etc +- add AGPL diff --git a/{{ cookiecutter.project_slug }}/.python-version b/{{ cookiecutter.project_slug }}/.python-version new file mode 100644 index 0000000..3e72e17 --- /dev/null +++ b/{{ cookiecutter.project_slug }}/.python-version @@ -0,0 +1 @@ +{{ cookiecutter.python_min_version }} diff --git a/{{ cookiecutter.project_slug }}/README.md b/{{ cookiecutter.project_slug }}/README.md new file mode 100644 index 0000000..a718cc6 --- /dev/null +++ b/{{ cookiecutter.project_slug }}/README.md @@ -0,0 +1,26 @@ +{% set is_open_source = cookiecutter.open_source_license != 'Not open source' -%} +# {{ cookiecutter.project_name }} + +{{ cookiecutter.project_short_description }} + +## Install + +This project can be installed using pip: + +``` +pip install git+{{ cookiecutter.project_url }}.git +``` + +{% if is_open_source %} +## License + +This project if a free software released under the {{ cookiecutter.open_source_license }}. +{% endif %} + +## Author + +- {{ cookiecutter.full_name }} + +## Security + +If you discover a potential security issue in this project, please contact {{ cookiecutter.email }}. diff --git a/{{ cookiecutter.project_slug }}/SECURITY.md b/{{ cookiecutter.project_slug }}/SECURITY.md new file mode 100644 index 0000000..cd89d47 --- /dev/null +++ b/{{ cookiecutter.project_slug }}/SECURITY.md @@ -0,0 +1,3 @@ +# Reporting a Vulnerability + +If you discover a potential security issue in this project, please contact {{ cookiecutter.email }}. From 28d3163ca74916739baea96ab3a9ac20b6a28578 Mon Sep 17 00:00:00 2001 From: Histausse Date: Sat, 25 Mar 2023 19:46:53 +0100 Subject: [PATCH 04/24] fix script name --- {{ cookiecutter.project_slug }}/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.project_slug }}/pyproject.toml b/{{ cookiecutter.project_slug }}/pyproject.toml index cab525d..86f8343 100644 --- a/{{ cookiecutter.project_slug }}/pyproject.toml +++ b/{{ cookiecutter.project_slug }}/pyproject.toml @@ -19,4 +19,4 @@ dependencies = [] "Bug Tracker" = "{{ cookiecutter.project_url }}/issues" [project.scripts] -analyse_artifact = "{{ cookiecutter.project_slug }}.cli:main" +{{ cookiecutter.project_slug }} = "{{ cookiecutter.project_slug }}.cli:main" From 0c830127ec67ba1f74892092c08c70c30da1cf2a Mon Sep 17 00:00:00 2001 From: Histausse Date: Sat, 25 Mar 2023 21:02:31 +0100 Subject: [PATCH 05/24] Generate gitea project automagically --- TODO.md | 1 - cookiecutter.json | 6 ++++-- hooks/post_gen_project.py | 42 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/TODO.md b/TODO.md index 0b026f6..fa45df9 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,4 @@ # TODO: -- generate gitea project - tests - add AGPL diff --git a/cookiecutter.json b/cookiecutter.json index 86b806c..248c345 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -5,8 +5,10 @@ "email": "histausse@protonmail.com", "git_user": "histausse", "project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_').replace('-', '_') }}", - "project_url": "https://git.mineau.eu/{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}", - "git_ogirin": "git@git.mineau.eu/{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}.git", + "gitea_url": "https://git.mineau.eu", + "project_url": "{{ cookiecutter.gitea_url }}/{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}", + "generate_gitea_project": true, + "git_origin": "{{ cookiecutter.gitea_url.replace('https://', 'gitea@').replace('http://', 'gitea') }}:{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}.git", "version": "0.1.0", "open_source_license": ["GNU General Public License v3", "MIT license", "BSD license", "ISC license", "Apache Software License 2.0", "Not open source"], "python_min_version": "3.10" diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index e01a4e3..0330ee6 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -5,7 +5,45 @@ subprocess.call(["git", "add", "*"]) subprocess.call(["git", "commit", "-m", "Initial commit"]) subprocess.call(["git", "config", "user.name", "{{ cookiecutter.git_user }}"]) subprocess.call(["git", "config", "user.email", "{{ cookiecutter.email }}"]) -subprocess.call(["git", "remote", "add", "origin", "{{ cookiecutter.git_ogirin }}"]) -subprocess.call(["git", "branch", "-u", "origin/master"]) subprocess.call(["python", "-m", "venv", "venv"]) + +if {{cookiecutter.generate_gitea_project}}: + try: + import giteapy + except ModuleNotFoundError: + print("giteapy is not availabled, repository not created") + exit() + try: + import secretstorage + + connection = secretstorage.dbus_init() + collection = secretstorage.get_default_collection(connection) + collection.unlock() + secret = collection.search_items({"Title": "Gitea Token"}).__next__() + secret.unlock() + API_KEY = secret.get_secret().decode("utf-8") + except (ModuleNotFoundError, StopIteration): + try: + import getpass + + my_input = getpass.getpass + except ModuleNotFoundError: + my_input = input + API_KEY = my_input( + "Secret service or secret {'Title': 'Gitea Token'} not available," + "please enter you gitea api key:" + ) + configuration = giteapy.Configuration() + configuration.api_key["access_token"] = API_KEY + client = giteapy.ApiClient(configuration) + client.configuration.host = "{{ cookiecutter.gitea_url }}/api/v1" + api_instance = giteapy.AdminApi(client) + username = "{{ cookiecutter.git_user }}" + repo = giteapy.CreateRepoOption( + name="{{ cookiecutter.project_slug }}", private=True + ) + api_instance.admin_create_repo(username, repo) + + subprocess.call(["git", "remote", "add", "origin", "{{ cookiecutter.git_origin }}"]) + subprocess.call(["git", "push", "-u", "origin", "master"]) From a5627c192d94d3d719b43db00838f63b0d614404 Mon Sep 17 00:00:00 2001 From: Histausse Date: Sun, 26 Mar 2023 17:28:37 +0200 Subject: [PATCH 06/24] use choice var instead of not yet released bool var --- TODO.md | 1 + cookiecutter.json | 2 +- hooks/post_gen_project.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index fa45df9..954c32f 100644 --- a/TODO.md +++ b/TODO.md @@ -2,3 +2,4 @@ - tests - add AGPL +- use bool value for `generate_gitea_project` when the feature is available diff --git a/cookiecutter.json b/cookiecutter.json index 248c345..fd4841d 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -7,7 +7,7 @@ "project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_').replace('-', '_') }}", "gitea_url": "https://git.mineau.eu", "project_url": "{{ cookiecutter.gitea_url }}/{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}", - "generate_gitea_project": true, + "generate_gitea_project": [ true, false ], "git_origin": "{{ cookiecutter.gitea_url.replace('https://', 'gitea@').replace('http://', 'gitea') }}:{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}.git", "version": "0.1.0", "open_source_license": ["GNU General Public License v3", "MIT license", "BSD license", "ISC license", "Apache Software License 2.0", "Not open source"], diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 0330ee6..323e35d 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -32,7 +32,7 @@ if {{cookiecutter.generate_gitea_project}}: my_input = input API_KEY = my_input( "Secret service or secret {'Title': 'Gitea Token'} not available," - "please enter you gitea api key:" + "please enter you gitea api token:" ) configuration = giteapy.Configuration() configuration.api_key["access_token"] = API_KEY From 1698a2121e1459ef342ff19de4f5c9f4f8b8cfd8 Mon Sep 17 00:00:00 2001 From: Histausse Date: Sun, 26 Mar 2023 18:22:27 +0200 Subject: [PATCH 07/24] add pytest --- {{ cookiecutter.project_slug }}/README.md | 20 +++++++++++++++++++ .../pyproject.toml | 11 ++++++++++ .../test_{{ cookiecutter.project_slug }}.py | 4 ++++ 3 files changed, 35 insertions(+) create mode 100644 {{ cookiecutter.project_slug }}/tests/test_{{ cookiecutter.project_slug }}.py diff --git a/{{ cookiecutter.project_slug }}/README.md b/{{ cookiecutter.project_slug }}/README.md index a718cc6..4e5c514 100644 --- a/{{ cookiecutter.project_slug }}/README.md +++ b/{{ cookiecutter.project_slug }}/README.md @@ -15,6 +15,25 @@ pip install git+{{ cookiecutter.project_url }}.git ## License This project if a free software released under the {{ cookiecutter.open_source_license }}. + +## Dev + +If you want to tinker with this project, you can clone it and install it in editable mode: + +``` +git clone {{ cookiecutter.project_url }}.git +cd {{ cookiecutter.project_slug }} +python -m venv venv && source venv/bin/activate +pip install -e .[dev] +``` + +### Test + +Tests are run using `pytest`: + +``` +pytest +``` {% endif %} ## Author @@ -24,3 +43,4 @@ This project if a free software released under the {{ cookiecutter.open_source_l ## Security If you discover a potential security issue in this project, please contact {{ cookiecutter.email }}. + diff --git a/{{ cookiecutter.project_slug }}/pyproject.toml b/{{ cookiecutter.project_slug }}/pyproject.toml index 86f8343..c29604a 100644 --- a/{{ cookiecutter.project_slug }}/pyproject.toml +++ b/{{ cookiecutter.project_slug }}/pyproject.toml @@ -14,9 +14,20 @@ readme = "README.md" requires-python = ">={{ cookiecutter.python_min_version }}" dependencies = [] +[project.optional-dependencies] +test = [ + "pytest >=7.2.2", +] +dev = ["{{ cookiecutter.project_slug }}[test]"] + [project.urls] "Homepage" = "{{ cookiecutter.project_url }}" "Bug Tracker" = "{{ cookiecutter.project_url }}/issues" [project.scripts] {{ cookiecutter.project_slug }} = "{{ cookiecutter.project_slug }}.cli:main" + +[tool.pytest.ini_options] +addopts = [ + "--import-mode=importlib", +] diff --git a/{{ cookiecutter.project_slug }}/tests/test_{{ cookiecutter.project_slug }}.py b/{{ cookiecutter.project_slug }}/tests/test_{{ cookiecutter.project_slug }}.py new file mode 100644 index 0000000..35c1b8d --- /dev/null +++ b/{{ cookiecutter.project_slug }}/tests/test_{{ cookiecutter.project_slug }}.py @@ -0,0 +1,4 @@ +import {{ cookiecutter.project_slug }} + +def test_dummy(): + assert True From 2b7362c2f46fbbcaefaa8815549fddebeb5b5313 Mon Sep 17 00:00:00 2001 From: Histausse Date: Mon, 15 May 2023 13:23:02 +0200 Subject: [PATCH 08/24] poetry version --- README.md | 21 ++++ TODO.md | 8 ++ cookiecutter.json | 15 +++ hooks/post_gen_project.py | 50 ++++++++ {{ cookiecutter.project_slug }}/.gitignore | 32 +++++ {{ cookiecutter.project_slug }}/LICENSE | 111 ++++++++++++++++++ {{ cookiecutter.project_slug }}/README.md | 46 ++++++++ {{ cookiecutter.project_slug }}/SECURITY.md | 3 + .../pyproject.toml | 22 ++++ .../tests/__init__.py | 0 .../__init__.py | 3 + .../{{ cookiecutter.project_slug }}/cli.py | 8 ++ 12 files changed, 319 insertions(+) create mode 100644 README.md create mode 100644 TODO.md create mode 100644 cookiecutter.json create mode 100644 hooks/post_gen_project.py create mode 100644 {{ cookiecutter.project_slug }}/.gitignore create mode 100644 {{ cookiecutter.project_slug }}/LICENSE create mode 100644 {{ cookiecutter.project_slug }}/README.md create mode 100644 {{ cookiecutter.project_slug }}/SECURITY.md create mode 100644 {{ cookiecutter.project_slug }}/pyproject.toml create mode 100644 {{ cookiecutter.project_slug }}/tests/__init__.py create mode 100644 {{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/__init__.py create mode 100644 {{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/cli.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..d4154d1 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# Python template + +A template for python project using [cookicutter](https://github.com/cookiecutter/cookiecutter). + + +## Cookicutter config + +A good config to have for cookicutter at `~/.cookiecutterrc`: + +``` +abbreviations: + pp: https://git.pains-perdus.fr/templates/{}.git + +default_context: + full_name: "Jane Doe" + email: "jane.doe@example.com" + git_user: "jdoe" + gitea_url: "https://git.pains-perdus.fr" +``` + +To create the project on gitea, cookie cutter needs the `giteapy` module and a gitea token. The token can be retrieved with the `secretstorage` by looking up the secret `"Title": "Gitea Token"`, or by prompting the user. diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..f741092 --- /dev/null +++ b/TODO.md @@ -0,0 +1,8 @@ +# TODO: + +- edit readme to use poetry +- tests +- add AGPL +- add CI +- add flake +- use bool value for `generate_gitea_project` when the feature is available diff --git a/cookiecutter.json b/cookiecutter.json new file mode 100644 index 0000000..899337e --- /dev/null +++ b/cookiecutter.json @@ -0,0 +1,15 @@ +{ + "project_name": "", + "project_short_description": "", + "full_name": "", + "email": "", + "git_user": "", + "project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_').replace('-', '_') }}", + "gitea_url": "", + "project_url": "{{ cookiecutter.gitea_url }}/{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}", + "generate_gitea_project": [ true, false ], + "git_origin": "{{ cookiecutter.gitea_url.replace('https://', 'gitea@').replace('http://', 'gitea') }}:{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}.git", + "version": "0.1.0", + "open_source_license": ["GNU General Public License v3", "MIT license", "BSD license", "ISC license", "Apache Software License 2.0", "Proprietary"], + "python_min_version": "3.10" +} diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py new file mode 100644 index 0000000..1318aea --- /dev/null +++ b/hooks/post_gen_project.py @@ -0,0 +1,50 @@ +import subprocess + +subprocess.call(["git", "init"]) +subprocess.call(["git", "checkout", "-b", "main"]) +subprocess.call(["git", "add", "*"]) +subprocess.call(["git", "commit", "-m", "Initial commit"]) +subprocess.call(["git", "config", "user.name", "{{ cookiecutter.git_user }}"]) +subprocess.call(["git", "config", "user.email", "{{ cookiecutter.email }}"]) + +#subprocess.call(["python", "-m", "venv", "venv"]) + +if {{cookiecutter.generate_gitea_project}}: + try: + import giteapy + except ModuleNotFoundError: + print("giteapy is not availabled, repository not created") + exit() + try: + import secretstorage + + connection = secretstorage.dbus_init() + collection = secretstorage.get_default_collection(connection) + collection.unlock() + secret = collection.search_items({"Title": "Gitea Token"}).__next__() + secret.unlock() + API_KEY = secret.get_secret().decode("utf-8") + except (ModuleNotFoundError, StopIteration): + try: + import getpass + + my_input = getpass.getpass + except ModuleNotFoundError: + my_input = input + API_KEY = my_input( + "Secret service or secret {'Title': 'Gitea Token'} not available," + "please enter you gitea api token:" + ) + configuration = giteapy.Configuration() + configuration.api_key["access_token"] = API_KEY + client = giteapy.ApiClient(configuration) + client.configuration.host = "{{ cookiecutter.gitea_url }}/api/v1" + api_instance = giteapy.AdminApi(client) + username = "{{ cookiecutter.git_user }}" + repo = giteapy.CreateRepoOption( + name="{{ cookiecutter.project_slug }}", private=True + ) + api_instance.admin_create_repo(username, repo) + + subprocess.call(["git", "remote", "add", "origin", "{{ cookiecutter.git_origin }}"]) + subprocess.call(["git", "push", "-u", "origin", "master"]) diff --git a/{{ cookiecutter.project_slug }}/.gitignore b/{{ cookiecutter.project_slug }}/.gitignore new file mode 100644 index 0000000..a23a015 --- /dev/null +++ b/{{ cookiecutter.project_slug }}/.gitignore @@ -0,0 +1,32 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# virtualenv +venv/ + +# mypy +.mypy_cache/ diff --git a/{{ cookiecutter.project_slug }}/LICENSE b/{{ cookiecutter.project_slug }}/LICENSE new file mode 100644 index 0000000..24b2600 --- /dev/null +++ b/{{ cookiecutter.project_slug }}/LICENSE @@ -0,0 +1,111 @@ +{% if cookiecutter.open_source_license == 'MIT license' -%} +MIT License + +Copyright (c) {% now 'local', '%Y' %}, {{ cookiecutter.full_name }} + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +{% elif cookiecutter.open_source_license == 'BSD license' %} + +BSD License + +Copyright (c) {% now 'local', '%Y' %}, {{ cookiecutter.full_name }} +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. +{% elif cookiecutter.open_source_license == 'ISC license' -%} +ISC License + +Copyright (c) {% now 'local', '%Y' %}, {{ cookiecutter.full_name }} + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +{% elif cookiecutter.open_source_license == 'Apache Software License 2.0' -%} +Apache Software License 2.0 + +Copyright (c) {% now 'local', '%Y' %}, {{ cookiecutter.full_name }} + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +{% elif cookiecutter.open_source_license == 'GNU General Public License v3' -%} +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + {{ cookiecutter.project_short_description }} + Copyright (C) {% now 'local', '%Y' %} {{ cookiecutter.full_name }} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. +{% endif %} diff --git a/{{ cookiecutter.project_slug }}/README.md b/{{ cookiecutter.project_slug }}/README.md new file mode 100644 index 0000000..99ed047 --- /dev/null +++ b/{{ cookiecutter.project_slug }}/README.md @@ -0,0 +1,46 @@ +{% set is_open_source = cookiecutter.open_source_license != 'Proprietary' -%} +# {{ cookiecutter.project_name }} + +{{ cookiecutter.project_short_description }} + +## Install + +This project can be installed using pip: + +``` +pip install git+{{ cookiecutter.project_url }}.git +``` + +{% if is_open_source %} +## License + +This project if a free software released under the {{ cookiecutter.open_source_license }}. + +## Dev + +If you want to tinker with this project, you can clone it and install it in editable mode: + +``` +git clone {{ cookiecutter.project_url }}.git +cd {{ cookiecutter.project_slug }} +python -m venv venv && source venv/bin/activate +pip install -e .[dev] +``` + +### Test + +Tests are run using `pytest`: + +``` +pytest +``` +{% endif %} + +## Author + +- {{ cookiecutter.full_name }} + +## Security + +If you discover a potential security issue in this project, please contact {{ cookiecutter.email }}. + diff --git a/{{ cookiecutter.project_slug }}/SECURITY.md b/{{ cookiecutter.project_slug }}/SECURITY.md new file mode 100644 index 0000000..cd89d47 --- /dev/null +++ b/{{ cookiecutter.project_slug }}/SECURITY.md @@ -0,0 +1,3 @@ +# Reporting a Vulnerability + +If you discover a potential security issue in this project, please contact {{ cookiecutter.email }}. diff --git a/{{ cookiecutter.project_slug }}/pyproject.toml b/{{ cookiecutter.project_slug }}/pyproject.toml new file mode 100644 index 0000000..3c63433 --- /dev/null +++ b/{{ cookiecutter.project_slug }}/pyproject.toml @@ -0,0 +1,22 @@ +[tool.poetry] +name = "{{ cookiecutter.project_slug }}" +version = "{{ cookiecutter.version }}" +description = "{{ cookiecutter.project_short_description }}" +authors = ["{{ cookiecutter.full_name }} <{{ cookiecutter.email }}>"] +readme = "README.md" +homepage = "{{ cookiecutter.project_url }}" +repository = "{{ cookiecutter.project_url }}" +license = "{{ cookiecutter.open_source_license }}" + +[tool.poetry.urls] +"Bug Tracker" = "{{ cookiecutter.project_url }}/issues" + +[tool.poetry.dependencies] +python = "^3.10" + +[tool.poetry.scripts] +{{ cookiecutter.project_slug }} = "{{ cookiecutter.project_slug }}.cli:main" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/{{ cookiecutter.project_slug }}/tests/__init__.py b/{{ cookiecutter.project_slug }}/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/__init__.py b/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/__init__.py new file mode 100644 index 0000000..594e5b7 --- /dev/null +++ b/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/__init__.py @@ -0,0 +1,3 @@ +__author__ = """{{ cookiecutter.full_name }}""" +__email__ = '{{ cookiecutter.email }}' +__version__ = '{{ cookiecutter.version }}' diff --git a/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/cli.py b/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/cli.py new file mode 100644 index 0000000..7f605ce --- /dev/null +++ b/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/cli.py @@ -0,0 +1,8 @@ +import argparse + +def main(): + """ Console entrypoint for {{cookiecutter.project_slug}}.""" + parser = argparse.ArgumentParser() + parser.add_argument('_', nargs='*') + args = parser.parse_args() + print("Hello word!") From f60257935736a2484306e119c12fc2e77b4606aa Mon Sep 17 00:00:00 2001 From: Histausse Date: Mon, 15 May 2023 21:35:47 +0200 Subject: [PATCH 09/24] master -> main --- hooks/post_gen_project.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 1318aea..f236e63 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -7,7 +7,7 @@ subprocess.call(["git", "commit", "-m", "Initial commit"]) subprocess.call(["git", "config", "user.name", "{{ cookiecutter.git_user }}"]) subprocess.call(["git", "config", "user.email", "{{ cookiecutter.email }}"]) -#subprocess.call(["python", "-m", "venv", "venv"]) +# subprocess.call(["python", "-m", "venv", "venv"]) if {{cookiecutter.generate_gitea_project}}: try: @@ -47,4 +47,4 @@ if {{cookiecutter.generate_gitea_project}}: api_instance.admin_create_repo(username, repo) subprocess.call(["git", "remote", "add", "origin", "{{ cookiecutter.git_origin }}"]) - subprocess.call(["git", "push", "-u", "origin", "master"]) + subprocess.call(["git", "push", "-u", "origin", "main"]) From a4dfffb40dd285c103efbaf8d927a6b70d9245c7 Mon Sep 17 00:00:00 2001 From: Histausse Date: Mon, 15 May 2023 22:00:30 +0200 Subject: [PATCH 10/24] reference to poetry in readme --- TODO.md | 1 - {{ cookiecutter.project_slug }}/.gitignore | 1 + {{ cookiecutter.project_slug }}/README.md | 7 ++++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/TODO.md b/TODO.md index f741092..33f655a 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,5 @@ # TODO: -- edit readme to use poetry - tests - add AGPL - add CI diff --git a/{{ cookiecutter.project_slug }}/.gitignore b/{{ cookiecutter.project_slug }}/.gitignore index a23a015..f9373f0 100644 --- a/{{ cookiecutter.project_slug }}/.gitignore +++ b/{{ cookiecutter.project_slug }}/.gitignore @@ -26,6 +26,7 @@ wheels/ *.egg # virtualenv +.venv/ venv/ # mypy diff --git a/{{ cookiecutter.project_slug }}/README.md b/{{ cookiecutter.project_slug }}/README.md index 99ed047..23d57dd 100644 --- a/{{ cookiecutter.project_slug }}/README.md +++ b/{{ cookiecutter.project_slug }}/README.md @@ -18,13 +18,14 @@ This project if a free software released under the {{ cookiecutter.open_source_l ## Dev -If you want to tinker with this project, you can clone it and install it in editable mode: +This project is managed by [poetry](https://python-poetry.org/). +To open a shell in a venv of the project: ``` git clone {{ cookiecutter.project_url }}.git cd {{ cookiecutter.project_slug }} -python -m venv venv && source venv/bin/activate -pip install -e .[dev] +poetry shell +poetry install ``` ### Test From d7ebe08091be3a2a66169706163f5f17f1c84f69 Mon Sep 17 00:00:00 2001 From: Histausse Date: Mon, 15 May 2023 22:41:42 +0200 Subject: [PATCH 11/24] add tests --- TODO.md | 1 - {{ cookiecutter.project_slug }}/README.md | 3 ++- {{ cookiecutter.project_slug }}/pyproject.toml | 7 +++++++ {{ cookiecutter.project_slug }}/tests/test_dummy.py | 4 ++++ .../{{ cookiecutter.project_slug }}/cli.py | 1 + 5 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 {{ cookiecutter.project_slug }}/tests/test_dummy.py diff --git a/TODO.md b/TODO.md index 33f655a..816fc7d 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,5 @@ # TODO: -- tests - add AGPL - add CI - add flake diff --git a/{{ cookiecutter.project_slug }}/README.md b/{{ cookiecutter.project_slug }}/README.md index 23d57dd..7a4eaf5 100644 --- a/{{ cookiecutter.project_slug }}/README.md +++ b/{{ cookiecutter.project_slug }}/README.md @@ -33,8 +33,9 @@ poetry install Tests are run using `pytest`: ``` -pytest +poetry run pytest ``` + {% endif %} ## Author diff --git a/{{ cookiecutter.project_slug }}/pyproject.toml b/{{ cookiecutter.project_slug }}/pyproject.toml index 3c63433..fe42c60 100644 --- a/{{ cookiecutter.project_slug }}/pyproject.toml +++ b/{{ cookiecutter.project_slug }}/pyproject.toml @@ -17,6 +17,13 @@ python = "^3.10" [tool.poetry.scripts] {{ cookiecutter.project_slug }} = "{{ cookiecutter.project_slug }}.cli:main" +[tool.poetry.group.dev.dependencies] +pytest = "*" +pytest-cov = "*" + +[tool.pytest.ini_options] +addopts = "--cov" + [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" diff --git a/{{ cookiecutter.project_slug }}/tests/test_dummy.py b/{{ cookiecutter.project_slug }}/tests/test_dummy.py new file mode 100644 index 0000000..35c1b8d --- /dev/null +++ b/{{ cookiecutter.project_slug }}/tests/test_dummy.py @@ -0,0 +1,4 @@ +import {{ cookiecutter.project_slug }} + +def test_dummy(): + assert True diff --git a/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/cli.py b/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/cli.py index 7f605ce..090bab7 100644 --- a/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/cli.py +++ b/{{ cookiecutter.project_slug }}/{{ cookiecutter.project_slug }}/cli.py @@ -1,5 +1,6 @@ import argparse + def main(): """ Console entrypoint for {{cookiecutter.project_slug}}.""" parser = argparse.ArgumentParser() From f028d9ad2e73d154f861c4246f317ee6cc37fbc9 Mon Sep 17 00:00:00 2001 From: Histausse Date: Tue, 16 May 2023 12:53:02 +0200 Subject: [PATCH 12/24] clean up licenses --- TODO.md | 1 - cookiecutter.json | 2 +- {{ cookiecutter.project_slug }}/LICENSE | 39 +++++++++++++------------ 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/TODO.md b/TODO.md index 816fc7d..a3b6fe0 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,5 @@ # TODO: -- add AGPL - add CI - add flake - use bool value for `generate_gitea_project` when the feature is available diff --git a/cookiecutter.json b/cookiecutter.json index 899337e..ba2add7 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -10,6 +10,6 @@ "generate_gitea_project": [ true, false ], "git_origin": "{{ cookiecutter.gitea_url.replace('https://', 'gitea@').replace('http://', 'gitea') }}:{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}.git", "version": "0.1.0", - "open_source_license": ["GNU General Public License v3", "MIT license", "BSD license", "ISC license", "Apache Software License 2.0", "Proprietary"], + "open_source_license": ["AGPL-3.0-only", "GPL-3.0-only", "MIT", "BSD-3-Clause", "ISC", "Apache-2.0", "Proprietary"], "python_min_version": "3.10" } diff --git a/{{ cookiecutter.project_slug }}/LICENSE b/{{ cookiecutter.project_slug }}/LICENSE index 24b2600..28b9eca 100644 --- a/{{ cookiecutter.project_slug }}/LICENSE +++ b/{{ cookiecutter.project_slug }}/LICENSE @@ -1,4 +1,4 @@ -{% if cookiecutter.open_source_license == 'MIT license' -%} +{% if cookiecutter.open_source_license == 'MIT' -%} MIT License Copyright (c) {% now 'local', '%Y' %}, {{ cookiecutter.full_name }} @@ -20,7 +20,7 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -{% elif cookiecutter.open_source_license == 'BSD license' %} +{% elif cookiecutter.open_source_license == 'BSD-3-Clause' %} BSD License @@ -51,7 +51,7 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -{% elif cookiecutter.open_source_license == 'ISC license' -%} +{% elif cookiecutter.open_source_license == 'ISC' -%} ISC License Copyright (c) {% now 'local', '%Y' %}, {{ cookiecutter.full_name }} @@ -59,7 +59,7 @@ Copyright (c) {% now 'local', '%Y' %}, {{ cookiecutter.full_name }} Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -{% elif cookiecutter.open_source_license == 'Apache Software License 2.0' -%} +{% elif cookiecutter.open_source_license == 'Apache-2.0' -%} Apache Software License 2.0 Copyright (c) {% now 'local', '%Y' %}, {{ cookiecutter.full_name }} @@ -75,7 +75,7 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -{% elif cookiecutter.open_source_license == 'GNU General Public License v3' -%} +{% elif cookiecutter.open_source_license == 'GPL-3.0-only' -%} GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 @@ -84,8 +84,7 @@ GNU GENERAL PUBLIC LICENSE This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + the Free Software Foundation, version 3. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -94,18 +93,22 @@ GNU GENERAL PUBLIC LICENSE You should have received a copy of the GNU General Public License along with this program. If not, see . +{% elif cookiecutter.open_source_license == 'AGPL-3.0-only' %} +GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 -Also add information on how to contact you by electronic and paper mail. + {{ cookiecutter.project_short_description }} + Copyright (C) {% now 'local', '%Y' %} {{ cookiecutter.full_name }} - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, version 3. - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . {% endif %} From 5ceb648dc97e8a2d99460441998f9ecac66c7283 Mon Sep 17 00:00:00 2001 From: Histausse Date: Fri, 19 May 2023 17:16:55 +0200 Subject: [PATCH 13/24] first test for woodpecjer --- cookiecutter.json | 3 + hooks/post_gen_project.py | 69 ++++++++++++++----- .../.woodpecker.yml | 5 ++ 3 files changed, 59 insertions(+), 18 deletions(-) create mode 100644 {{ cookiecutter.project_slug }}/.woodpecker.yml diff --git a/cookiecutter.json b/cookiecutter.json index ba2add7..34664c8 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -8,6 +8,9 @@ "gitea_url": "", "project_url": "{{ cookiecutter.gitea_url }}/{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}", "generate_gitea_project": [ true, false ], + "configure_ci": [ true, false ], + "woodpecker_gitea_user": "ci", + "woodpecker_server": "ci.pains-perdus.fr", "git_origin": "{{ cookiecutter.gitea_url.replace('https://', 'gitea@').replace('http://', 'gitea') }}:{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}.git", "version": "0.1.0", "open_source_license": ["AGPL-3.0-only", "GPL-3.0-only", "MIT", "BSD-3-Clause", "ISC", "Apache-2.0", "Proprietary"], diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index f236e63..cd6c85d 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -9,42 +9,75 @@ subprocess.call(["git", "config", "user.email", "{{ cookiecutter.email }}"]) # subprocess.call(["python", "-m", "venv", "venv"]) -if {{cookiecutter.generate_gitea_project}}: - try: - import giteapy - except ModuleNotFoundError: - print("giteapy is not availabled, repository not created") - exit() + +def get_secret(secret_name: str): try: import secretstorage connection = secretstorage.dbus_init() collection = secretstorage.get_default_collection(connection) collection.unlock() - secret = collection.search_items({"Title": "Gitea Token"}).__next__() + secret = collection.search_items({"Title": secret_name}).__next__() secret.unlock() - API_KEY = secret.get_secret().decode("utf-8") + return secret.get_secret().decode("utf-8") except (ModuleNotFoundError, StopIteration): - try: - import getpass + import getpass - my_input = getpass.getpass - except ModuleNotFoundError: - my_input = input - API_KEY = my_input( - "Secret service or secret {'Title': 'Gitea Token'} not available," + return getpass.getpass( + f"Secret service or secret {'Title': 'secret_name'} not available," "please enter you gitea api token:" ) + + +if {{cookiecutter.generate_gitea_project}}: + try: + import giteapy + except ModuleNotFoundError: + print("module `giteapy` is not availabled, repository not created") + exit() + API_KEY = get_secret("Gitea Token") configuration = giteapy.Configuration() configuration.api_key["access_token"] = API_KEY client = giteapy.ApiClient(configuration) client.configuration.host = "{{ cookiecutter.gitea_url }}/api/v1" - api_instance = giteapy.AdminApi(client) - username = "{{ cookiecutter.git_user }}" + api_instance = giteapy.UserApi(client) repo = giteapy.CreateRepoOption( name="{{ cookiecutter.project_slug }}", private=True ) - api_instance.admin_create_repo(username, repo) + api_instance.create_current_user_repo(repo) subprocess.call(["git", "remote", "add", "origin", "{{ cookiecutter.git_origin }}"]) subprocess.call(["git", "push", "-u", "origin", "main"]) + +if {{cookiecutter.generate_gitea_project}} and {{cookiecutter.configure_ci}}: + import http.client + + # import json + + api_instance = giteapy.RepositoryApi(client) + options = giteapy.AddCollaboratorOption("read") + api_instance.repo_add_collaborator( + "{{ cookiecutter.git_user }}", + "{{ cookiecutter.project_slug }}", + "{{ cookiecutter.woodpecker_gitea_user }}", + options, + ) + + API_KEY = get_secret("Woodpecker Token") + WOODPECKER_SERVER = "{{ cookiecutter.woodpecker_server }}".removeprefix("https://") + origin = "cookiecutter.git_origin" + repo = "/".join(origin.removesuffix(".git").split("/")[-2:]) + connection = http.client.HTTPSConnection(WOODPECKER_SERVER) + connection.request( + "POST", + f"/api/repos/{repo}", + headers={ + "Authorization": f"Bearer {API_KEY}", + "referer": f"https://{WOODPECKER_SERVER}/repo/add", + }, + ) + response = connection.getresponse() + status = response.status + # body = json.load(response) + if status != 200: + print(f"Invalid response: {status}") diff --git a/{{ cookiecutter.project_slug }}/.woodpecker.yml b/{{ cookiecutter.project_slug }}/.woodpecker.yml new file mode 100644 index 0000000..300eafc --- /dev/null +++ b/{{ cookiecutter.project_slug }}/.woodpecker.yml @@ -0,0 +1,5 @@ +pipeline: + a-test-step: + image: debian + commands: + - echo "Testing.." From d18ac0baa689d02bfba1ae884f881788640b0788 Mon Sep 17 00:00:00 2001 From: Histausse Date: Fri, 19 May 2023 18:21:14 +0200 Subject: [PATCH 14/24] fix hook --- hooks/post_gen_project.py | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index cd6c85d..745f65c 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -44,10 +44,8 @@ if {{cookiecutter.generate_gitea_project}}: repo = giteapy.CreateRepoOption( name="{{ cookiecutter.project_slug }}", private=True ) - api_instance.create_current_user_repo(repo) + api_instance.create_current_user_repo(body=repo) - subprocess.call(["git", "remote", "add", "origin", "{{ cookiecutter.git_origin }}"]) - subprocess.call(["git", "push", "-u", "origin", "main"]) if {{cookiecutter.generate_gitea_project}} and {{cookiecutter.configure_ci}}: import http.client @@ -60,14 +58,28 @@ if {{cookiecutter.generate_gitea_project}} and {{cookiecutter.configure_ci}}: "{{ cookiecutter.git_user }}", "{{ cookiecutter.project_slug }}", "{{ cookiecutter.woodpecker_gitea_user }}", - options, + body=options, ) API_KEY = get_secret("Woodpecker Token") WOODPECKER_SERVER = "{{ cookiecutter.woodpecker_server }}".removeprefix("https://") - origin = "cookiecutter.git_origin" - repo = "/".join(origin.removesuffix(".git").split("/")[-2:]) + origin = "{{ cookiecutter.git_origin }}" + repo = "/".join(origin.removesuffix(".git").split(":")[-1].split("/")[-2:]) connection = http.client.HTTPSConnection(WOODPECKER_SERVER) + connection.request( + "GET", + "/api/user/repos?all=true&flush=true", + headers={"Authorization": f"Bearer {API_KEY}"}, + ) + response = connection.getresponse() + status = response.status + response.read() + if status != 200: + print( + f"\033[38;2;255;0;0mInvalid response from woodpecker while loading repos: {status} ({response.reason})\033[0m" + ) + exit(1) + connection.request( "POST", f"/api/repos/{repo}", @@ -78,6 +90,12 @@ if {{cookiecutter.generate_gitea_project}} and {{cookiecutter.configure_ci}}: ) response = connection.getresponse() status = response.status - # body = json.load(response) if status != 200: - print(f"Invalid response: {status}") + print( + f"\033[38;2;255;0;0mInvalid response from woodpecker while linking repo: {status} ({response.reason})\033[0m" + ) + exit(1) + +if {{cookiecutter.generate_gitea_project}}: + subprocess.call(["git", "remote", "add", "origin", "{{ cookiecutter.git_origin }}"]) + subprocess.call(["git", "push", "-u", "origin", "main"]) From 6aa251e9ecc13cdbe4d41a11a431b8ae980dfff6 Mon Sep 17 00:00:00 2001 From: Histausse Date: Fri, 19 May 2023 18:32:16 +0200 Subject: [PATCH 15/24] add badge --- cookiecutter.json | 4 ++-- {{ cookiecutter.project_slug }}/README.md | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cookiecutter.json b/cookiecutter.json index 34664c8..7441fc8 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -5,12 +5,12 @@ "email": "", "git_user": "", "project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_').replace('-', '_') }}", - "gitea_url": "", + "gitea_url": "https://git.pains-perdus.fr", "project_url": "{{ cookiecutter.gitea_url }}/{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}", "generate_gitea_project": [ true, false ], "configure_ci": [ true, false ], "woodpecker_gitea_user": "ci", - "woodpecker_server": "ci.pains-perdus.fr", + "woodpecker_server": "https://ci.pains-perdus.fr", "git_origin": "{{ cookiecutter.gitea_url.replace('https://', 'gitea@').replace('http://', 'gitea') }}:{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}.git", "version": "0.1.0", "open_source_license": ["AGPL-3.0-only", "GPL-3.0-only", "MIT", "BSD-3-Clause", "ISC", "Apache-2.0", "Proprietary"], diff --git a/{{ cookiecutter.project_slug }}/README.md b/{{ cookiecutter.project_slug }}/README.md index 7a4eaf5..1d18504 100644 --- a/{{ cookiecutter.project_slug }}/README.md +++ b/{{ cookiecutter.project_slug }}/README.md @@ -1,5 +1,8 @@ {% set is_open_source = cookiecutter.open_source_license != 'Proprietary' -%} +{% set repo = "/".join(cookiecutter.git_origin.removesuffix(".git").split(":")[-1].split("/")[-2:]) %} # {{ cookiecutter.project_name }} +{% if cookiecutter.configure_ci %}[![CI status badge]({{ cookiecutter.woodpecker_server }}/api/badges/{{ repo }}/status.svg)](https://ci.pains-perdus.fr/histausse/test_ci_template){% endif %} + {{ cookiecutter.project_short_description }} From fc90b3fb71dbe7ffe44f049e32c8f530fc00144f Mon Sep 17 00:00:00 2001 From: Histausse Date: Fri, 19 May 2023 19:35:18 +0200 Subject: [PATCH 16/24] Add CI config --- TODO.md | 1 - hooks/post_gen_project.py | 13 +++++++++++++ {{ cookiecutter.project_slug }}/.woodpecker.yml | 15 ++++++++++++--- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/TODO.md b/TODO.md index a3b6fe0..924f353 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,4 @@ # TODO: -- add CI - add flake - use bool value for `generate_gitea_project` when the feature is available diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 745f65c..dfa5100 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -1,4 +1,17 @@ import subprocess +import os + +REMOVE_PATHS = [ + {% if cookiecutter.open_source_license == "Proprietary" %} "LICENSE", {% endif %} + {% if cookiecutter.configure_ci == "False" %} ".woodpecker.yml", {% endif %} +] + +for path in REMOVE_PATHS: + if path and os.path.exists(path): + if os.path.isdir(path): + os.rmdir(path) + else: + os.unlink(path) subprocess.call(["git", "init"]) subprocess.call(["git", "checkout", "-b", "main"]) diff --git a/{{ cookiecutter.project_slug }}/.woodpecker.yml b/{{ cookiecutter.project_slug }}/.woodpecker.yml index 300eafc..8fe54b3 100644 --- a/{{ cookiecutter.project_slug }}/.woodpecker.yml +++ b/{{ cookiecutter.project_slug }}/.woodpecker.yml @@ -1,5 +1,14 @@ pipeline: - a-test-step: - image: debian + test: + image: python:${PYTHON_VERSION} + pull: true + environment: + - POETRY_VIRTUALENVS_IN_PROJECT=true commands: - - echo "Testing.." + - pip install poetry + - poetry install + - poetry run pytest + +matrix: + PYTHON_VERSION: + - {{ cookiecutter. python_min_version}} From d23ae91b74c30e90d44c0c53b297af5a40909f63 Mon Sep 17 00:00:00 2001 From: Histausse Date: Sat, 20 May 2023 23:11:08 +0200 Subject: [PATCH 17/24] add flake support --- TODO.md | 2 +- .../.woodpecker.yml | 12 +++++++ {{ cookiecutter.project_slug }}/README.md | 25 ++++++++++++- {{ cookiecutter.project_slug }}/flake.nix | 36 +++++++++++++++++++ 4 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 {{ cookiecutter.project_slug }}/flake.nix diff --git a/TODO.md b/TODO.md index 924f353..038ff67 100644 --- a/TODO.md +++ b/TODO.md @@ -1,4 +1,4 @@ # TODO: -- add flake +- publish to gitea repo: [container](https://docs.gitea.io/en-us/usage/packages/container/) [badge](https://docs.gitea.io/en-us/usage/packages/generic/) - use bool value for `generate_gitea_project` when the feature is available diff --git a/{{ cookiecutter.project_slug }}/.woodpecker.yml b/{{ cookiecutter.project_slug }}/.woodpecker.yml index 8fe54b3..d00a7e9 100644 --- a/{{ cookiecutter.project_slug }}/.woodpecker.yml +++ b/{{ cookiecutter.project_slug }}/.woodpecker.yml @@ -1,5 +1,6 @@ pipeline: test: + group: test image: python:${PYTHON_VERSION} pull: true environment: @@ -9,6 +10,17 @@ pipeline: - poetry install - poetry run pytest + nix: + group: test + image: nixos/nix:latest + pull: true + commands: + - nix build --experimental-features 'nix-command flakes' + - nix build --experimental-features 'nix-command flakes' .#docker + when: + matrix: + PYTHON_VERSION: {{ cookiecutter. python_min_version}} # Still not sure about how to make flake for different python version + matrix: PYTHON_VERSION: - {{ cookiecutter. python_min_version}} diff --git a/{{ cookiecutter.project_slug }}/README.md b/{{ cookiecutter.project_slug }}/README.md index 1d18504..91f75a7 100644 --- a/{{ cookiecutter.project_slug }}/README.md +++ b/{{ cookiecutter.project_slug }}/README.md @@ -1,19 +1,42 @@ {% set is_open_source = cookiecutter.open_source_license != 'Proprietary' -%} {% set repo = "/".join(cookiecutter.git_origin.removesuffix(".git").split(":")[-1].split("/")[-2:]) %} # {{ cookiecutter.project_name }} -{% if cookiecutter.configure_ci %}[![CI status badge]({{ cookiecutter.woodpecker_server }}/api/badges/{{ repo }}/status.svg)](https://ci.pains-perdus.fr/histausse/test_ci_template){% endif %} +{% if cookiecutter.configure_ci == "True" %}[![CI status badge]({{ cookiecutter.woodpecker_server }}/api/badges/{{ repo }}/status.svg)](https://ci.pains-perdus.fr/histausse/test_ci_template){% endif %} {{ cookiecutter.project_short_description }} ## Install + +### With pip + This project can be installed using pip: ``` pip install git+{{ cookiecutter.project_url }}.git ``` +### With Nix + +There is a `flake.nix`, so you can clone the repo and use `nix shell` if you want. + +### Docker/Podman + +You can build a container image using nix. To build the image, in the repo, run: + +``` +nix build -o {{ cookiecutter.project_slug }}.img .#docker +``` + +You can then load the image with: + +``` +podman load < {{ cookiecutter.project_slug }}.img +``` + +(If you want to use the image, notice it uses nix and is very minimal). + {% if is_open_source %} ## License diff --git a/{{ cookiecutter.project_slug }}/flake.nix b/{{ cookiecutter.project_slug }}/flake.nix new file mode 100644 index 0000000..fbaaabc --- /dev/null +++ b/{{ cookiecutter.project_slug }}/flake.nix @@ -0,0 +1,36 @@ +{ + description = "{{ cookiecutter.project_short_description }}"; + + inputs.flake-utils.url = "github:numtide/flake-utils"; + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + inputs.poetry2nix = { + url = "github:nix-community/poetry2nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = { self, nixpkgs, flake-utils, poetry2nix }: + flake-utils.lib.eachDefaultSystem (system: + let + inherit (poetry2nix.legacyPackages.${system}) mkPoetryApplication; + pkgs = nixpkgs.legacyPackages.${system}; + in + { + packages = { + {{ cookiecutter.project_slug }} = mkPoetryApplication { projectDir = self; }; + docker = pkgs.dockerTools.buildImage { + name = "{{ cookiecutter.project_slug }}"; + tag = "latest"; + copyToRoot = pkgs.buildEnv { + name = "{{ cookiecutter.project_slug }}_root_img"; + paths = [ self.packages.${system}.{{ cookiecutter.project_slug }} ]; + pathsToLink = [ "/bin" ]; + }; + }; + default = self.packages.${system}.{{ cookiecutter.project_slug }}; + }; + + devShells.default = pkgs.mkShell { + packages = [ poetry2nix.packages.${system}.poetry ]; + }; + }); +} From 3271450011977060f8e9c463c177476e677e1f92 Mon Sep 17 00:00:00 2001 From: Histausse Date: Sun, 21 May 2023 01:12:35 +0200 Subject: [PATCH 18/24] add some research --- TODO.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/TODO.md b/TODO.md index 038ff67..4924d6c 100644 --- a/TODO.md +++ b/TODO.md @@ -2,3 +2,17 @@ - publish to gitea repo: [container](https://docs.gitea.io/en-us/usage/packages/container/) [badge](https://docs.gitea.io/en-us/usage/packages/generic/) - use bool value for `generate_gitea_project` when the feature is available + +### Package + +``` +curl -i --upload-file README.md --user "histausse:`secret-tool lookup Title 'Gitea Token'`" https://git.pains-perdus.fr/api/packages/histausse/generic/test_flake_poetry2nix/latest/README.md +curl https://git.pains-perdus.fr/api/packages/histausse/generic/test_flake_poetry2nix/latest/README.md +curl -i -X DELETE --user "histausse:`secret-tool lookup Title 'Gitea Token'`" https://git.pains-perdus.fr/api/packages/histausse/generic/test_flake_poetry2nix/latest/pyproject.toml +``` + +``` +podman login -u histausse -p `secret-tool lookup Title 'Gitea Token'` git.pains-perdus.fr +podman push test_flake_poetry2nix:latest git.pains-perdus.fr/histausse/test_flake_poetry2nix:latest + +``` From 09c4d9537680e31c60262f8a1452dbc6a1d84d37 Mon Sep 17 00:00:00 2001 From: Histausse Date: Sun, 21 May 2023 16:48:51 +0200 Subject: [PATCH 19/24] add some reserche --- TODO.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/TODO.md b/TODO.md index 4924d6c..50a3468 100644 --- a/TODO.md +++ b/TODO.md @@ -16,3 +16,30 @@ podman login -u histausse -p `secret-tool lookup Title 'Gitea Token'` git.pains podman push test_flake_poetry2nix:latest git.pains-perdus.fr/histausse/test_flake_poetry2nix:latest ``` + +Put secret in CI: + +``` + connection.request( + "POST", + f"/api/repos/{repo}/secrets", + json.dumps( + { + "name": "test_token", + "value": "loren ispum", + "image": ["test"], + "event": ["push", "tag"], + } + ), + { + "Authorization": f"Bearer {API_KEY}", + "content-type": "application/json", + }, + ) +``` + + +Gen badge: +``` +https://github.com/smarie/python-genbadge/issues +``` From 721d134c6ac2cc509b97786526cd814af971cec5 Mon Sep 17 00:00:00 2001 From: Histausse Date: Tue, 23 May 2023 12:38:31 +0200 Subject: [PATCH 20/24] generate new gitea token for the CI --- hooks/post_gen_project.py | 59 +++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index dfa5100..e48d01e 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -1,4 +1,6 @@ import subprocess +import http.client +import json import os REMOVE_PATHS = [ @@ -41,6 +43,33 @@ def get_secret(secret_name: str): "please enter you gitea api token:" ) +def get_new_gitea_token( + connection: http.client.HTTPSConnection, new_token_name: str, user: str, token: str +) -> str: + auth = b64encode(f"{user}:{token}".encode("utf-8")).decode("ascii") + connection.request( + "POST", + f"/api/v1/users/{user}/tokens", + json.dumps( + { + "name": new_token_name, + } + ), + { + "Authorization": f"Basic {auth}", + "content-type": "application/json", + }, + ) + response = connection.getresponse() + status = response.status + if status != 201: + print( + f"\033[38;2;255;0;0mInvalid response from gitea while creating a new token: {status} ({response.reason})\033[0m" + ) + exit(1) + data = json.load(response) + return data["sha1"] + if {{cookiecutter.generate_gitea_project}}: try: @@ -48,9 +77,9 @@ if {{cookiecutter.generate_gitea_project}}: except ModuleNotFoundError: print("module `giteapy` is not availabled, repository not created") exit() - API_KEY = get_secret("Gitea Token") + GITEA_API_KEY = get_secret("Gitea Token") configuration = giteapy.Configuration() - configuration.api_key["access_token"] = API_KEY + configuration.api_key["access_token"] = GITEA_API_KEY client = giteapy.ApiClient(configuration) client.configuration.host = "{{ cookiecutter.gitea_url }}/api/v1" api_instance = giteapy.UserApi(client) @@ -61,10 +90,6 @@ if {{cookiecutter.generate_gitea_project}}: if {{cookiecutter.generate_gitea_project}} and {{cookiecutter.configure_ci}}: - import http.client - - # import json - api_instance = giteapy.RepositoryApi(client) options = giteapy.AddCollaboratorOption("read") api_instance.repo_add_collaborator( @@ -73,7 +98,8 @@ if {{cookiecutter.generate_gitea_project}} and {{cookiecutter.configure_ci}}: "{{ cookiecutter.woodpecker_gitea_user }}", body=options, ) - + connection_gitea = http.client.HTTPSConnection("git.pains-perdus.fr") + GITEA_API_KEY = get_new_gitea_token(connection_gitea, "CI {{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}", "{{ cookiecutter.git_user }}", GITEA_API_KEY) API_KEY = get_secret("Woodpecker Token") WOODPECKER_SERVER = "{{ cookiecutter.woodpecker_server }}".removeprefix("https://") origin = "{{ cookiecutter.git_origin }}" @@ -111,4 +137,21 @@ if {{cookiecutter.generate_gitea_project}} and {{cookiecutter.configure_ci}}: if {{cookiecutter.generate_gitea_project}}: subprocess.call(["git", "remote", "add", "origin", "{{ cookiecutter.git_origin }}"]) - subprocess.call(["git", "push", "-u", "origin", "main"]) + subpr def get_new_gitea_token(): + """""" + connection.request( + "POST", + f"/api/repos/{repo}/secrets", + json.dumps( + { + "name": "test_token", + "value": "loren ispum", + "image": ["test"], + "event": ["push", "tag"], + } + ), + { + "Authorization": f"Bearer {API_KEY}", + "content-type": "application/json", + }, + )ocess.call(["git", "push", "-u", "origin", "main"]) From d6e0d933d8c181b08599db3264446a7458fdca43 Mon Sep 17 00:00:00 2001 From: Histausse Date: Tue, 23 May 2023 12:57:07 +0200 Subject: [PATCH 21/24] push token to woodpecker --- hooks/post_gen_project.py | 72 +++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 21 deletions(-) diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index e48d01e..d5a995d 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -2,6 +2,7 @@ import subprocess import http.client import json import os +from base64 import b64encode REMOVE_PATHS = [ {% if cookiecutter.open_source_license == "Proprietary" %} "LICENSE", {% endif %} @@ -66,10 +67,46 @@ def get_new_gitea_token( print( f"\033[38;2;255;0;0mInvalid response from gitea while creating a new token: {status} ({response.reason})\033[0m" ) + print(response.read()) exit(1) data = json.load(response) return data["sha1"] +def push_woodpecker_secret( + connection: http.client.HTTPSConnection, + repo: str, + secret_name: str, + secret: str, + woodpecker_token: str, + images: list[str] | None = None +): + if images is None: images = [] + connection.request( + "POST", + f"/api/repos/{repo}/secrets", + json.dumps( + { + "name": secret_name, + "value": secret, + "image": images, + "event": ["push", "tag"], + } + ), + { + "Authorization": f"Bearer {woodpecker_token}", + "content-type": "application/json", + }, + ) + response = connection.getresponse() + status = response.status + if status != 200: + print( + f"\033[38;2;255;0;0mInvalid response from woodpecker when sending a new secret: {status} ({response.reason})\033[0m" + ) + print(response.read()) + exit(1) + response.read() + if {{cookiecutter.generate_gitea_project}}: try: @@ -100,15 +137,16 @@ if {{cookiecutter.generate_gitea_project}} and {{cookiecutter.configure_ci}}: ) connection_gitea = http.client.HTTPSConnection("git.pains-perdus.fr") GITEA_API_KEY = get_new_gitea_token(connection_gitea, "CI {{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}", "{{ cookiecutter.git_user }}", GITEA_API_KEY) - API_KEY = get_secret("Woodpecker Token") + WOODPECKER_API_KEY = get_secret("Woodpecker Token") WOODPECKER_SERVER = "{{ cookiecutter.woodpecker_server }}".removeprefix("https://") origin = "{{ cookiecutter.git_origin }}" repo = "/".join(origin.removesuffix(".git").split(":")[-1].split("/")[-2:]) + connection = http.client.HTTPSConnection(WOODPECKER_SERVER) connection.request( "GET", "/api/user/repos?all=true&flush=true", - headers={"Authorization": f"Bearer {API_KEY}"}, + headers={"Authorization": f"Bearer {WOODPECKER_API_KEY}"}, ) response = connection.getresponse() status = response.status @@ -123,7 +161,7 @@ if {{cookiecutter.generate_gitea_project}} and {{cookiecutter.configure_ci}}: "POST", f"/api/repos/{repo}", headers={ - "Authorization": f"Bearer {API_KEY}", + "Authorization": f"Bearer {WOODPECKER_API_KEY}", "referer": f"https://{WOODPECKER_SERVER}/repo/add", }, ) @@ -133,25 +171,17 @@ if {{cookiecutter.generate_gitea_project}} and {{cookiecutter.configure_ci}}: print( f"\033[38;2;255;0;0mInvalid response from woodpecker while linking repo: {status} ({response.reason})\033[0m" ) + print(response.read()) exit(1) + response.read() + push_woodpecker_secret( + connection, + repo, + "gitea_token", + GITEA_API_KEY, + WOODPECKER_API_KEY + ) if {{cookiecutter.generate_gitea_project}}: subprocess.call(["git", "remote", "add", "origin", "{{ cookiecutter.git_origin }}"]) - subpr def get_new_gitea_token(): - """""" - connection.request( - "POST", - f"/api/repos/{repo}/secrets", - json.dumps( - { - "name": "test_token", - "value": "loren ispum", - "image": ["test"], - "event": ["push", "tag"], - } - ), - { - "Authorization": f"Bearer {API_KEY}", - "content-type": "application/json", - }, - )ocess.call(["git", "push", "-u", "origin", "main"]) + subprocess.call(["git", "push", "-u", "origin", "main"]) From 48c95b975ac80e3792b3c477148b5f5e1323f556 Mon Sep 17 00:00:00 2001 From: Histausse Date: Wed, 24 May 2023 12:33:11 +0200 Subject: [PATCH 22/24] push docker with CI --- hooks/post_gen_project.py | 1 + .../.woodpecker.yml | 19 ++++++++++++++++--- {{ cookiecutter.project_slug }}/README.md | 10 +++++++++- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index d5a995d..c2e94cf 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -16,6 +16,7 @@ for path in REMOVE_PATHS: else: os.unlink(path) +subprocess.call(["poetry", "lock"]) subprocess.call(["git", "init"]) subprocess.call(["git", "checkout", "-b", "main"]) subprocess.call(["git", "add", "*"]) diff --git a/{{ cookiecutter.project_slug }}/.woodpecker.yml b/{{ cookiecutter.project_slug }}/.woodpecker.yml index d00a7e9..5cafcce 100644 --- a/{{ cookiecutter.project_slug }}/.woodpecker.yml +++ b/{{ cookiecutter.project_slug }}/.woodpecker.yml @@ -16,11 +16,24 @@ pipeline: pull: true commands: - nix build --experimental-features 'nix-command flakes' - - nix build --experimental-features 'nix-command flakes' .#docker + - nix build -o image_link --experimental-features 'nix-command flakes' .#docker + - cp image_link image when: matrix: - PYTHON_VERSION: {{ cookiecutter. python_min_version}} # Still not sure about how to make flake for different python version + PYTHON_VERSION: {{ cookiecutter.python_min_version}} # Still not sure about how to make flake for different python version + + push_image: + image: quay.io/podman/stable:latest + pull: true + commands: + - podman login -u {{ cookiecutter.git_user }} -p $GITEA_TOKEN {{ cookiecutter.gitea_url.removeprefix('https://') }} + - podman load < image + - podman push {{ cookiecutter.project_slug }}:latest {{ cookiecutter.gitea_url.removeprefix('https://') }}/{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}:latest + secrets: [ gitea_token ] + when: + matrix: + PYTHON_VERSION: {{ cookiecutter.python_min_version}} # Still not sure about how to make flake for different python version matrix: PYTHON_VERSION: - - {{ cookiecutter. python_min_version}} + - {{ cookiecutter.python_min_version}} diff --git a/{{ cookiecutter.project_slug }}/README.md b/{{ cookiecutter.project_slug }}/README.md index 91f75a7..f447e57 100644 --- a/{{ cookiecutter.project_slug }}/README.md +++ b/{{ cookiecutter.project_slug }}/README.md @@ -23,6 +23,13 @@ There is a `flake.nix`, so you can clone the repo and use `nix shell` if you wan ### Docker/Podman +{% if cookiecutter.configure_ci == "True" %} +You can run this projet with docker or podman: + +``` +podman run --rm -it {{ cookiecutter.gitea_url.removeprefix('https://') }}/{{ cookiecutter.git_user }}/{{ cookiecutter.project_slug }}:latest {{ cookiecutter.project_slug }} +``` +{% else %} You can build a container image using nix. To build the image, in the repo, run: ``` @@ -34,8 +41,9 @@ You can then load the image with: ``` podman load < {{ cookiecutter.project_slug }}.img ``` +{% endif %} -(If you want to use the image, notice it uses nix and is very minimal). +Notice the image is build with nix and is very minimalist. {% if is_open_source %} ## License From 99cf060e08adee83b3d98f08d68c3b94ee4f8529 Mon Sep 17 00:00:00 2001 From: Histausse Date: Sat, 27 May 2023 18:20:07 +0200 Subject: [PATCH 23/24] fix badge url --- {{ cookiecutter.project_slug }}/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.project_slug }}/README.md b/{{ cookiecutter.project_slug }}/README.md index f447e57..b1419ec 100644 --- a/{{ cookiecutter.project_slug }}/README.md +++ b/{{ cookiecutter.project_slug }}/README.md @@ -1,7 +1,7 @@ {% set is_open_source = cookiecutter.open_source_license != 'Proprietary' -%} {% set repo = "/".join(cookiecutter.git_origin.removesuffix(".git").split(":")[-1].split("/")[-2:]) %} # {{ cookiecutter.project_name }} -{% if cookiecutter.configure_ci == "True" %}[![CI status badge]({{ cookiecutter.woodpecker_server }}/api/badges/{{ repo }}/status.svg)](https://ci.pains-perdus.fr/histausse/test_ci_template){% endif %} +{% if cookiecutter.configure_ci == "True" %}[![CI status badge]({{ cookiecutter.woodpecker_server }}/api/badges/{{ repo }}/status.svg)](https://ci.pains-perdus.fr/{{ repo }}){% endif %} {{ cookiecutter.project_short_description }} From ad7b9ec60223c7a06e7868f40077587b9a0656a5 Mon Sep 17 00:00:00 2001 From: Histausse Date: Mon, 19 Jun 2023 12:32:26 +0200 Subject: [PATCH 24/24] config git before first commit --- hooks/post_gen_project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index c2e94cf..9aae08c 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -20,9 +20,9 @@ subprocess.call(["poetry", "lock"]) subprocess.call(["git", "init"]) subprocess.call(["git", "checkout", "-b", "main"]) subprocess.call(["git", "add", "*"]) -subprocess.call(["git", "commit", "-m", "Initial commit"]) subprocess.call(["git", "config", "user.name", "{{ cookiecutter.git_user }}"]) subprocess.call(["git", "config", "user.email", "{{ cookiecutter.email }}"]) +subprocess.call(["git", "commit", "-m", "Initial commit"]) # subprocess.call(["python", "-m", "venv", "venv"])