diff --git a/.forgejo/workflows/alt.yaml b/.forgejo/workflows/alt.yaml index ef1faa4..8a11c4b 100644 --- a/.forgejo/workflows/alt.yaml +++ b/.forgejo/workflows/alt.yaml @@ -2,7 +2,6 @@ on: [push] jobs: alpine: - runs-on: ubuntu-latest container: image: ${{vars.DOCKER}}alpine:3.19 steps: @@ -17,7 +16,6 @@ jobs: - run: spcd-browse-workspace debian: - runs-on: ubuntu-latest needs: alpine if: failure() || success() container: @@ -34,7 +32,6 @@ jobs: - run: spcd-browse-workspace ubuntu: - runs-on: ubuntu-latest needs: debian if: failure() || success() container: @@ -51,7 +48,6 @@ jobs: - run: spcd-browse-workspace arch: - runs-on: ubuntu-latest needs: ubuntu if: failure() || success() container: @@ -68,7 +64,6 @@ jobs: - run: spcd-browse-workspace opensuse: - runs-on: ubuntu-latest needs: arch if: failure() || success() container: @@ -85,7 +80,6 @@ jobs: - run: spcd-browse-workspace fedora: - runs-on: ubuntu-latest needs: opensuse if: failure() || success() container: @@ -102,7 +96,6 @@ jobs: - run: spcd-browse-workspace alma: - runs-on: ubuntu-latest needs: fedora if: failure() || success() container: @@ -119,7 +112,6 @@ jobs: - run: spcd-browse-workspace rocky: - runs-on: ubuntu-latest needs: alma if: failure() || success() container: diff --git a/.forgejo/workflows/main.yaml b/.forgejo/workflows/main.yaml index 05b6e0a..45b1978 100644 --- a/.forgejo/workflows/main.yaml +++ b/.forgejo/workflows/main.yaml @@ -2,7 +2,6 @@ on: [push] jobs: alpine: - runs-on: ubuntu-latest container: image: ${{vars.DOCKER}}alpine:3.20 steps: @@ -17,7 +16,6 @@ jobs: - run: spcd-browse-workspace debian: - runs-on: ubuntu-latest needs: alpine if: failure() || success() container: @@ -37,7 +35,6 @@ jobs: - run: spcd-synchronize ubuntu: - runs-on: ubuntu-latest needs: debian if: failure() || success() container: @@ -54,7 +51,6 @@ jobs: - run: spcd-browse-workspace arch: - runs-on: ubuntu-latest needs: ubuntu if: failure() || success() container: @@ -71,7 +67,6 @@ jobs: - run: spcd-browse-workspace opensuse: - runs-on: ubuntu-latest needs: arch if: failure() || success() container: @@ -88,7 +83,6 @@ jobs: - run: spcd-browse-workspace fedora: - runs-on: ubuntu-latest needs: opensuse if: failure() || success() container: @@ -105,7 +99,6 @@ jobs: - run: spcd-browse-workspace alma: - runs-on: ubuntu-latest needs: fedora if: failure() || success() container: @@ -122,7 +115,6 @@ jobs: - run: spcd-browse-workspace rocky: - runs-on: ubuntu-latest needs: alma if: failure() || success() container: diff --git a/pyproject.toml b/pyproject.toml index 1436be7..103539a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ dependencies = ["rwx"] description = "Shell to Python Continuous Deployment" dynamic = ["version"] keywords = [] -license-files = ["license.md"] +license-files = { paths = ["license.md"] } name = "spcd" readme = "readme.md" requires-python = ">= 3.11" diff --git a/readme.md b/readme.md index 552f13d..0728687 100644 --- a/readme.md +++ b/readme.md @@ -54,10 +54,9 @@ Picture it… * [X] installing Git to clone * [X] this project * [X] its parent framework -* [X] installing Python +* [X] installing both Python * [X] system environment * [X] virtual environment - * [ ] managed version * [X] generating a Python module to switch context #### Python @@ -96,16 +95,30 @@ Handle project workflows in a unified way: * [ ] SourceHut * whatever the Operating System container -| System | Latest | Previous | -|:---------|:---------------------------|:---------------------------| -| Alma | * [X] 9 | * [X] 8 | -| Alpine | * [X] 3.20 | * [X] 3.19 | -| Arch | * [X] 20240818 (.0.255804) | * [X] 20240101 (.0.204074) | -| Debian | * [X] Bookworm (12) | * [ ] Bullseye (11) | -| Fedora | * [X] 40 | * [X] 39 | -| OpenSUSE | * [ ] 15.6 | * [ ] 15.5 | -| Rocky | * [X] 9 | * [X] 8 | -| Ubuntu | * [X] Noble (24.04) | * [ ] Jammy (22.04) | + * [X] Alma + * [X] 9 + * [X] 8 + * [X] Alpine + * [X] 3.20 + * [X] 3.19 + * [X] Arch + * [X] 20240818 (.0.255804) + * [X] 20240101 (.0.204074) + * [X] Debian + * [X] Bookworm (12) + * [ ] Bullseye (11) + * [X] Fedora + * [X] 40 + * [X] 39 + * [ ] OpenSUSE + * [ ] 15.6 + * [ ] 15.5 + * [X] Rocky + * [X] 9 + * [X] 8 + * [X] Ubuntu + * [X] Noble (24.04) + * [ ] Jammy (22.04) ### Environment variables @@ -116,7 +129,6 @@ Handle project workflows in a unified way: | SPCD_GIT_RWX | RWX Git repository | rwx | | SPCD_GIT_SHUNIT | ShUnit Git repository | shunit2 | | SPCD_GIT_SPCD | SPCD Git repository | spcd | -| SPCD_REF_ARCHIVE | Archive deployment ref | old | | SPCD_REF_FEATURE | Feature deployment ref | f | | SPCD_REF_RELEASE | Release deployment ref | main | | SPCD_REF_STAGING | Staging deployment ref | dev | @@ -138,40 +150,44 @@ Handle project workflows in a unified way: #### Latest -| os | https | up ca | python | ffmpeg | gource | graphviz | plantuml | shellcheck | shfmt | shunit | -|:----------------|---|---|------------:|-------:|-----:|------:|-----------:|------:|-----:|------:| -| Arch 20240818 | ☑ | ☑ | 3.12 | 7.0.2 | 0.54 | 12.0 | 1.2023.13 | 0.10 | 3.8 | 2.1.8 | -| Alpine 3.20 | ☑ | ☐ | 3.12 | 6.1.1 | 0.54 | 9.0 | 1.2024.4 | 0.10 | 3.8 | 2.1.8 | -| Fedora 40 | ☑ | ☑ | 3.12 → 3.13 | 6.1.2 | 0.55 | 9.0 | 1.2024.6 | 0.9 | 3.7 | 2.1.6 | -| Debian Bookworm | ☐ | ☐ | 3.11 | 5.1.6 | 0.54 | 2.42 | 1.2020.2 | 0.9 | 3.6 | 2.1.8 | -| OpenSUSE 15.6 | ☐ | ☑ | 3.6 → 3.12 | 4.4.4 | 0.54 | 2.48 | 1.2020.9 | 0.8 | 3.5 | 2.1.6 | -| Ubuntu Noble | ☐ | ☐ | 3.12 | 6.1.1 | 0.54 | u2.42 | u1.2020.2 | u0.9 | u3.8 | 2.1.8 | -| Alma / Rocky 9 | ☑ | ☑ | 3.9 → 3.12 | e5.1.4 | | 2.44 | e1.2024.6 | e0.8 | | | +| os | https | up ca | python | graphviz | plantuml | shellcheck | shunit | shfmt | gource | ffmpeg | +|:----------------|---|---|------------:|------:|-----------:|------:|------:|-----:|-----:|-------:| +| Arch 20240818 | ☑ | ☑ | 3.12 | 12.0 | 1.2023.13 | 0.10 | 2.1.8 | 3.8 | 0.54 | 7.0.2 | +| Alpine 3.20 | ☑ | ☐ | 3.12 | 9.0 | 1.2024.4 | 0.10 | 2.1.8 | 3.8 | 0.54 | 6.1.1 | +| Fedora 40 | ☑ | ☑ | 3.12 → 3.13 | 9.0 | 1.2024.6 | 0.9 | 2.1.6 | 3.7 | 0.55 | 6.1.2 | +| Debian Bookworm | ☐ | ☐ | 3.11 | 2.42 | 1.2020.2 | 0.9 | 2.1.8 | 3.6 | 0.54 | 5.1.6 | +| OpenSUSE 15.6 | ☐ | ☑ | 3.6 → 3.12 | 2.48 | 1.2020.9 | 0.8 | 2.1.6 | 3.5 | 0.54 | 4.4.4 | +| Ubuntu Noble | ☐ | ☐ | 3.12 | u2.42 | u1.2020.2 | u0.9 | 2.1.8 | u3.8 | 0.54 | 6.1.1 | +| Alma / Rocky 9 | ☑ | ☑ | 3.9 → 3.12 | 2.44 | e1.2024.6 | e0.8 | | | | e5.1.4 | #### Previous -| os | https | up ca | python | ffmpeg | gource | graphviz | plantuml | shellcheck | shfmt | shunit | -|:----------------|---|---|------------:|-------:|-----:|------:|-----------:|------:|-----:|------:| -| Alpine 3.19 | ☑ | ☐ | 3.11 | 6.1.1 | 0.54 | 9.0 | 1.2023.12 | 0.9 | 3.7 | 2.1.8 | -| Fedora 39 | ☑ | ☑ | 3.12 → 3.13 | 6.1.1 | 0.55 | 8.1 | 1.2024.6 | 0.9 | 3.5 | 2.1.6 | -| OpenSUSE 15.5 | ☐ | ☑ | 3.6 → 3.11 | 4.4.4 | 0.54 | 2.48 | 1.2020.9 | 0.8 | 3.5 | 2.1.6 | -| Alma / Rocky 8 | ☑ | ☑ | 3.6 → 3.12 | | | 2.40 | e1.2024.6 | e0.6 | | | +| os | https | up ca | python | graphviz | plantuml | shellcheck | shunit | shfmt | gource | ffmpeg | +|:----------------|---|---|------------:|------:|-----------:|------:|------:|-----:|-----:|-------:| +| Alpine 3.19 | ☑ | ☐ | 3.11 | 9.0 | 1.2023.12 | 0.9 | 2.1.8 | 3.7 | 0.54 | 6.1.1 | +| Fedora 39 | ☑ | ☑ | 3.12 → 3.13 | 8.1 | 1.2024.6 | 0.9 | 2.1.6 | 3.5 | 0.55 | 6.1.1 | +| OpenSUSE 15.5 | ☐ | ☑ | 3.6 → 3.11 | 2.48 | 1.2020.9 | 0.8 | 2.1.6 | 3.5 | 0.54 | 4.4.4 | +| Alma / Rocky 8 | ☑ | ☑ | 3.6 → 3.12 | 2.40 | e1.2024.6 | e0.6 | | | | | #### Older Python -| os | https | up ca | python | ffmpeg | gource | graphviz | plantuml | shellcheck | shfmt | shunit | -|:----------------|---|---|------------:|-------:|-----:|------:|-----------:|------:|-----:|------:| -| Ubuntu Jammy | ☐ | ☐ | 3.10 | 4.4.2 | 0.51 | u2.42 | u1.2020.2 | u0.8 | u3.4 | 2.1.6 | -| Debian Bullseye | ☐ | ☐ | 3.9 | 4.3.7 | 0.51 | 2.42 | 1.2020.2 | 0.7 | | 2.1.6 | +| os | https | up ca | python | graphviz | plantuml | shellcheck | shunit | shfmt | gource | ffmpeg | +|:----------------|---|---|------------:|------:|-----------:|------:|------:|-----:|-----:|-------:| +| Ubuntu Jammy | ☐ | ☐ | 3.10 | u2.42 | u1.2020.2 | u0.8 | 2.1.6 | u3.4 | 0.51 | 4.4.2 | +| Debian Bullseye | ☐ | ☐ | 3.9 | 2.42 | 1.2020.2 | 0.7 | 2.1.6 | | 0.51 | 4.3.7 | --- ## Who -### Author +### By * [Marc Beninca](https://marc.beninca.link) +### For + +* People feeling the need to aim for consistency in the CI / CD universe + --- ## Where @@ -274,7 +290,5 @@ Handle project workflows in a unified way: * rpm fusion * tex * translate to french -* try to support - * guix - * nix +* try to support nix * uv diff --git a/spcd/__init__.py b/spcd/__init__.py index 31cd594..4b9b6a5 100644 --- a/spcd/__init__.py +++ b/spcd/__init__.py @@ -10,13 +10,12 @@ from rwx import fs from rwx.log import stream as log from rwx.ps import run -from spcd import act, commands +from spcd import cmd from spcd.ci import project, projects from spcd.shell import env from spcd.util import browse, cat, split, step COMMANDS_PREFIX = "spcd-" -ENTRY_POINT = "__main__.py" def clone_project_branch() -> None: @@ -45,45 +44,6 @@ def clone_project_branch() -> None: ) -def install_actions() -> None: - """Make actions usable in workflows.""" - step("Install actions") - name = "action.yaml" - root = project.root / "act" - vpy = Path(env.SPCD_PYTHON_VENV_BINARIES) / "python" - for action in ("action", "synchronize"): - log.info(action) - directory = root / action - fs.make_directory(directory) - match action: - case "action": - inputs = """\ - arg_1: - required: true - arg_2: - required: true - arg_3: - required: true - arg_4: - default: '"placeholder"' -""" - case "synchronize": - inputs = """\ - source: - default: out - required: false -""" - yaml = f"""\ -runs: - using: composite - steps: - - run: {vpy} -m spcd {action} -inputs: -{inputs}""" - fs.write(directory / name, yaml) - cat(directory / name) - - def install_commands(path: Path) -> None: """Make commands callable in the operating system. @@ -92,12 +52,12 @@ def install_commands(path: Path) -> None: """ step("Install commands") user = Path("/usr/local/bin") - for command in ( + for command in [ "browse-workspace", "build-project", "check-project", "synchronize", - ): + ]: log.info(command) (user / f"{COMMANDS_PREFIX}{command}").symlink_to(path) @@ -148,20 +108,15 @@ def main(main_file: Path) -> None: if env.SPCD_PYTHON_VENV_BINARIES not in paths: environ["PATH"] = pathsep.join([env.SPCD_PYTHON_VENV_BINARIES, *paths]) path, *arguments = sys.argv - if (name := Path(path).name) == ENTRY_POINT: - if arguments: - name, *arguments = arguments - f = getattr(act, name) - f(*arguments) - else: - list_environment_variables() - clone_project_branch() - set_ssh() - install_actions() - install_commands(main_file) - install_python_packages() + name = Path(path).name + if name == "__main__.py": + list_environment_variables() + clone_project_branch() + set_ssh() + install_commands(main_file) + install_python_packages() else: - f = getattr(commands, name.replace("-", "_")) + f = getattr(cmd, name.replace("-", "_")) f(*arguments) diff --git a/spcd/act.py b/spcd/act.py deleted file mode 100644 index 7886bbe..0000000 --- a/spcd/act.py +++ /dev/null @@ -1,62 +0,0 @@ -"""Actions available for workflows.""" - -from __future__ import annotations - -import os -from ast import literal_eval -from pathlib import Path - -from rwx import ps -from rwx.log import stream as log - -from spcd.ci import project, projects -from spcd.shell import env - -PREFIX = "INPUT_" - - -def action() -> None: - """Display action inputs.""" - for variable, value in parse_inputs().items(): - log.info("%s = %s", variable, value) - - -def parse_inputs() -> dict[str, object]: - """Parse inputs as a dictionary. - - :return: name & value pairs - :rtype: dict[str, object] - """ - inputs = {} - for variable, value in sorted(projects.environment.items()): - if variable.startswith(PREFIX): - name = variable.removeprefix(PREFIX).lower() - inputs[name] = literal_eval(value) - return inputs - - -def synchronize(source: str | None = None, target: str | None = None) -> None: - """Synchronize output towards a target. - - :param source: where to deploy from - :type source: str | None - :param target: where to deploy to - :type target: str | None - """ - if not target: - user = "cd" - host = env.SPCD_PROJECT_PATH - root = ( - Path(os.sep) / user / projects.group / project.name / project.branch - ) - target = f"{user}@{host}:{root}" - if not source: - source = "out" - ps.run( - "rsync", - "--archive", - "--delete-before", - "--verbose", - f"{source}/", - f"{target}/", - ) diff --git a/spcd/bootstrap.sh b/spcd/bootstrap.sh index 3ce4993..b9b1702 100644 --- a/spcd/bootstrap.sh +++ b/spcd/bootstrap.sh @@ -1,3 +1,5 @@ +#! /usr/bin/env sh + # ╭───────────────╮ # │ __ = internal │ # ╰───────────────╯ @@ -384,7 +386,6 @@ spcd_e_default() { [ -n "${SPCD_GIT_SHUNIT}" ] || SPCD_GIT_SHUNIT="shunit2" - [ -n "${SPCD_REF_ARCHIVE}" ] || SPCD_REF_ARCHIVE="old" [ -n "${SPCD_REF_FEATURE}" ] || SPCD_REF_FEATURE="f" [ -n "${SPCD_REF_RELEASE}" ] || SPCD_REF_RELEASE="main" [ -n "${SPCD_REF_STAGING}" ] || SPCD_REF_STAGING="dev" @@ -512,8 +513,7 @@ ${SPCD_PROJECT_ROOT}$(basename "${GITHUB_SERVER_URL}")" fi # check project variables case "${SPCD_PROJECT_BRANCH}" in - "${SPCD_REF_ARCHIVE}" | \ - "${SPCD_REF_RELEASE}" | \ + "${SPCD_REF_RELEASE}" | \ "${SPCD_REF_STAGING}" | \ "${SPCD_REF_FEATURE}") ;; *) spcd_error_ci "SPCD_PROJECT_BRANCH" ;; @@ -796,15 +796,6 @@ spcd_f_pkg() { "${SPCD_OS_ALMA}" | "${SPCD_OS_ROCKY}") ;; *) spcd_f_pm_pkg_install "gource" ;; esac - # gpg - spcd_step "GnuPG" - case "${SPCD_OS_ID}" in - "${SPCD_OS_DEBIAN}") - spcd_f_pm_pkg_install "gpg" - ;; - # TODO other operating systems - *) ;; - esac # graphviz spcd_step "GraphViz" spcd_f_pm_pkg_install "graphviz" @@ -826,9 +817,6 @@ spcd_f_pkg() { # plantuml spcd_step "PlantUML" spcd_f_pm_pkg_install "plantuml" - # qrencode - spcd_step "QRencode" - spcd_f_pm_pkg_install "qrencode" # rsync spcd_step "Rsync" spcd_f_pm_pkg_install "rsync" @@ -852,20 +840,6 @@ spcd_f_pkg() { ;; *) spcd_f_pm_pkg_install "shfmt" ;; esac - # tex - spcd_step "TeX" - case "${SPCD_OS_ID}" in - "${SPCD_OS_DEBIAN}") - spcd_f_pm_pkg_install "texlive-xetex" - spcd_f_pm_pkg_install "texlive-lang-french" - spcd_f_pm_pkg_install "texlive-plain-generic" - spcd_f_pm_pkg_install "texlive-bibtex-extra" - spcd_f_pm_pkg_install "texlive-fonts-recommended" - spcd_f_pm_pkg_install "biber" - ;; - # TODO other operating systems - *) ;; - esac spcd_step_out } @@ -1405,7 +1379,6 @@ index-url = ${SPCD_URL_PYTHON}/simple spcd_step "Activate" export PATH="${SPCD_PYTHON_VENV_BINARIES}:${PATH}" export VIRTUAL_ENV="${SPCD_PYTHON_VENV}" - pip install "PyYAML" spcd_step_out } diff --git a/spcd/commands.py b/spcd/cmd.py similarity index 64% rename from spcd/commands.py rename to spcd/cmd.py index cc1a944..188d191 100644 --- a/spcd/commands.py +++ b/spcd/cmd.py @@ -1,8 +1,6 @@ """Commands available for workflows.""" -from __future__ import annotations - -from os import sep +import os from pathlib import Path from rwx import ps @@ -19,8 +17,8 @@ def spcd_browse_workspace() -> None: def spcd_build_project() -> None: """Perform the actual building process.""" - for extension in ("py", "sh"): - path = project.root / f"render.{extension}" + for extension in ["py", "sh"]: + path = project.root / f"build.{extension}" if path.exists(): ps.run(str(path)) break @@ -28,25 +26,11 @@ def spcd_build_project() -> None: def spcd_check_project() -> None: """Check the project for anything wrong.""" - ps.run( - "ruff", - "check", - ("--ignore", "D203,D213"), - "--isolated", - ("--select", "ALL"), - ) - ps.run( - "ruff", - "format", - "--diff", - "--isolated", - ("--line-length", "80"), - ) + ps.run("ruff", "check") def spcd_synchronize( - source: str | None = None, - target: str | None = None, + source: str | None = None, target: str | None = None ) -> None: """Synchronize output towards a target. @@ -58,7 +42,9 @@ def spcd_synchronize( if not target: user = "cd" host = env.SPCD_PROJECT_PATH - root = Path(sep) / user / projects.group / project.name / project.branch + root = ( + Path(os.sep) / user / projects.group / project.name / project.branch + ) target = f"{user}@{host}:{root}" if not source: source = "out" @@ -67,6 +53,6 @@ def spcd_synchronize( "--archive", "--delete-before", "--verbose", - f"{source}{sep}", - f"{target}{sep}", + f"{source}/", + f"{target}/", )