🎉 working copier setup

This commit is contained in:
Joe Kaufeld 2023-04-07 00:07:16 -04:00
commit 428005dbed
12 changed files with 432 additions and 0 deletions

View File

@ -0,0 +1,54 @@
name: Release
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: https://github.com/actions/checkout@v2
- uses: https://github.com/actions/setup-python@v4
with:
python-version: '3.11.x'
- name: Install Env
# this should be all we need because shiv will download the deps itself
run: |
pip install --upgrade pip
pip install shiv
pip install poetry
- name: Add VERSION env property
run: |
echo "VERSION=v$(poetry version | python -c 'import sys;print(sys.stdin.read().split()[1])')" >> $GITHUB_ENV
echo ${{ env.VERSION }}
- name: Build the sucker
run: |
sed -i -e "s/?????/${{ env.VERSION }}/g" src/__init__.py
make build
- name: Create release!
run: |
JSON_DATA=$(
printf '%s' \
'{'\
'"tag_name":"${{ env.VERSION }}",'\
'"name":"${{ env.VERSION }}",'\
'"body":"RELEASE THE KRAKEN"'\
'}' \
)
echo """release_id=$(\
curl -X POST \
-s https://git.joekaufeld.com/api/v1/repos/${GITHUB_REPOSITORY%/*}/${{ github.event.repository.name }}/releases \
-H "Authorization: token ${{ secrets.PAT }}" \
-H 'Content-Type: application/json' \
-d "$JSON_DATA" \
| python3 -c "import sys, json; print(json.load(sys.stdin)['id'])"\
)""" >> $GITHUB_ENV
- name: Upload assets!
run: |
curl https://git.joekaufeld.com/api/v1/repos/${GITHUB_REPOSITORY%/*}/${{ github.event.repository.name }}/releases/${{ env.release_id }}/assets \
-H "Authorization: token ${{ secrets.PAT }}" \
-F attachment=@[[ module_name ]]

131
.gitignore.jinja Normal file
View File

@ -0,0 +1,131 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
setup.py
{{ module_name }}

10
Makefile.jinja Normal file
View File

@ -0,0 +1,10 @@
setup:
python src/poetry2setup.py > setup.py
build: setup shiv
clean:
rm setup.py
shiv:
shiv --preamble src/preamble.py -c [[ module_name ]] -o [[ module_name ]] .

16
README.md.jinja Normal file
View File

@ -0,0 +1,16 @@
# [[ project_name ]]
[[ description ]]
Use this template by installing `copier` and running:
```shell
copier https://git.joekaufeld.com/jkaufeld/copier-shiv.git [dir]
```
After that, you can set up the system with:
```shell
poetry shell
poetry install
make build
```

View File

34
copier.yml Normal file
View File

@ -0,0 +1,34 @@
# questions
project_name:
type: str
help: What is your project name?
module_name:
type: str
help: What is your Python module name?
description:
type: str
help: Project description?
author_name:
type: str
help: What's your name?
email:
type: str
help: What's your contact email?
repo_name:
type: str
help: What's the slug of the repo name on Gitea?
_envops:
autoescape: false
block_end_string: "%]"
block_start_string: "[%"
comment_end_string: "#]"
comment_start_string: "[#"
keep_trailing_newline: true
variable_end_string: "]]"
variable_start_string: "[["

3
poetry.toml Normal file
View File

@ -0,0 +1,3 @@
[virtualenvs]
create = true
in-project = true

24
pyproject.toml.jinja Normal file
View File

@ -0,0 +1,24 @@
[tool.poetry]
name = "src"
version = "0.1.0"
description = "[[ description ]]"
authors = ["[[ author_name ]] <[[ email ]]>"]
[tool.poetry.dependencies]
python = "^3.10"
shiv = "^1.0.1"
httpx = "^0.23.0"
click = "^8.1.3"
rich = "^12.5.1"
art = "^5.9"
[tool.poetry.dev-dependencies]
poetry = "^1.1.14"
black = "^22.6.0"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.poetry.plugins."console_scripts"]
"[[ module_name ]]" = "src.cli:main"

1
src/__init__.py Normal file
View File

@ -0,0 +1 @@
__version__ = "?????" # will be replaced during build by CI

117
src/cli.py.jinja Normal file
View File

@ -0,0 +1,117 @@
import code
import io
import random
import string
import sys
import uuid
import art
import click
import httpx
from rich import console as rich_console, pretty
from rich.status import Status
from rich.traceback import install
from shiv.bootstrap import current_zipfile
import src
def print_help():
ctx = click.get_current_context()
click.echo(ctx.get_help())
ctx.exit()
class RichGroup(click.Group):
def format_usage(self, ctx, formatter):
sio = io.StringIO()
console = rich_console.Console(file=sio, force_terminal=True)
console.print("Usage: ./[[ module_name ]] [COMMAND]")
console.print(" All dependencies are contained within. Use your")
console.print(" chosen Python version to launch this file.")
formatter.write(sio.getvalue())
@click.group(
cls=RichGroup,
context_settings=dict(help_option_names=["-h", "--help", "--halp"]),
)
@click.pass_context
@click.version_option(version=src.__version__, prog_name="[[ module_name ]]")
@click.option(
"--update",
is_flag=True,
help="Check Gitea for a new version and auto-update.",
)
@click.option(
"--shell",
"shell",
is_flag=True,
default=False,
help="Launch a REPL for testing.",
)
def main(ctx, update, shell):
"""
Launch [[ project_name ]] or drop into a command line REPL.
"""
if update:
update_from_gitea()
sys.exit()
if shell:
banner = art.text2art("[[ module_name ]]")
pretty.install() # type: ignore
install() # traceback handler
code.interact(local=globals(), banner=banner)
sys.exit()
elif ctx.invoked_subcommand is None:
print_help()
@main.command()
def uuid4():
"""Generate a random UUID4."""
click.echo(uuid.uuid4())
def update_from_gitea():
"""Get the newest release from Gitea and install it."""
status = Status("Checking for new release...")
status.start()
response = httpx.get(
"https://git.joekaufeld.com/api/v1/repos/jkaufeld/[[ repo_name ]]/releases/latest"
)
if response.status_code != 200:
status.stop()
click.echo(
f"Something went wrong when talking to Gitea; got a"
f" {response.status_code} with the following content:\n"
f"{response.content}"
)
return
status.update("Checking for new release...")
release_data = response.json()
if release_data["tag_name"] == src.__version__:
status.stop()
click.echo(
"Server version is the same as current version; nothing to update."
)
return
status.update("Updating...")
url = release_data["assets"][0]["browser_download_url"]
with current_zipfile() as archive:
with open(archive.filename, "wb") as f, httpx.stream(
"GET", url, follow_redirects=True
) as r:
for line in r.iter_bytes():
f.write(line)
status.stop()
click.echo(f"Updated to {release_data['tag_name']}! 🎉")
if __name__ == "__main__":
main()

16
src/poetry2setup.py Normal file
View File

@ -0,0 +1,16 @@
from pathlib import Path
from poetry.core.factory import Factory
from poetry.core.masonry.builders.sdist import SdistBuilder
def build_setup_py():
return SdistBuilder(Factory().create_poetry(Path(".").resolve())).build_setup()
def main():
print(build_setup_py().decode("utf8"))
if __name__ == "__main__":
main()

26
src/preamble.py Normal file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env python3
# https://shiv.readthedocs.io/en/latest/#preamble
import os
import shutil
from pathlib import Path
# These variables are injected by shiv.bootstrap
site_packages: Path
env: "shiv.bootstrap.environment.Environment"
# Get a handle of the current PYZ's site_packages directory
current = site_packages.parent
# The parent directory of the site_packages directory is our shiv cache
cache_path = current.parent
name, build_id = current.name.split('_')
if __name__ == "__main__":
for path in cache_path.iterdir():
if path.name.startswith(f"{name}_") and not path.name.endswith(build_id):
shutil.rmtree(path)
if path.name.startswith(f".{name}") and not path.name.endswith(f"{build_id}_lock"):
os.remove(path)