Align CI with the validated Ubuntu support floor

Stop implying that one Ubuntu 3.11 unit lane validates the full Linux support surface Aman documents.\n\nSplit CI into an Ubuntu CPython 3.10/3.11/3.12 unit-package matrix, a portable install plus doctor smoke lane, and a packaging lane gated on both. Add a reproducible ci_portable_smoke.sh helper with fake systemctl coverage, and force the installer onto /usr/bin/python3 so the smoke path uses the distro-provided GI and X11 Python packages it is meant to validate.\n\nUpdate the README, release/distribution docs, and Debian metadata to distinguish the automated Ubuntu CI floor from broader manual GA signoff families, and add the missing AppIndicator introspection package to the Ubuntu/Debian dependency lists.\n\nValidate with python3 -m unittest discover -s tests -p 'test_*.py', python3 -m py_compile src/*.py tests/*.py, and bash -n scripts/ci_portable_smoke.sh. The full xvfb-backed smoke could not be run locally in this sandbox because xvfb-run is unavailable.
This commit is contained in:
Thales Maciel 2026-03-14 15:45:21 -03:00
parent 4d0081d1d0
commit dd2813340b
9 changed files with 270 additions and 9 deletions

View file

@ -5,18 +5,120 @@ on:
pull_request: pull_request:
jobs: jobs:
test-and-build: unit-matrix:
name: Unit Matrix (${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install Ubuntu runtime dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
gobject-introspection \
libcairo2-dev \
libgirepository1.0-dev \
libportaudio2 \
pkg-config \
python3-gi \
python3-xlib \
gir1.2-gtk-3.0 \
gir1.2-ayatanaappindicator3-0.1 \
libayatana-appindicator3-1
- name: Create project environment
run: |
python -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install uv build
uv sync --active --frozen
echo "${GITHUB_WORKSPACE}/.venv/bin" >> "${GITHUB_PATH}"
- name: Run compile check
run: python -m py_compile src/*.py tests/*.py
- name: Run unit and package-logic test suite
run: python -m unittest discover -s tests -p 'test_*.py'
portable-ubuntu-smoke:
name: Portable Ubuntu Smoke
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-python@v5 - uses: actions/setup-python@v5
with: with:
python-version: "3.11" python-version: "3.11"
- name: Install dependencies - name: Install Ubuntu runtime dependencies
run: | run: |
sudo apt-get update
sudo apt-get install -y \
gobject-introspection \
libcairo2-dev \
libgirepository1.0-dev \
libportaudio2 \
pkg-config \
python3-gi \
python3-xlib \
gir1.2-gtk-3.0 \
gir1.2-ayatanaappindicator3-0.1 \
libayatana-appindicator3-1 \
xvfb
- name: Create project environment
run: |
python -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade pip python -m pip install --upgrade pip
python -m pip install uv build python -m pip install uv build
uv sync uv sync --active --frozen
echo "${GITHUB_WORKSPACE}/.venv/bin" >> "${GITHUB_PATH}"
- name: Run portable install and doctor smoke with distro python
env:
AMAN_CI_SYSTEM_PYTHON: /usr/bin/python3
run: bash ./scripts/ci_portable_smoke.sh
- name: Upload portable smoke logs
if: always()
uses: actions/upload-artifact@v4
with:
name: aman-portable-smoke-logs
path: build/ci-smoke
package-artifacts:
name: Package Artifacts
runs-on: ubuntu-latest
needs:
- unit-matrix
- portable-ubuntu-smoke
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install Ubuntu runtime dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
gobject-introspection \
libcairo2-dev \
libgirepository1.0-dev \
libportaudio2 \
pkg-config \
python3-gi \
python3-xlib \
gir1.2-gtk-3.0 \
gir1.2-ayatanaappindicator3-0.1 \
libayatana-appindicator3-1
- name: Create project environment
run: |
python -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install uv build
uv sync --active --frozen
echo "${GITHUB_WORKSPACE}/.venv/bin" >> "${GITHUB_PATH}"
- name: Prepare release candidate artifacts - name: Prepare release candidate artifacts
run: make release-prep run: make release-prep
- name: Upload packaging artifacts - name: Upload packaging artifacts

View file

@ -19,12 +19,16 @@ Support requests and bug reports go to
| Supported daily-use mode | `systemd --user` service | | Supported daily-use mode | `systemd --user` service |
| Manual foreground mode | `aman run` for setup, support, and debugging | | Manual foreground mode | `aman run` for setup, support, and debugging |
| Canonical recovery sequence | `aman doctor` -> `aman self-check` -> `journalctl --user -u aman` -> `aman run --verbose` | | Canonical recovery sequence | `aman doctor` -> `aman self-check` -> `journalctl --user -u aman` -> `aman run --verbose` |
| Representative GA validation families | Debian/Ubuntu, Arch, Fedora, openSUSE | | Automated CI floor | Ubuntu CI: CPython `3.10`, `3.11`, `3.12` for unit/package coverage, plus portable install and `aman doctor` smoke with Ubuntu system `python3` |
| Manual GA signoff families | Debian/Ubuntu, Arch, Fedora, openSUSE |
| Portable installer prerequisite | System CPython `3.10`, `3.11`, or `3.12` | | Portable installer prerequisite | System CPython `3.10`, `3.11`, or `3.12` |
Distribution policy and user persona details live in Distribution policy and user persona details live in
[`docs/persona-and-distribution.md`](docs/persona-and-distribution.md). [`docs/persona-and-distribution.md`](docs/persona-and-distribution.md).
The wider distro-family list is a manual validation target for release signoff.
It is not the current automated CI surface yet.
## 60-Second Quickstart ## 60-Second Quickstart
First, install the runtime dependencies for your distro: First, install the runtime dependencies for your distro:
@ -33,7 +37,7 @@ First, install the runtime dependencies for your distro:
<summary>Ubuntu/Debian</summary> <summary>Ubuntu/Debian</summary>
```bash ```bash
sudo apt install -y libportaudio2 python3-gi python3-xlib gir1.2-gtk-3.0 libayatana-appindicator3-1 sudo apt install -y libportaudio2 python3-gi python3-xlib gir1.2-gtk-3.0 gir1.2-ayatanaappindicator3-0.1 libayatana-appindicator3-1
``` ```
</details> </details>

View file

@ -14,10 +14,13 @@ make package-arch
make runtime-check make runtime-check
make release-check make release-check
make release-prep make release-prep
bash ./scripts/ci_portable_smoke.sh
``` ```
- `make package-portable` builds `dist/aman-x11-linux-<version>.tar.gz` plus - `make package-portable` builds `dist/aman-x11-linux-<version>.tar.gz` plus
its `.sha256` file. its `.sha256` file.
- `bash ./scripts/ci_portable_smoke.sh` reproduces the Ubuntu CI portable
install plus `aman doctor` smoke path locally.
- `make release-prep` runs `make release-check`, builds the packaged artifacts, - `make release-prep` runs `make release-check`, builds the packaged artifacts,
and writes `dist/SHA256SUMS` for the release page upload set. and writes `dist/SHA256SUMS` for the release page upload set.
- `make package-deb` installs Python dependencies while creating the package. - `make package-deb` installs Python dependencies while creating the package.

View file

@ -50,7 +50,10 @@ For X11 GA, Aman supports:
- Runtime dependencies installed from the distro package manager. - Runtime dependencies installed from the distro package manager.
- `systemd --user` as the supported daily-use path. - `systemd --user` as the supported daily-use path.
- `aman run` as the foreground setup, support, and debugging path. - `aman run` as the foreground setup, support, and debugging path.
- Representative validation across Debian/Ubuntu, Arch, Fedora, and openSUSE. - Automated validation floor on Ubuntu CI: CPython `3.10`, `3.11`, and `3.12`
for unit/package coverage, plus portable install and `aman doctor` smoke with
Ubuntu system `python3`.
- Manual GA signoff families: Debian/Ubuntu, Arch, Fedora, openSUSE.
- The recovery sequence `aman doctor` -> `aman self-check` -> - The recovery sequence `aman doctor` -> `aman self-check` ->
`journalctl --user -u aman` -> `aman run --verbose`. `journalctl --user -u aman` -> `aman run --verbose`.

View file

@ -15,6 +15,11 @@ Download published bundles, checksums, and release notes from
- System CPython `3.10`, `3.11`, or `3.12` - System CPython `3.10`, `3.11`, or `3.12`
- Runtime dependencies installed from the distro package manager - Runtime dependencies installed from the distro package manager
Current automated validation covers Ubuntu CI on CPython `3.10`, `3.11`, and
`3.12` for unit/package coverage, plus a portable install and `aman doctor`
smoke path with Ubuntu system `python3`. The other distro-family instructions
below remain manual validation targets.
## Runtime dependencies ## Runtime dependencies
Install the runtime dependencies for your distro before running `install.sh`. Install the runtime dependencies for your distro before running `install.sh`.
@ -22,7 +27,7 @@ Install the runtime dependencies for your distro before running `install.sh`.
### Ubuntu/Debian ### Ubuntu/Debian
```bash ```bash
sudo apt install -y libportaudio2 python3-gi python3-xlib gir1.2-gtk-3.0 libayatana-appindicator3-1 sudo apt install -y libportaudio2 python3-gi python3-xlib gir1.2-gtk-3.0 gir1.2-ayatanaappindicator3-0.1 libayatana-appindicator3-1
``` ```
### Arch Linux ### Arch Linux

View file

@ -15,7 +15,10 @@ This is the first GA-targeted X11 release for Aman.
- `systemd --user` for supported daily use - `systemd --user` for supported daily use
- System CPython `3.10`, `3.11`, or `3.12` for the portable installer - System CPython `3.10`, `3.11`, or `3.12` for the portable installer
- Runtime dependencies installed from the distro package manager - Runtime dependencies installed from the distro package manager
- Representative validation families: Debian/Ubuntu, Arch, Fedora, openSUSE - Automated validation floor: Ubuntu CI on CPython `3.10`, `3.11`, and `3.12`
for unit/package coverage, plus portable install and `aman doctor` smoke
with Ubuntu system `python3`
- Manual GA signoff families: Debian/Ubuntu, Arch, Fedora, openSUSE
## Artifacts ## Artifacts

View file

@ -34,6 +34,10 @@ state.
## Evidence sources ## Evidence sources
- Automated CI validation:
GitHub Actions Ubuntu lanes for CPython `3.10`, `3.11`, and `3.12` for
unit/package coverage, plus a portable install and `aman doctor` smoke lane
with Ubuntu system `python3`
- Portable lifecycle matrix: - Portable lifecycle matrix:
[`portable-validation-matrix.md`](./portable-validation-matrix.md) [`portable-validation-matrix.md`](./portable-validation-matrix.md)
- Runtime reliability matrix: - Runtime reliability matrix:
@ -52,6 +56,7 @@ state.
| Milestone 2 portable lifecycle | Complete for now | Arch row in `portable-validation-matrix.md` plus [`user-readiness/1773357669.md`](../../user-readiness/1773357669.md) | | Milestone 2 portable lifecycle | Complete for now | Arch row in `portable-validation-matrix.md` plus [`user-readiness/1773357669.md`](../../user-readiness/1773357669.md) |
| Milestone 3 runtime reliability | Complete for now | Arch runtime rows in `runtime-validation-report.md` plus [`user-readiness/1773357669.md`](../../user-readiness/1773357669.md) | | Milestone 3 runtime reliability | Complete for now | Arch runtime rows in `runtime-validation-report.md` plus [`user-readiness/1773357669.md`](../../user-readiness/1773357669.md) |
| Milestone 4 first-run UX/docs | Complete | `first-run-review-notes.md` and `user-readiness/1773352170.md` | | Milestone 4 first-run UX/docs | Complete | `first-run-review-notes.md` and `user-readiness/1773352170.md` |
| Automated validation floor | Repo-complete | GitHub Actions Ubuntu matrix on CPython `3.10`-`3.12` plus portable smoke with Ubuntu system `python3` |
| Release metadata and support surface | Repo-complete | `LICENSE`, `SUPPORT.md`, `pyproject.toml`, packaging templates | | Release metadata and support surface | Repo-complete | `LICENSE`, `SUPPORT.md`, `pyproject.toml`, packaging templates |
| Release artifacts and checksums | Repo-complete | `make release-prep`, `dist/SHA256SUMS`, `docs/releases/1.0.0.md` | | Release artifacts and checksums | Repo-complete | `make release-prep`, `dist/SHA256SUMS`, `docs/releases/1.0.0.md` |
| Full four-family GA validation | Pending | Complete the remaining Debian/Ubuntu, Fedora, and openSUSE rows in both validation matrices | | Full four-family GA validation | Pending | Complete the remaining Debian/Ubuntu, Fedora, and openSUSE rows in both validation matrices |

View file

@ -4,7 +4,7 @@ Section: utils
Priority: optional Priority: optional
Architecture: __ARCH__ Architecture: __ARCH__
Maintainer: Thales Maciel <thales@thalesmaciel.com> Maintainer: Thales Maciel <thales@thalesmaciel.com>
Depends: python3, python3-venv, python3-gi, python3-xlib, libportaudio2, gir1.2-gtk-3.0, libayatana-appindicator3-1 Depends: python3, python3-venv, python3-gi, python3-xlib, libportaudio2, gir1.2-gtk-3.0, gir1.2-ayatanaappindicator3-0.1, libayatana-appindicator3-1
Description: Aman local amanuensis daemon for X11 desktops Description: Aman local amanuensis daemon for X11 desktops
Aman records microphone input, transcribes speech, optionally rewrites output, Aman records microphone input, transcribes speech, optionally rewrites output,
and injects text into the focused desktop app. Includes tray controls and a and injects text into the focused desktop app. Includes tray controls and a

136
scripts/ci_portable_smoke.sh Executable file
View file

@ -0,0 +1,136 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
source "${SCRIPT_DIR}/package_common.sh"
require_command mktemp
require_command tar
require_command xvfb-run
DISTRO_PYTHON="${AMAN_CI_SYSTEM_PYTHON:-/usr/bin/python3}"
require_command "${DISTRO_PYTHON}"
LOG_DIR="${BUILD_DIR}/ci-smoke"
RUN_DIR="${LOG_DIR}/run"
HOME_DIR="${RUN_DIR}/home"
FAKE_BIN_DIR="${RUN_DIR}/fake-bin"
EXTRACT_DIR="${RUN_DIR}/bundle"
RUNTIME_DIR="${RUN_DIR}/xdg-runtime"
COMMAND_LOG="${LOG_DIR}/commands.log"
SYSTEMCTL_LOG="${LOG_DIR}/systemctl.log"
dump_logs() {
local path
for path in "${COMMAND_LOG}" "${SYSTEMCTL_LOG}" "${LOG_DIR}"/*.stdout.log "${LOG_DIR}"/*.stderr.log; do
if [[ -f "${path}" ]]; then
echo "=== ${path#${ROOT_DIR}/} ==="
cat "${path}"
fi
done
}
on_exit() {
local status="$1"
if [[ "${status}" -ne 0 ]]; then
dump_logs
fi
}
trap 'on_exit $?' EXIT
run_logged() {
local name="$1"
shift
local stdout_log="${LOG_DIR}/${name}.stdout.log"
local stderr_log="${LOG_DIR}/${name}.stderr.log"
{
printf "+"
printf " %q" "$@"
printf "\n"
} >>"${COMMAND_LOG}"
"$@" >"${stdout_log}" 2>"${stderr_log}"
}
rm -rf "${LOG_DIR}"
mkdir -p "${HOME_DIR}" "${FAKE_BIN_DIR}" "${EXTRACT_DIR}" "${RUNTIME_DIR}"
: >"${COMMAND_LOG}"
: >"${SYSTEMCTL_LOG}"
cat >"${FAKE_BIN_DIR}/systemctl" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
log_path="${SYSTEMCTL_LOG:?}"
if [[ "${1:-}" == "--user" ]]; then
shift
fi
printf '%s\n' "$*" >>"${log_path}"
case "$*" in
"daemon-reload")
;;
"enable --now aman")
;;
"stop aman")
;;
"disable --now aman")
;;
"is-system-running")
printf 'running\n'
;;
"show aman --property=FragmentPath --value")
printf '%s\n' "${AMAN_CI_SERVICE_PATH:?}"
;;
"is-enabled aman")
printf 'enabled\n'
;;
"is-active aman")
printf 'active\n'
;;
*)
echo "unexpected systemctl command: $*" >&2
exit 1
;;
esac
EOF
chmod 0755 "${FAKE_BIN_DIR}/systemctl"
run_logged package-portable bash "${SCRIPT_DIR}/package_portable.sh"
VERSION="$(project_version)"
PACKAGE_NAME="$(project_name)"
PORTABLE_TARBALL="${DIST_DIR}/${PACKAGE_NAME}-x11-linux-${VERSION}.tar.gz"
BUNDLE_DIR="${EXTRACT_DIR}/${PACKAGE_NAME}-x11-linux-${VERSION}"
run_logged extract tar -C "${EXTRACT_DIR}" -xzf "${PORTABLE_TARBALL}"
export HOME="${HOME_DIR}"
export PATH="${FAKE_BIN_DIR}:${HOME_DIR}/.local/bin:${PATH}"
export SYSTEMCTL_LOG
export AMAN_CI_SERVICE_PATH="${HOME_DIR}/.config/systemd/user/aman.service"
run_logged distro-python "${DISTRO_PYTHON}" --version
(
cd "${BUNDLE_DIR}"
run_logged install env \
PATH="${FAKE_BIN_DIR}:${HOME_DIR}/.local/bin:$(dirname "${DISTRO_PYTHON}"):${PATH}" \
./install.sh
)
run_logged version "${HOME_DIR}/.local/bin/aman" version
run_logged init "${HOME_DIR}/.local/bin/aman" init --config "${HOME_DIR}/.config/aman/config.json"
run_logged doctor xvfb-run -a env \
HOME="${HOME_DIR}" \
PATH="${PATH}" \
SYSTEMCTL_LOG="${SYSTEMCTL_LOG}" \
AMAN_CI_SERVICE_PATH="${AMAN_CI_SERVICE_PATH}" \
XDG_RUNTIME_DIR="${RUNTIME_DIR}" \
XDG_SESSION_TYPE="x11" \
"${HOME_DIR}/.local/bin/aman" doctor --config "${HOME_DIR}/.config/aman/config.json"
run_logged uninstall "${HOME_DIR}/.local/share/aman/current/uninstall.sh" --purge
echo "portable smoke passed"
echo "logs: ${LOG_DIR}"
cat "${LOG_DIR}/doctor.stdout.log"