From ef5d81fd201dc1e62ee41a83b047b4bf9a1312df Mon Sep 17 00:00:00 2001 From: Mikhail Yevchenko Date: Mon, 7 Sep 2026 16:23:19 +0300 Subject: [PATCH] Build all five G15 packages and add native Gitea push CI --- .gitea/workflows/debian.yml | 34 ++++++++++++++++++++++++++++++++++ .github/workflows/debian.yml | 3 +++ README.md | 16 ++++++++++------ packaging/Dockerfile | 2 +- packaging/NOTES.md | 26 ++++++++++++++++---------- packaging/build.sh | 18 ++++++++++++------ packaging/rebuild.sh | 4 ++-- packaging/run.sh | 2 +- packaging/test.sh | 10 ++++++---- 9 files changed, 85 insertions(+), 30 deletions(-) create mode 100644 .gitea/workflows/debian.yml diff --git a/.gitea/workflows/debian.yml b/.gitea/workflows/debian.yml new file mode 100644 index 0000000..3104b2b --- /dev/null +++ b/.gitea/workflows/debian.yml @@ -0,0 +1,34 @@ +name: Debian 13 packages +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 60 + steps: + - uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + with: + persist-credentials: false + submodules: recursive + - name: Build, test and rebuild all five sources + shell: bash + run: | + set -euo pipefail + for script in packaging/*.sh packaging/overlays/v1/*.sh; do bash -n "$script"; done + mkdir -p "$RUNNER_TEMP/debs" + bash packaging/run.sh "$RUNNER_TEMP/debs" + docker run --rm --mount "type=bind,src=$PWD/packaging,dst=/checks/packaging,readonly" \ + -w /checks g15-packaging shellcheck packaging/*.sh packaging/overlays/v1/*.sh + test -z "$(git submodule foreach --quiet --recursive 'git status --porcelain')" + - name: Upload verified binaries and standalone sources + uses: https://github.com/actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3 (Gitea artifact protocol) + with: + name: debian13-amd64 + path: ${{ runner.temp }}/debs/* + if-no-files-found: error \ No newline at end of file diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml index ff31a5a..feb1b2f 100644 --- a/.github/workflows/debian.yml +++ b/.github/workflows/debian.yml @@ -1,5 +1,7 @@ name: Debian 13 packages on: + push: + branches: [main] pull_request: paths: - 'packaging/**' @@ -12,6 +14,7 @@ on: - 'libg15render' - 'g15daemon' - 'g15macro' + - 'g15stats' workflow_dispatch: release: types: [published] diff --git a/README.md b/README.md index 1ae349f..4fd92af 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ # G15 tools: Debian 13 development and packages -This outer repository builds and packages four pinned Git submodules: `libg15`, -`libg15render`, `g15daemon`, and `g15macro`. A fifth submodule, `g15stats`, is -present but is not integrated into the build or packaging pipeline. +This outer repository builds and packages five pinned Git submodules: `libg15`, +`libg15render`, `g15daemon`, `g15macro`, and `g15stats`. Initialize a fresh clone with `git submodule update --init --recursive`. Builds reject missing, dirty, or misaligned submodules; they export committed, unpatched Debian sources and @@ -12,18 +11,23 @@ never modify submodule working trees or refs. Create an empty directory outside the checkout (for example with `mktemp -d`) and run `bash packaging/run.sh /absolute/path/to/that-directory`. -The runner uses disposable Debian 13 Docker containers to build all four +The runner uses disposable Debian 13 Docker containers to build all five projects in dependency order, install their own development packages before -downstream builds, test distro replacement, and rebuild all four source packages +downstream builds, test distro replacement, and rebuild all five source packages without the checkout mounted. It mounts only an allowlist of build inputs; `.vscode` is not exposed to release build containers. -Outputs include eight binary packages, debug symbols, four standalone Debian +Outputs include nine binary packages, debug symbols, five standalone Debian source packages, build metadata, submodule provenance and checksums. See `packaging/NOTES.md` for versions, overlays, QA and release behavior. The old outer `git archive` ZIP is not a source distribution: it omits submodule content. Use the verified Debian source artifacts instead. +Gitea Actions builds all five projects on pushes to `main` and manual dispatch. +Successful runs provide the `debian13-amd64` artifact, including binaries, +standalone sources and `SHA256SUMS`. An `ubuntu-latest` runner with local Docker +and matching workspace mount paths is required; see `packaging/NOTES.md`. + **Safety limitation:** legacy macro memory/configuration handling has known preexisting defects. Compatibility overlays do not repair the macro engine. Do not run it as root or use untrusted configuration. Build and install tests diff --git a/packaging/Dockerfile b/packaging/Dockerfile index 2b1e869..bb46e06 100644 --- a/packaging/Dockerfile +++ b/packaging/Dockerfile @@ -2,7 +2,7 @@ FROM debian:trixie-slim ENV DEBIAN_FRONTEND=noninteractive RUN printf 'deb-src http://deb.debian.org/debian trixie main\n' > /etc/apt/sources.list.d/g15-source.list \ && apt-get update \ - && apt-get install -y --no-install-recommends build-essential autoconf automake libtool pkg-config debhelper dpkg-dev libusb-1.0-0-dev git ca-certificates fakeroot lintian devscripts dh-sequence-movetousr libfreetype-dev libxtst-dev quilt shellcheck \ + && apt-get install -y --no-install-recommends build-essential autoconf automake libtool pkg-config debhelper dpkg-dev libusb-1.0-0-dev git ca-certificates fakeroot lintian devscripts dh-sequence-movetousr libfreetype-dev libxtst-dev libgtop2-dev quilt shellcheck \ && rm -rf /var/lib/apt/lists/* WORKDIR /work CMD ["bash", "packaging/container-build.sh"] \ No newline at end of file diff --git a/packaging/NOTES.md b/packaging/NOTES.md index 4413535..b145baf 100644 --- a/packaging/NOTES.md +++ b/packaging/NOTES.md @@ -9,7 +9,7 @@ API keys or `.env` are needed. Build scripts install packages and require a disposable root container; do not run them in the hardware-enabled devcontainer. `G15_BUILD_IMAGE` optionally changes the shared image tag. -`run.sh` builds `packaging/Dockerfile`, mounts only Git metadata, the four +`run.sh` builds `packaging/Dockerfile`, mounts only Git metadata, the five submodules and `packaging/` read-only, then runs build and lifecycle tests. A second fresh container mounts only artifacts and `rebuild.sh`, proving that the source packages do not need this repository. All working sources are in @@ -19,12 +19,12 @@ allowlisted mount layout. No container receives USB, uinput or a Docker socket. ## Sources, patches and versions -Order: `libg15`, `libg15render`, `g15daemon`, `g15macro`. Each stage installs +Order: `libg15`, `libg15render`, `g15daemon`, `g15macro`, `g15stats`. Each stage installs its own runtime and development packages before the next stage resolves build dependencies. The base image does not supply distro G15 development packages. -Each of these four build submodules must match its indexed gitlink and be clean. -The additional `g15stats` submodule is not built, packaged or recorded in package -provenance. Git +Each of these five build submodules must match its indexed gitlink and be clean. +Stats uses its committed modern Debian packaging without an outer overlay; +the image includes its `libgtop2-dev` build dependency. Git archives export immutable HEADs, not working-tree contents. No checkout, patching, committing, ref updates or pushing occurs in submodules. @@ -52,7 +52,7 @@ The inherited `dh_installsystemd --no-start` remains in force. Versions use `+g15.git<12-character-commit>-1`. Macro's upstream version is 1.0.5 (configure.ac), not the historical Debian changelog's 1.0.3. Tests require versions above every available trixie candidate, including binNMUs. -There is no trixie macro candidate: macro is tested as a fresh installation, +There are no trixie macro or stats candidates: both are tested as fresh installations, not falsely reported as a distro upgrade. Increment the local Debian revision when changing overlays for an already-published source commit. Git hashes are identifiers, not monotonically increasing versions between local releases. @@ -65,9 +65,9 @@ binary reproducibility. Keep complete released artifacts. No signing is performe ## Outputs and gates -Eight packages: `libg15-1`, `libg15-dev`, `libg15render1`, `libg15render-dev`, -`g15daemon`, `libg15daemon-client1t64`, `libg15daemon-client-dev`, `g15macro`; -plus five debug-symbol packages on amd64. Each of the four sources has a `.dsc`, +Nine packages: `libg15-1`, `libg15-dev`, `libg15render1`, `libg15render-dev`, +`g15daemon`, `libg15daemon-client1t64`, `libg15daemon-client-dev`, `g15macro`, `g15stats`; +plus six debug-symbol packages on amd64. Each of the five sources has a `.dsc`, orig tarball, Debian tarball, `.buildinfo` and `.changes`. `SUBMODULES` records pins and `SHA256SUMS` covers all artifacts. The outer Git ZIP is not a substitute. @@ -77,7 +77,13 @@ SONAMEs, executable linking, development headers/linking, t64 fields, service and udev installation, macro help/version and purge cleanup. Source rebuilds install newly rebuilt dependencies, not binaries from the first build. -CI uses recursive checkout on relevant PRs, manual dispatch and published +Gitea CI (`.gitea/workflows/debian.yml`) builds on every push to `main` and +manual dispatch, using an `ubuntu-latest` runner with local Docker Engine. +The runner must expose the same workspace paths to Docker for read-only mounts. +It uploads `debian13-amd64` artifacts using the Gitea-compatible v3 protocol; +download the artifact from the successful run and check `SHA256SUMS`. +Gitea does not run the GitHub CLI release job or publish release assets. +GitHub CI uses recursive checkout on main pushes, relevant PRs, manual dispatch and published releases. Build permissions are read-only; a separate write-permission job downloads the verified artifact and checks checksums before uploading release assets. All actions are commit-pinned. Existing assets are not overwritten. diff --git a/packaging/build.sh b/packaging/build.sh index 9f4f6f5..76e95af 100644 --- a/packaging/build.sh +++ b/packaging/build.sh @@ -14,15 +14,15 @@ trap 'rm -rf "$work"' EXIT export DEB_BUILD_OPTIONS=${DEB_BUILD_OPTIONS:-parallel=2} export DEBFULLNAME='G15 packaging contributors' DEBEMAIL='noreply@example.invalid' git config --global --add safe.directory "$root" -for source in libg15 libg15render g15daemon g15macro; do +for source in libg15 libg15render g15daemon g15macro g15stats; do git config --global --add safe.directory "$root/$source" pin=$(git -C "$root" ls-files --stage -- "$source" | awk '$1 == 160000 {print $2}') [[ -n $pin && $(git -C "$root/$source" rev-parse HEAD) == "$pin" ]] [[ -z $(git -C "$root/$source" status --porcelain --untracked-files=all) ]] done -git -C "$root" submodule status --recursive -- libg15 libg15render g15daemon g15macro > "$out/SUBMODULES" +git -C "$root" submodule status --recursive -- libg15 libg15render g15daemon g15macro g15stats > "$out/SUBMODULES" if grep -q '^[+U-]' "$out/SUBMODULES"; then echo 'Submodule pin mismatch or missing module' >&2; exit 1; fi -for source in libg15 libg15render g15daemon g15macro; do +for source in libg15 libg15render g15daemon g15macro g15stats; do mkdir "$work/$source" cd "$work/$source" sha=$(git -C "$root/$source" rev-parse HEAD) @@ -40,7 +40,9 @@ for source in libg15 libg15render g15daemon g15macro; do tree=$PWD/$source-$upstream tar --sort=name --mtime="@$SOURCE_DATE_EPOCH" --owner=0 --group=0 --numeric-owner \ --exclude="$source-$upstream/debian" -cJf "${source}_${upstream}.orig.tar.xz" "$source-$upstream" - (cd "$tree" && bash "$root/packaging/overlays/v1/apply.sh" "$source" "$root") + if [[ $source != g15stats ]]; then + (cd "$tree" && bash "$root/packaging/overlays/v1/apply.sh" "$source" "$root") + fi if [[ $source == g15daemon ]]; then mkdir official (cd official && apt-get source --download-only g15daemon=1.9.5.3-14.1 && dpkg-source --skip-patches -x ./*.dsc source) @@ -50,9 +52,13 @@ for source in libg15 libg15render g15daemon g15macro; do cd "$tree" sed -i "s/^Maintainer:.*/Maintainer: $DEBFULLNAME <$DEBEMAIL>/" debian/control dch --newversion "$version" --distribution trixie --force-distribution \ - "Export $source commit $sha; apply documented outer packaging overlay v1." + "Export $source commit $sha; see README.local-build for packaging policy." sed -i "0,/^ -- /s/^ -- .*/ -- $DEBFULLNAME <$DEBEMAIL> $(date -u -R -d "@$SOURCE_DATE_EPOCH")/" debian/changelog - cp "$root/packaging/overlays/v1/README.md" debian/README.local-build + if [[ $source == g15stats ]]; then + printf '%s\n' 'Uses committed Debian packaging without an outer overlay.' > debian/README.local-build + else + cp "$root/packaging/overlays/v1/README.md" debian/README.local-build + fi apt-get build-dep -y . dpkg-buildpackage -us -uc -sa cd .. diff --git a/packaging/rebuild.sh b/packaging/rebuild.sh index 8493dc6..6e25a02 100644 --- a/packaging/rebuild.sh +++ b/packaging/rebuild.sh @@ -8,7 +8,7 @@ out=$(realpath "${1:?artifact directory}") work=$(mktemp -d) trap 'rm -rf "$work"' EXIT export DEB_BUILD_OPTIONS=parallel=2 -for source in libg15 libg15render g15daemon g15macro; do +for source in libg15 libg15render g15daemon g15macro g15stats; do mkdir "$work/$source" cd "$work/$source" dsc=("$out/${source}_"*.dsc) @@ -20,4 +20,4 @@ for source in libg15 libg15render g15daemon g15macro; do cd .. apt-get install -y ./*.deb done -echo 'PASS: all four source artifacts rebuilt standalone in dependency order.' +echo 'PASS: all five source artifacts rebuilt standalone in dependency order.' diff --git a/packaging/run.sh b/packaging/run.sh index 4fb5c2e..f075d3a 100644 --- a/packaging/run.sh +++ b/packaging/run.sh @@ -10,7 +10,7 @@ image=${G15_BUILD_IMAGE:-g15-packaging} docker build -t "$image" -f "$root/packaging/Dockerfile" "$root/packaging" # Allowlist mounts: .vscode and other unrelated local files are not exposed. mounts=() -for path in .git .gitmodules packaging libg15 libg15render g15daemon g15macro; do +for path in .git .gitmodules packaging libg15 libg15render g15daemon g15macro g15stats; do mounts+=(--mount "type=bind,src=$root/$path,dst=/work/$path,readonly") done docker run --rm "${mounts[@]}" --mount "type=bind,src=$out,dst=/out" "$image" diff --git a/packaging/test.sh b/packaging/test.sh index d746db3..3a1e9ed 100644 --- a/packaging/test.sh +++ b/packaging/test.sh @@ -6,7 +6,9 @@ export LC_ALL=C out=$(realpath "${1:?artifact directory required}") cd "$out" sha256sum -c SHA256SUMS -packages=(libg15-1 libg15-dev libg15render1 libg15render-dev g15daemon libg15daemon-client1t64 libg15daemon-client-dev g15macro) +packages=(libg15-1 libg15-dev libg15render1 libg15render-dev g15daemon libg15daemon-client1t64 libg15daemon-client-dev g15macro g15stats) +[[ $(find . -maxdepth 1 -name '*.dsc' | wc -l) == 5 ]] +[[ $(wc -l < SUBMODULES) == 5 ]] distro=() for package in "${packages[@]}"; do files=("${package}"_*.deb) @@ -17,8 +19,8 @@ for package in "${packages[@]}"; do dpkg --compare-versions "$(dpkg-deb -f "${files[0]}" Version)" gt "$candidate" distro+=("$package=$candidate") else - [[ $package == g15macro ]] || exit 1 - echo 'g15macro has no trixie candidate; fresh installation only.' + [[ $package == g15macro || $package == g15stats ]] || exit 1 + echo "$package has no trixie candidate; fresh installation only." fi done lintian --fail-on error ./*.changes @@ -43,7 +45,7 @@ smoke() { files=("${package}"_*.deb) [[ $(dpkg-query -W -f='${Version}' "$package") == "$(dpkg-deb -f "${files[0]}" Version)" ]] done - for binary in /usr/sbin/g15daemon /usr/bin/g15macro; do + for binary in /usr/sbin/g15daemon /usr/bin/g15macro /usr/bin/g15stats; do ldd "$binary" > "$scratch/ldd" cat "$scratch/ldd" if grep -q 'not found' "$scratch/ldd"; then exit 1; fi