Skip to content

Publish pip wheel into pypi on master merge #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions .github/workflows/push-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ concurrency: ${{ github.workflow }}-${{ github.ref }}

env:
PACKAGE: luxos
GITHUB_DUMP: ${{ toJson(github) }}

jobs:
build:
Expand Down Expand Up @@ -68,14 +69,24 @@ jobs:
--junitxml=$OUTDIR/junit/junit.xml --html=$OUTDIR/junit/junit.html --self-contained-html \
tests

- name: Dump env
shell: bash
run: |
echo "github env:"
echo "$GITHUB_DUMP"

- name: Build wheel packages
if: ${{ ! contains(matrix.os, 'windows') }}
env:
GITHUB_DUMP: ${{ toJson(github) }}
run: |
python -m build
python make.pyz beta-release -v
touch .keepme

- name: "Publish beta package to pypi"
uses: pypa/gh-action-pypi-publish@release/v1
if: ${{ matrix.python-version == env.XTARGET }}
with:
password: ${{ secrets.PYPI_API_TOKEN }}

- name: Archive artifacts
uses: actions/upload-artifact@v4
with:
Expand Down
11 changes: 9 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
# LUXOS CHANGELOG
# LUXOS TOOLING CHANGELOG

- [LUXOS TOOLING CHANGELOG](#luxos-tooling-changelog)
- [\[Unreleased\]](#unreleased)

All notable changes to this project will be documented in this file.
<!--
All notable changes to this project will be documented in this file.
Please, use the format:

## [Unreleased]

- <module>: short description

-->

## [Unreleased]

- beta-builder: automatically publish beta packages into pypi from main branch
Binary file modified health-checker.pyz
Binary file not shown.
Binary file modified luxos.pyz
Binary file not shown.
177 changes: 108 additions & 69 deletions make.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,64 +2,42 @@
"""A make-like script"""
import argparse
import contextlib
import hashlib
import json
import os
import shutil
import sys
import logging
import functools
import subprocess
import zipfile
from pathlib import Path

# curl -LO https://github.com/cav71/hatch-ci/raw/beta/0.1.4/make.pyz
from make import fileos, misc, task, text # type: ignore

log = logging.getLogger(__name__)

def task(name=None):
"""task decorator

This decorator will run the decorated function so:
1. change the current directory to this script
directory
2. call the decorated task
3. return to the (eventual) starting dir

The wrapped function can have few `magic` arguments:
- args : this is the sys.argv[2:] list
- parser : this will be a argparse.ArgumentParser ready
- workdir : in case you dont want to auto cd into workdir
"""
def _task1(fn):
@functools.wraps(fn)
def _task(workdir, args):
from inspect import signature
cwd = Path.cwd()
try:
kwargs = {}
if "args" in signature(fn).parameters:
kwargs["args"] = args
if "parser" in signature(fn).parameters:
class F(argparse.ArgumentDefaultsHelpFormatter):
pass
kwargs["parser"] = argparse.ArgumentParser(
formatter_class=F, description=_task.description)
if "workdir" in signature(fn).parameters:
kwargs["workdir"] = workdir
else:
os.chdir(workdir)
return fn(**kwargs)
finally:
os.chdir(cwd)

_task.task = name or fn.__name__
_task.description = (
fn.__doc__.strip().partition("\n")[0] if fn.__doc__ else "no help available"
)
return _task

return _task1
@task()
def hello(argv):
"""this is the hello world"""
print( # noqa: T201
f"""
Hi!
python: {sys.executable}
version: {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}
cwd: {Path.cwd()}
argv: {argv}
"""
)


@task(name=None)
def onepack(parser, args, workdir):
def onepack(parser, argv):
"""create a one .pyz single file package"""
from zipapp import create_archive
from configparser import ConfigParser, ParsingError
workdir = Path.cwd()

config = ConfigParser(strict=False)
with contextlib.suppress(ParsingError):
Expand All @@ -73,22 +51,55 @@ def onepack(parser, args, workdir):

parser.add_argument("-o", "--output-dir",
default=workdir, type=Path)
o = parser.parse_args(args)
o = parser.parse_args(argv)

def extract(path: Path) -> dict[str, list[str | None, str | None]]:
result = {}
if not path.exists():
return result
zfp = zipfile.ZipFile(path)
for item in zfp.infolist():
with zfp.open(item) as fp:
data = fp.read()
result[item.filename] = [hashlib.sha256(data).hexdigest(), None]
return result

for target, entrypoint in targets:
dst = o.output_dir / target
create_archive(
workdir / "src",
dst,
main=entrypoint,
compressed=True
)

# cleanup cache dirs
for xx in (workdir / "src").rglob("__pycache__"):
shutil.rmtree(xx, ignore_errors=True)

# get the relatove path (nicer for display)
relpath = (
dst.relative_to(Path.cwd())
if dst.is_relative_to(Path.cwd())
else dst
)
print(f"Written: {relpath}", file=sys.stderr)

generate = True
if dst.exists():
dst1 = dst.parent / f"{dst.name}.bak"
create_archive(
workdir / "src",
dst1,
main=entrypoint,
compressed=True
)
generate = (extract(dst) != extract(dst1))
dst1.unlink()
if generate:
create_archive(
workdir / "src",
dst,
main=entrypoint,
compressed=True
)

print(f"Written: {relpath}", file=sys.stderr)
else:
print(f"Skipping generation: {relpath}", file=sys.stderr)


@task()
Expand All @@ -99,29 +110,57 @@ def checks():

@task()
def tests():
"""runs all tests (excluding the manual ones)"""
workdir = Path.cwd()
subprocess.check_call(
["pytest", "-vvs", str(workdir / "tests") ]
)


if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
tasks = [ item for item in list(locals().values()) if getattr(item, "task", None)]
@task(name="beta-build")
def beta_build(parser, argv):
"""create beta packages for luxos (only works in github)"""

if len(sys.argv) < 2 or sys.argv[1] not in [t.task for t in tasks]:
txt = "\n".join(f" {task.task} - {task.description}" for task in tasks)
print( # noqa: T201
f"""\
make.py <command> {{arguments}}
parser.add_argument("-n", "--dry-run", dest="dryrun", action="store_true")
options = parser.parse_args(argv)

Commands:
{txt}
""",
file=sys.stderr,
)
sys.exit()
github_dump = os.getenv("GITHUB_DUMP")
if not github_dump:
raise RuntimeError("missing GITHUB_DUMP variable")
gdata = (
json.loads(Path(github_dump[1:]).read_text())
if github_dump.startswith("@")
else json.loads(github_dump)
)
misc.validate_gdata(
gdata, ["run_number", "sha", "ref_name", "ref_type", "workflow_ref"]
)

workdir = Path(__file__).parent
function = [t for t in tasks if sys.argv[1] == t.task][0]
function(workdir, args=sys.argv[2:])
with contextlib.ExitStack() as stack:
save = stack.enter_context(fileos.backups())

# pyproject.toml
pyproject = save("pyproject.toml")
lineno, current, quote = misc.get_variable_def(pyproject, "version")
log.debug("found at LN:%i: version = '%s'", lineno, current)
version = f"{current}b{gdata['run_number']}"

log.info("creating for version %s [%s]", version, gdata["sha"])
misc.set_variable_def(pyproject, "version", lineno, version, quote)

# __init__.py
initfile = save("src/luxos/__init__.py")
lineno, old, quote = misc.get_variable_def(initfile, "__version__")
log.debug("found at LN:%i: __version__ = '%s'", lineno, old)
if old != "" and old != current:
raise RuntimeError(f"found in {initfile} __version__ {old} != {current}")
misc.set_variable_def(pyproject, "__version__", lineno, version, quote)

lineno, old, quote = misc.get_variable_def(initfile, "__hash__")
log.debug("found at LN:%i: __hash__ = '%s'", lineno, old)
if old != "" and old != gdata["sha"]:
raise RuntimeError(f"found in {initfile} __hash__ {old} != {gdata['sha']}")
misc.set_variable_def(pyproject, "__hash__", lineno, gdata["sha"], quote)

if not options.dryrun:
subprocess.check_call([sys.executable, "-m", "build"]) # noqa: S603
2 changes: 2 additions & 0 deletions src/luxos/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
__version__ = ""
__hash__ = ""