Compare commits

..

No commits in common. "4ba599b2fe69d24d9581e761fdc211ab8fc23d60" and "a0a64a098f3146c51914afd12ab7c0ce52f5f1d5" have entirely different histories.

8 changed files with 75 additions and 225 deletions

View file

@ -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:

View file

@ -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:

View file

@ -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"

View file

@ -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

View file

@ -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)

View file

@ -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}/",
)

View file

@ -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
}

View file

@ -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}/",
)