From 56167765a78e8f04c868f4e24917fba36253e3e3 Mon Sep 17 00:00:00 2001 From: Thomas Willetal Date: Sun, 12 Jul 2026 12:57:57 +0200 Subject: [PATCH 1/6] Example projects have been restructured and split into examples and fixtures --- .vscode/settings.json | 2 +- {test => example}/hplip/.gitignore | 0 {test => example}/hplip/build.sh | 0 {test => example}/hplip/clone.sh | 0 {test => example}/systemd/.gitignore | 0 {test => example}/systemd/build.sh | 0 {test => example}/systemd/clone.sh | 0 packtly-builder/tooling/pyproject.toml | 2 +- test/debhello/README.md | 33 ---------- test/debhello/debian/compat | 2 - .../build.sh => fixtures/build-quilt.sh} | 8 +-- .../debhello-native}/.gitignore | 0 .../debhello-native}/Makefile | 2 +- .../debhello-native}/debian/changelog | 0 .../debhello-native}/debian/control | 8 +-- .../debhello-native}/debian/copyright | 0 .../debhello-native}/debian/rules | 0 .../debhello-native}/debian/source/format | 0 .../debhello-native}/src/hello.c | 0 test/fixtures/debhello-quilt/.gitignore | 66 +++++++++++++++++++ test/fixtures/debhello-quilt/Makefile | 25 +++++++ test/fixtures/debhello-quilt/debian/changelog | 6 ++ test/fixtures/debhello-quilt/debian/control | 18 +++++ test/fixtures/debhello-quilt/debian/copyright | 9 +++ .../debhello-quilt/debian/debhello.install | 1 + test/fixtures/debhello-quilt/debian/rules | 12 ++++ .../debhello-quilt/debian/source/format | 1 + test/fixtures/debhello-quilt/src/hello.c | 8 +++ 28 files changed, 157 insertions(+), 46 deletions(-) rename {test => example}/hplip/.gitignore (100%) rename {test => example}/hplip/build.sh (100%) rename {test => example}/hplip/clone.sh (100%) rename {test => example}/systemd/.gitignore (100%) rename {test => example}/systemd/build.sh (100%) rename {test => example}/systemd/clone.sh (100%) delete mode 100644 test/debhello/README.md delete mode 100644 test/debhello/debian/compat rename test/{debhello/build.sh => fixtures/build-quilt.sh} (92%) rename test/{debhello => fixtures/debhello-native}/.gitignore (100%) rename test/{debhello => fixtures/debhello-native}/Makefile (87%) rename test/{debhello => fixtures/debhello-native}/debian/changelog (100%) rename test/{debhello => fixtures/debhello-native}/debian/control (80%) rename test/{debhello => fixtures/debhello-native}/debian/copyright (100%) rename test/{debhello => fixtures/debhello-native}/debian/rules (100%) rename test/{debhello => fixtures/debhello-native}/debian/source/format (100%) rename test/{debhello => fixtures/debhello-native}/src/hello.c (100%) create mode 100644 test/fixtures/debhello-quilt/.gitignore create mode 100644 test/fixtures/debhello-quilt/Makefile create mode 100644 test/fixtures/debhello-quilt/debian/changelog create mode 100644 test/fixtures/debhello-quilt/debian/control create mode 100644 test/fixtures/debhello-quilt/debian/copyright create mode 100644 test/fixtures/debhello-quilt/debian/debhello.install create mode 100755 test/fixtures/debhello-quilt/debian/rules create mode 100644 test/fixtures/debhello-quilt/debian/source/format create mode 100644 test/fixtures/debhello-quilt/src/hello.c diff --git a/.vscode/settings.json b/.vscode/settings.json index a7d493f..3edcedc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,7 +9,7 @@ "python.testing.pytestArgs": [ "-s", "--verbose", - "--dpkgbuild=test/debhello", + "--dpkgbuild=test/fixtures/debhello-quilt", "--no-cov", "packtly-builder/tooling/packtly_builder_tooling" ], diff --git a/test/hplip/.gitignore b/example/hplip/.gitignore similarity index 100% rename from test/hplip/.gitignore rename to example/hplip/.gitignore diff --git a/test/hplip/build.sh b/example/hplip/build.sh similarity index 100% rename from test/hplip/build.sh rename to example/hplip/build.sh diff --git a/test/hplip/clone.sh b/example/hplip/clone.sh similarity index 100% rename from test/hplip/clone.sh rename to example/hplip/clone.sh diff --git a/test/systemd/.gitignore b/example/systemd/.gitignore similarity index 100% rename from test/systemd/.gitignore rename to example/systemd/.gitignore diff --git a/test/systemd/build.sh b/example/systemd/build.sh similarity index 100% rename from test/systemd/build.sh rename to example/systemd/build.sh diff --git a/test/systemd/clone.sh b/example/systemd/clone.sh similarity index 100% rename from test/systemd/clone.sh rename to example/systemd/clone.sh diff --git a/packtly-builder/tooling/pyproject.toml b/packtly-builder/tooling/pyproject.toml index 744a5bc..3726160 100644 --- a/packtly-builder/tooling/pyproject.toml +++ b/packtly-builder/tooling/pyproject.toml @@ -43,7 +43,7 @@ packtly_builder_tooling = "packtly_builder_tooling.cli:main" [tool.pytest.ini_options] addopts = """\ - --dpkgbuild=../../test/debhello \ + --dpkgbuild=../../test/fixtures/debhello-quilt \ --doctest-modules \ --junitxml=python-test-results.xml \ --cov-report=term \ diff --git a/test/debhello/README.md b/test/debhello/README.md deleted file mode 100644 index fa25abd..0000000 --- a/test/debhello/README.md +++ /dev/null @@ -1,33 +0,0 @@ -Debian (.deb) package for C application automate example -==== - -# About -.deb package "Chapter 4. Simple Example" automation -[Chapter 4. Simple Example](https://www.debian.org/doc/manuals/debmake-doc/ch04.en.html) - -# Usage -``` -sudo apt-get install debmake -y -bash deploy/packaging_deb.sh -``` - -# Detail -packaging automation. - * make linux application source package of .tar.gz - * default debian package setting files and overwrite - * make .deb package - -# Output -.tar.gz : `object/deb_object/debhello-0.0.tar.gz` - (show: `tar -tzf debhello-0.0.tar.gz`) -.deb : `object/deb_object/debhello_0.0-1_amd64.deb` - (show: `dpkg -c debhello_0.0-1_amd64.deb`) - -# Reference -[Chapter 4. Simple Example](https://www.debian.org/doc/manuals/debmake-doc/ch04.en.html) -[(ja)第4章 debian/ ディレクトリー以下に無くてはならないファイル](https://www.debian.org/doc/manuals/maint-guide/dreq.ja.html) - -# Contact -mail: [michinari.nukazawa@gmail.com](mailto:michinari.nukazawa@gmail.com) -twitter: [@MNukazawa](https://twitter.com/MNukazawa) - diff --git a/test/debhello/debian/compat b/test/debhello/debian/compat deleted file mode 100644 index 021ea30..0000000 --- a/test/debhello/debian/compat +++ /dev/null @@ -1,2 +0,0 @@ -10 - diff --git a/test/debhello/build.sh b/test/fixtures/build-quilt.sh similarity index 92% rename from test/debhello/build.sh rename to test/fixtures/build-quilt.sh index ea5a6d3..81e4498 100755 --- a/test/debhello/build.sh +++ b/test/fixtures/build-quilt.sh @@ -9,12 +9,12 @@ TOPDIR="$(git rev-parse --show-toplevel)" KEYS_DIR="$TOPDIR/../packtly-infra/ansible/generated-secrets/localhost" APTLY_CREDENTIALS_FILE="$SCRIPT_DIR/../aptly-credentials" -CONTAINER_IMAGE="ghcr.io/packtly/packtly-builder:latest" -#CONTAINER_IMAGE="packtly-builder:latest" +#CONTAINER_IMAGE="ghcr.io/packtly/packtly-builder:latest" +CONTAINER_IMAGE="packtly-builder:latest" PODMAN_COMMON=( --rm - -v "$SCRIPT_DIR/..":/workspace:Z + -v "$SCRIPT_DIR":/workspace:Z -v "$KEYS_DIR/public/repo_signing.key":/opt/keys/gpg/repo_signing.key:Z,ro -v "$KEYS_DIR/private/repo_signing_private.key":/opt/keys/gpg/repo_signing_private.key:Z,ro -v "$KEYS_DIR/private/repo_signing_private_pass":/opt/keys/gpg/repo_signing_private_pass:Z,ro @@ -25,7 +25,7 @@ PODMAN_COMMON=( ) COMMON_ARGS=( - /workspace/debhello + /workspace/debhello-quilt --log-file /logs/build.log --dist trixie-apollo --component main diff --git a/test/debhello/.gitignore b/test/fixtures/debhello-native/.gitignore similarity index 100% rename from test/debhello/.gitignore rename to test/fixtures/debhello-native/.gitignore diff --git a/test/debhello/Makefile b/test/fixtures/debhello-native/Makefile similarity index 87% rename from test/debhello/Makefile rename to test/fixtures/debhello-native/Makefile index c1096ee..6b21508 100644 --- a/test/debhello/Makefile +++ b/test/fixtures/debhello-native/Makefile @@ -6,7 +6,7 @@ src/hello: src/hello.c @echo "CFLAGS=$(CFLAGS)" | \ fold -s -w 70 | \ sed -e 's/^/# /' - $(CC) $(CPPFLAGS) $(CFLAGS) $(LDCFLAGS) -o $@ $^ + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $^ install: src/hello install -D src/hello \ diff --git a/test/debhello/debian/changelog b/test/fixtures/debhello-native/debian/changelog similarity index 100% rename from test/debhello/debian/changelog rename to test/fixtures/debhello-native/debian/changelog diff --git a/test/debhello/debian/control b/test/fixtures/debhello-native/debian/control similarity index 80% rename from test/debhello/debian/control rename to test/fixtures/debhello-native/debian/control index 17129dc..b78faf4 100644 --- a/test/debhello/debian/control +++ b/test/fixtures/debhello-native/debian/control @@ -1,10 +1,10 @@ Source: debhello -Section: non-free/graphics +Section: utils Priority: optional Maintainer: Thomas Willetal -Build-Depends: debhelper (>=12), - libgtest-dev -Standards-Version: 3.9.6 +Build-Depends: debhelper-compat (= 13) +Standards-Version: 4.7.2 +Rules-Requires-Root: no Package: debhello Architecture: any diff --git a/test/debhello/debian/copyright b/test/fixtures/debhello-native/debian/copyright similarity index 100% rename from test/debhello/debian/copyright rename to test/fixtures/debhello-native/debian/copyright diff --git a/test/debhello/debian/rules b/test/fixtures/debhello-native/debian/rules similarity index 100% rename from test/debhello/debian/rules rename to test/fixtures/debhello-native/debian/rules diff --git a/test/debhello/debian/source/format b/test/fixtures/debhello-native/debian/source/format similarity index 100% rename from test/debhello/debian/source/format rename to test/fixtures/debhello-native/debian/source/format diff --git a/test/debhello/src/hello.c b/test/fixtures/debhello-native/src/hello.c similarity index 100% rename from test/debhello/src/hello.c rename to test/fixtures/debhello-native/src/hello.c diff --git a/test/fixtures/debhello-quilt/.gitignore b/test/fixtures/debhello-quilt/.gitignore new file mode 100644 index 0000000..48cfc9c --- /dev/null +++ b/test/fixtures/debhello-quilt/.gitignore @@ -0,0 +1,66 @@ + +.* +!.gitkeep +!.gitignore +tags + +*~ +*.back +# patch command backup file +*.rej +*.orig + +# cash +*~ + +# tmporary +/tmp +/temp +/gabage +/work +/object +/binary +/build +/download + +# object files +*.d +*.o +*.a +*.exe +*.app + +# object files +*.o +*.ko +*.obj +*.elf + +# libraries +*.lib +*.a +*.la +*.lo + +# shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# doxygen +/doxygen + +# debhelper +.debhelper +debian/debhello +debian/tmp +*.log +debian/debhello* +!debian/debhello.install +debian/debhelper-build-stamp +debhello +debian/files +src/hello +/gtk3_win64 + diff --git a/test/fixtures/debhello-quilt/Makefile b/test/fixtures/debhello-quilt/Makefile new file mode 100644 index 0000000..6b21508 --- /dev/null +++ b/test/fixtures/debhello-quilt/Makefile @@ -0,0 +1,25 @@ +prefix = /usr + +all: src/hello + +src/hello: src/hello.c + @echo "CFLAGS=$(CFLAGS)" | \ + fold -s -w 70 | \ + sed -e 's/^/# /' + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $^ + +install: src/hello + install -D src/hello \ + $(DESTDIR)$(prefix)/bin/hello + +clean: + -rm -f src/hello + +distclean: clean + +uninstall: + -rm -f $(DESTDIR)$(prefix)/bin/hello + +.PHONY: all install clean distclean uninstall + + diff --git a/test/fixtures/debhello-quilt/debian/changelog b/test/fixtures/debhello-quilt/debian/changelog new file mode 100644 index 0000000..326dd53 --- /dev/null +++ b/test/fixtures/debhello-quilt/debian/changelog @@ -0,0 +1,6 @@ +debhello (1.0.0-1) unstable; urgency=medium + + * debhello example + + -- Thomas Willetal Fri, 12 Aug 2022 23:09:11 +0200 + diff --git a/test/fixtures/debhello-quilt/debian/control b/test/fixtures/debhello-quilt/debian/control new file mode 100644 index 0000000..b78faf4 --- /dev/null +++ b/test/fixtures/debhello-quilt/debian/control @@ -0,0 +1,18 @@ +Source: debhello +Section: utils +Priority: optional +Maintainer: Thomas Willetal +Build-Depends: debhelper-compat (= 13) +Standards-Version: 4.7.2 +Rules-Requires-Root: no + +Package: debhello +Architecture: any +Multi-Arch: foreign +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: example package in the debmake-doc package + This is an example package to demonstrate the Debian packaging using + the debmake command. + . + The generated Debian package uses the dh command offered by the + debhelper package and the dpkg source format `3.0 (quilt)'. diff --git a/test/fixtures/debhello-quilt/debian/copyright b/test/fixtures/debhello-quilt/debian/copyright new file mode 100644 index 0000000..d5e8841 --- /dev/null +++ b/test/fixtures/debhello-quilt/debian/copyright @@ -0,0 +1,9 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: debhello +Source: + +Files: Makefile + src/hello.c +Copyright: 2016 Michinari.Nukazawa +License: Undecided + diff --git a/test/fixtures/debhello-quilt/debian/debhello.install b/test/fixtures/debhello-quilt/debian/debhello.install new file mode 100644 index 0000000..5d336f4 --- /dev/null +++ b/test/fixtures/debhello-quilt/debian/debhello.install @@ -0,0 +1 @@ +usr/bin/hello diff --git a/test/fixtures/debhello-quilt/debian/rules b/test/fixtures/debhello-quilt/debian/rules new file mode 100755 index 0000000..a603e80 --- /dev/null +++ b/test/fixtures/debhello-quilt/debian/rules @@ -0,0 +1,12 @@ +#!/usr/bin/make -f +export DH_VERBOSE = 1 +export DEB_BUILD_MAINT_OPTIONS = hardening=+all +export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic +export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed + +%: + dh $@ + +override_dh_auto_install: + dh_auto_install --destdir=debian/tmp + diff --git a/test/fixtures/debhello-quilt/debian/source/format b/test/fixtures/debhello-quilt/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/test/fixtures/debhello-quilt/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/test/fixtures/debhello-quilt/src/hello.c b/test/fixtures/debhello-quilt/src/hello.c new file mode 100644 index 0000000..092877e --- /dev/null +++ b/test/fixtures/debhello-quilt/src/hello.c @@ -0,0 +1,8 @@ +#include + +int main() +{ + printf("Hello, world!\n"); + return 0; +} + From 2cd068d2a9aacbfc88ecb79005d80a53847d7236 Mon Sep 17 00:00:00 2001 From: Thomas Willetal Date: Sun, 12 Jul 2026 13:13:51 +0200 Subject: [PATCH 2/6] Add initial robot framework test --- .gitignore | 8 ++ .vscode/tasks.json | 8 ++ test/robot/keywords/aptly.robot | 11 ++ test/robot/keywords/git.robot | 18 +++ test/robot/keywords/gpg.robot | 48 +++++++ test/robot/requirements.txt | 4 + test/robot/run.sh | 17 +++ test/robot/suites/debhello_quilt.robot | 185 +++++++++++++++++++++++++ 8 files changed, 299 insertions(+) create mode 100644 test/robot/keywords/aptly.robot create mode 100644 test/robot/keywords/git.robot create mode 100644 test/robot/keywords/gpg.robot create mode 100644 test/robot/requirements.txt create mode 100755 test/robot/run.sh create mode 100644 test/robot/suites/debhello_quilt.robot diff --git a/.gitignore b/.gitignore index bbbe7f2..c1ddb98 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,11 @@ cover/ python-test-results.xml test-output.xml *.log + +# Robot Framework artifacts +output.xml +report.html +log.html +xunit.xml +debugfile.txt +test/robot/results/ diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 18d15b8..02306a4 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -13,6 +13,14 @@ "cwd": "${workspaceFolder}/packtly-builder/tooling" }, "problemMatcher": [] + }, + { + "label": "run robot tests", + "type": "shell", + "command": "${workspaceFolder}/test/robot/run.sh", + "problemMatcher": [ + "$python" + ] } ], "inputs": [ diff --git a/test/robot/keywords/aptly.robot b/test/robot/keywords/aptly.robot new file mode 100644 index 0000000..253005b --- /dev/null +++ b/test/robot/keywords/aptly.robot @@ -0,0 +1,11 @@ +*** Settings *** +Library OperatingSystem + +*** Keywords *** +Generate Aptly Credentials + [Arguments] + ... ${path} + ... ${username}=admin + ... ${password}=password + + Create File ${path} username=${username}\npassword=${password} diff --git a/test/robot/keywords/git.robot b/test/robot/keywords/git.robot new file mode 100644 index 0000000..3340f17 --- /dev/null +++ b/test/robot/keywords/git.robot @@ -0,0 +1,18 @@ +*** Settings *** +Library Process + +*** Keywords *** +Checkout Repository + [Arguments] ${url} ${path} ${branch}=main + + ${result}= Run Process + ... git + ... clone + ... --depth + ... 1 + ... --branch + ... ${branch} + ... ${url} + ... ${path} + + Should Be Equal As Integers ${result.rc} 0 ${result.stderr} diff --git a/test/robot/keywords/gpg.robot b/test/robot/keywords/gpg.robot new file mode 100644 index 0000000..74c339a --- /dev/null +++ b/test/robot/keywords/gpg.robot @@ -0,0 +1,48 @@ +*** Settings *** +Library Process +Library String +Library OperatingSystem + +*** Variables *** +${GEN_GPG_SCRIPT} ${EMPTY} + +*** Keywords *** +Get Gen GPG Script + ${result}= Run Process git rev-parse --show-toplevel + Should Be Equal As Integers ${result.rc} 0 ${result.stderr} + ${topdir}= Strip String ${result.stdout} + RETURN ${topdir}/packtly-builder/containers/scripts/gen_gpg + +Generate GPG Keys + [Arguments] + ... ${keys_dir} + ... ${image} + ... ${name}=packtly-test + ... ${email}=test@packtly.local + ... ${pass}=test1234 + + ${gpg_out}= Set Variable ${keys_dir}/_gpg_out + ${gen_gpg}= Get Gen GPG Script + + Create Directory ${keys_dir}/public + Create Directory ${keys_dir}/private + Create Directory ${gpg_out} + + ${result}= Run Process + ... podman run --rm + ... --entrypoint /usr/local/bin/gen_gpg + ... -v ${gen_gpg}:/usr/local/bin/gen_gpg:Z,ro + ... -v ${gpg_out}:/opt/keys/gpg:Z + ... ${image} + ... --name ${name} + ... --email ${email} + ... --pass ${pass} + ... stdout=PIPE stderr=PIPE + + Should Be Equal As Integers ${result.rc} 0 ${result.stderr} + + Move File ${gpg_out}/repo_signing.key ${keys_dir}/public/repo_signing.key + Move File ${gpg_out}/repo_signing_private.key ${keys_dir}/private/repo_signing_private.key + Move File ${gpg_out}/repo_signing_private_pass ${keys_dir}/private/repo_signing_private_pass + + Remove Directory ${gpg_out} recursive=True diff --git a/test/robot/requirements.txt b/test/robot/requirements.txt new file mode 100644 index 0000000..357978a --- /dev/null +++ b/test/robot/requirements.txt @@ -0,0 +1,4 @@ +robotframework +robotframework-requests +robotframework-jsonlibrary +robotframework-pythonlibcore diff --git a/test/robot/run.sh b/test/robot/run.sh new file mode 100755 index 0000000..9f1ca25 --- /dev/null +++ b/test/robot/run.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Install robotframework if not already installed +if ! pipx list --short | grep -qx 'robotframework'; then + pipx install \ + --pip-args="-r ${ROOT}/requirements.txt" \ + robotframework +fi + +# Tests ausführen +robot \ + --outputdir "${ROOT}/results" \ + "${ROOT}/suites" + diff --git a/test/robot/suites/debhello_quilt.robot b/test/robot/suites/debhello_quilt.robot new file mode 100644 index 0000000..9bbcd1c --- /dev/null +++ b/test/robot/suites/debhello_quilt.robot @@ -0,0 +1,185 @@ +*** Settings *** +Library OperatingSystem +Library Process +Resource ../keywords/git.robot +Resource ../keywords/gpg.robot +Resource ../keywords/aptly.robot + +Suite Setup Prepare Workspace +Suite Teardown Run Keyword If '${WORKSPACE}' != '' Remove Directory ${WORKSPACE} recursive=True + + +*** Variables *** +${FIXTURES_DIR} ${CURDIR}/../../fixtures +${DEBHELLO_DIR} ${FIXTURES_DIR}/debhello-quilt +${CONTAINER_IMAGE} packtly-builder:latest +${APTLY_CREDENTIALS} ${EMPTY} +${WORKSPACE} ${EMPTY} +${KEYS_DIR} ${EMPTY} + +*** Keywords *** +Prepare Workspace + Set Suite Variable ${WORKSPACE} ${TEMPDIR}/debhello-quilt-build + Set Suite Variable ${KEYS_DIR} ${WORKSPACE}/keys + Set Suite Variable ${APTLY_CREDENTIALS} ${WORKSPACE}/aptly-credentials + Run Process git clean -fdx cwd=${FIXTURES_DIR} + Create Directory ${WORKSPACE} + Create Directory ${WORKSPACE}/logs + Generate GPG Keys ${KEYS_DIR} ${CONTAINER_IMAGE} + Generate Aptly Credentials ${APTLY_CREDENTIALS} + +Run Debhello Quilt Build + [Arguments] + ... ${workspace} + ... ${keys_dir} + ... ${aptly_credentials} + ... ${image} + ... ${dist}=trixie-apollo + ... ${component}=main + + ${result}= Run Process + ... podman run --rm + ... -v ${workspace}:/workspace:Z + ... -v ${keys_dir}/public/repo_signing.key:/opt/keys/gpg/repo_signing.key:Z,ro + ... -v ${keys_dir}/private/repo_signing_private.key:/opt/keys/gpg/repo_signing_private.key:Z,ro + ... -v ${keys_dir}/private/repo_signing_private_pass:/opt/keys/gpg/repo_signing_private_pass:Z,ro + ... -v ${aptly_credentials}:/run/secrets/aptly-credentials:Z,ro + ... -v ${workspace}/logs:/logs:Z + ... -e APTLYHOST\=http://localhost:8080 + ... --network\=host + ... ${image} + ... /workspace/debhello-quilt + ... --log-file /logs/build.log + ... --dist ${dist} + ... --component ${component} + ... --build-mode full + + Log File ${workspace}/logs/build.log + Copy File ${workspace}/logs/build.log ${CURDIR}/../results/debhello_build.log + Should Be Equal As Integers ${result.rc} 0 + ... Build failed with rc ${result.rc}. See stdout/stderr and build.log above. + + +Verify Build Artifacts + [Documentation] Verify a successful build produced valid .changes and .deb artifacts. + [Arguments] ${workspace} ${image} + + # A successful debuild leaves the .changes and .deb files in the workspace. + ${changes}= List Files In Directory ${workspace} *.changes absolute=True + Should Not Be Empty ${changes} No .changes file produced - build did not complete + ${debs}= List Files In Directory ${workspace} *.deb absolute=True + Should Not Be Empty ${debs} No .deb packages produced + + # Validate each .deb is a structurally valid Debian package. + FOR ${deb} IN @{debs} + ${info}= Run Process + ... podman run --rm + ... --entrypoint dpkg-deb + ... -v ${workspace}:/workspace:Z,ro + ... ${image} + ... --info /workspace/${deb.rsplit('/', 1)[1]} + Log ${info.stdout} + Should Be Equal As Integers ${info.rc} 0 + ... dpkg-deb rejected ${deb}: ${info.stderr} + END + +Verify Changes Signature + [Arguments] ${workspace} ${keys_dir} ${image} + + ${changes}= List Files In Directory ${workspace} *.changes absolute=True + Length Should Be ${changes} 1 + + ${changes_file}= Set Variable ${changes[0].rsplit('/',1)[1]} + ${cmd}= Set Variable + ... gpg --batch --import /tmp/repo_signing.key >/dev/null 2>&1 && gpg --status-fd\=1 --verify /workspace/${changes_file} + ${result}= Run Process + ... podman run --rm + ... -v ${workspace}:/workspace:Z,ro + ... -v ${keys_dir}/public/repo_signing.key:/tmp/repo_signing.key:Z,ro + ... --entrypoint sh + ... ${image} + ... -c ${cmd} + + Log ${result.stdout} + Log ${result.stderr} + + Should Be Equal As Integers ${result.rc} 0 GPG verification failed! Check logs. + Should Contain ${result.stdout} [GNUPG:] GOODSIG + Should Contain ${result.stdout} [GNUPG:] VALIDSIG + +Verify Source Package Artifacts + [Documentation] Verify source package artifacts (.dsc + referenced tarballs) exist and pass dpkg-source integrity check. + [Arguments] ${workspace} ${image} + + ${dscs}= List Files In Directory ${workspace} *.dsc absolute=True + Should Not Be Empty ${dscs} No .dsc file produced - source package missing + + ${dsc_file}= Set Variable ${dscs[0].rsplit('/', 1)[1]} + ${result}= Run Process + ... podman run --rm + ... --entrypoint sh + ... -v ${workspace}:/workspace:Z,ro + ... ${image} + ... -c dpkg-source -x /workspace/${dsc_file} /tmp/src-check && rm -rf /tmp/src-check + + Log ${result.stdout} + Log ${result.stderr} + Should Be Equal As Integers ${result.rc} 0 + ... dpkg-source -x failed for ${dsc_file}: ${result.stderr} + +Verify DSC Signature + [Arguments] ${workspace} ${keys_dir} ${image} + + ${dscs}= List Files In Directory ${workspace} *.dsc absolute=True + Length Should Be ${dscs} 1 + + ${dsc_file}= Set Variable ${dscs[0].rsplit('/', 1)[1]} + ${cmd}= Set Variable + ... gpg --batch --import /tmp/repo_signing.key >/dev/null 2>&1 && gpg --status-fd\=1 --verify /workspace/${dsc_file} + ${result}= Run Process + ... podman run --rm + ... -v ${workspace}:/workspace:Z,ro + ... -v ${keys_dir}/public/repo_signing.key:/tmp/repo_signing.key:Z,ro + ... --entrypoint sh + ... ${image} + ... -c ${cmd} + + Log ${result.stdout} + Log ${result.stderr} + + Should Be Equal As Integers ${result.rc} 0 GPG verification of .dsc failed! Check logs. + Should Contain ${result.stdout} [GNUPG:] GOODSIG + Should Contain ${result.stdout} [GNUPG:] VALIDSIG + + +*** Test Cases *** + +Debhello Quilt Build + [Documentation] Test building debhello package with packtly-builder + [Tags] debhello build + Copy Directory ${FIXTURES_DIR}/debhello-quilt ${WORKSPACE}/debhello-quilt + Run Debhello Quilt Build + ... ${WORKSPACE} + ... ${KEYS_DIR} + ... ${APTLY_CREDENTIALS} + ... image=${CONTAINER_IMAGE} + +Binary Packages Are Valid + [Documentation] Verify .changes and .deb artifacts were produced and are structurally valid. + [Tags] debhello build binary + Verify Build Artifacts ${WORKSPACE} ${CONTAINER_IMAGE} + +Changes File Is Signed + [Documentation] Verify the .changes file carries a valid GPG signature. + [Tags] debhello build signature + Verify Changes Signature ${WORKSPACE} ${KEYS_DIR} ${CONTAINER_IMAGE} + +Source Package Is Valid + [Documentation] Verify the .dsc and referenced source tarballs pass dpkg-source integrity check. + [Tags] debhello build source + Verify Source Package Artifacts ${WORKSPACE} ${CONTAINER_IMAGE} + +DSC File Is Signed + [Documentation] Verify the .dsc file carries a valid GPG signature. + [Tags] debhello build signature source + Verify DSC Signature ${WORKSPACE} ${KEYS_DIR} ${CONTAINER_IMAGE} From d17b20e7261ecfa9a90158f701c672f7d0576ce0 Mon Sep 17 00:00:00 2001 From: Thomas Willetal Date: Sun, 12 Jul 2026 13:59:14 +0200 Subject: [PATCH 3/6] Add GitHub Actions workflow for Robot Framework tests --- .github/actions/setup-podman/action.yml | 8 +++ .github/workflows/_robot-tests.yml | 66 +++++++++++++++++++++++++ .github/workflows/_tooling.yml | 17 +++++-- .github/workflows/ci-build.yml | 10 ++++ 4 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/_robot-tests.yml diff --git a/.github/actions/setup-podman/action.yml b/.github/actions/setup-podman/action.yml index 954140f..13bf1f6 100644 --- a/.github/actions/setup-podman/action.yml +++ b/.github/actions/setup-podman/action.yml @@ -101,6 +101,14 @@ runs: systemctl --user enable --now podman.socket echo "DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock" >> $GITHUB_ENV + - name: Expose Podman socket as /var/run/docker.sock + shell: bash + run: | + # GitHub Actions container-based actions mount /var/run/docker.sock + # hardcoded. Symlink it to the Podman socket so those actions work. + sudo ln -sf "$XDG_RUNTIME_DIR/podman/podman.sock" /var/run/docker.sock +# sudo chmod 666 "$XDG_RUNTIME_DIR/podman/podman.sock" + - name: Verify Podman and podman-compose shell: bash run: | diff --git a/.github/workflows/_robot-tests.yml b/.github/workflows/_robot-tests.yml new file mode 100644 index 0000000..28cd643 --- /dev/null +++ b/.github/workflows/_robot-tests.yml @@ -0,0 +1,66 @@ +name: Robot Tests + +on: + workflow_call: + inputs: + release_version: + required: true + type: string + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + robot-tests: + runs-on: ubuntu-24.04 + + steps: + - name: Checkout repository + uses: actions/checkout@v7 + + - name: Set up Podman + uses: ./.github/actions/setup-podman + + - name: Login to ghcr.io + run: | + echo "${{ secrets.GITHUB_TOKEN }}" | \ + podman login ghcr.io \ + -u "${{ github.actor }}" \ + --password-stdin + + - name: Download runtime image (amd64) + uses: actions/download-artifact@v8 + with: + name: runtime-image-amd64 + + - name: Load runtime image + run: | + zstd -d runtime.tar.zst -o runtime.tar + podman load < runtime.tar + podman images + podman tag \ + ghcr.io/${{ github.repository }}:latest-amd64 \ + packtly-builder:latest + + - name: Run Robot Framework tests + run: ./test/robot/run.sh + + - name: Fix step summary permissions for Robot Reporter + if: always() + run: chmod o+w "$(dirname "$GITHUB_STEP_SUMMARY")" + + - name: Robot Reporter + if: always() && github.event_name == 'pull_request' + uses: joonvena/robotframework-reporter-action@v2.5 + with: + gh_access_token: ${{ secrets.GITHUB_TOKEN }} + report_path: test/robot/results + + - name: Upload Robot results + if: always() + uses: actions/upload-artifact@v7 + with: + name: robot-results + path: test/robot/results + if-no-files-found: warn + retention-days: 7 diff --git a/.github/workflows/_tooling.yml b/.github/workflows/_tooling.yml index 26d1db4..f8a7629 100644 --- a/.github/workflows/_tooling.yml +++ b/.github/workflows/_tooling.yml @@ -45,13 +45,20 @@ jobs: command: just build release-version: ${{ inputs.release_version }} - - name: Publish test results - uses: dorny/test-reporter@v3 + - name: Publish Unit Test Results + uses: mikepenz/action-junit-report@v6 if: always() with: - name: Pytest Results - path: packtly-builder/tooling/python-test-results.xml - reporter: python-xunit + comment: true + detailed_summary: true + group_suite: true + include_passed: true + include_time_in_summary: true + job_summary: true + report_paths: packtly-builder/tooling/python-test-results.xml + simplified_summary: false + skip_success_summary: false + updateComment: true - name: Coverage summary uses: orgoro/coverage@ca0c362dc1a4f100447309405e6dfea47e251495 diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 969ac8d..8211b86 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -63,3 +63,13 @@ jobs: permissions: packages: write + robot-tests: + needs: + - runtime-manifest + uses: ./.github/workflows/_robot-tests.yml + with: + release_version: ${{ needs.version.outputs.release_version }} + secrets: inherit + permissions: + checks: write + pull-requests: write From 6f9b3503106585419b60d4b1f1d61ce29592c848 Mon Sep 17 00:00:00 2001 From: Thomas Willetal Date: Sun, 12 Jul 2026 14:02:13 +0200 Subject: [PATCH 4/6] Enhance error handling in package build process --- .../tooling/packtly_builder_tooling/cli.py | 8 ++- .../packtly_builder_tooling/parts/apt.py | 61 +++++++++++++++---- .../packtly_builder_tooling/parts/debuild.py | 2 +- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/packtly-builder/tooling/packtly_builder_tooling/cli.py b/packtly-builder/tooling/packtly_builder_tooling/cli.py index 3067d26..b6e5d44 100755 --- a/packtly-builder/tooling/packtly_builder_tooling/cli.py +++ b/packtly-builder/tooling/packtly_builder_tooling/cli.py @@ -145,8 +145,12 @@ def build_package( logger.info("Skipping build step (--no-build)") return dbuild - dbuild.install_build_dependencies() - dbuild.build(mode=build_mode) + try: + dbuild.install_build_dependencies() + dbuild.build(mode=build_mode) + except FileNotFoundError as exc: + logger.error("Build failed: %s", exc) + raise SystemExit(1) from exc logger.info("Changes file: %s", dbuild.deb_changes_file()) logger.info("Architecture: %s", dbuild.deb_changes_arch()) diff --git a/packtly-builder/tooling/packtly_builder_tooling/parts/apt.py b/packtly-builder/tooling/packtly_builder_tooling/parts/apt.py index 3caf75a..30be388 100644 --- a/packtly-builder/tooling/packtly_builder_tooling/parts/apt.py +++ b/packtly-builder/tooling/packtly_builder_tooling/parts/apt.py @@ -193,24 +193,58 @@ def install_dependencies( return False package_name, req_version, req_relation = parsed[0][0] + self.cache.open() + is_virtual = package_name not in self.cache + resolved_name: Optional[str] = None + if req_version and req_relation: - self.cache.open() resolved_name = self._resolve_package_name(package_name) if resolved_name is None: self.logger.error("Package '%s' not found in cache.", package_name) return False - pkg = self.cache[resolved_name] - candidate = pkg.candidate - if not apt_pkg.check_dep(candidate.version, req_relation, req_version): - self.logger.error( - "Package '%s' candidate %s does not satisfy %s %s", - resolved_name, - candidate.version, - req_relation, - req_version, - ) + if is_virtual: + # For virtual packages the version constraint applies to the + # *provided* version, not the real provider's version. Check + # that at least one provides entry satisfies the constraint. + try: + apt_pkg_entry = self.cache._cache[package_name] + satisfied = any( + prov[1] + and apt_pkg.check_dep(prov[1], req_relation, req_version) + for prov in apt_pkg_entry.provides_list + if prov[2].parent_pkg.name == resolved_name + ) + except (KeyError, AttributeError): + satisfied = False + if not satisfied: + self.logger.error( + "No provider for '%s %s %s' found in cache.", + package_name, + req_relation, + req_version, + ) + return False + else: + pkg = self.cache[resolved_name] + candidate = pkg.candidate + if not apt_pkg.check_dep(candidate.version, req_relation, req_version): + self.logger.error( + "Package '%s' candidate %s does not satisfy %s %s", + resolved_name, + candidate.version, + req_relation, + req_version, + ) + return False + + if is_virtual: + # Install the real provider; do not pin to the virtual version. + install_name = resolved_name or self._resolve_package_name(package_name) + if install_name is None: + self.logger.error("Package '%s' not found in cache.", package_name) return False + return self.install_package(install_name, source_host=source_host) pinned_version = req_version if req_relation in ("=", "==") else None @@ -433,11 +467,12 @@ def _resolve_package_name(self, package_name: str) -> Optional[str]: if package_name in self.cache: return package_name - # The name may be a virtual package. Walk rev_provides_list to + # The name may be a virtual package. Walk provides_list to # find a real package that satisfies it. + # provides_list entries are tuples: (virtual_name, provided_version, apt_pkg.Version) try: apt_pkg_entry = self.cache._cache[package_name] - providers = [v.parent_pkg.name for v in apt_pkg_entry.rev_provides_list] + providers = [v[2].parent_pkg.name for v in apt_pkg_entry.provides_list] except (KeyError, AttributeError): providers = [] diff --git a/packtly-builder/tooling/packtly_builder_tooling/parts/debuild.py b/packtly-builder/tooling/packtly_builder_tooling/parts/debuild.py index af4a974..925f7b2 100644 --- a/packtly-builder/tooling/packtly_builder_tooling/parts/debuild.py +++ b/packtly-builder/tooling/packtly_builder_tooling/parts/debuild.py @@ -31,7 +31,7 @@ def __init__(self, builddir: Path) -> None: self.parsed_control_info = Deb822() self.parsed_deb_info = Deb822() if debuild_executable: - print("debuild executable found at:", debuild_executable) + logger.info("debuild executable found at: %s", debuild_executable) self._debuild = debuild_executable self._builddir = builddir self._outdir = Path(builddir).parent.resolve() From 3971403d32a4076d7532ee4b8cf01e0462e98231 Mon Sep 17 00:00:00 2001 From: Thomas Willetal Date: Sun, 12 Jul 2026 17:51:05 +0200 Subject: [PATCH 5/6] Adjust code configurations for packtly build and upload tasks --- .vscode/launch.json | 12 ++++++------ .vscode/tasks.json | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 2ffe036..a4476bf 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,7 +2,7 @@ "version": "0.2.0", "configurations": [ { - "name": "builder_tooling_upload", + "name": "packtly_build_full", "stopOnEntry": true, "type": "debugpy", "request": "launch", @@ -13,16 +13,14 @@ "--credentials-file=${workspaceFolder}/test/aptly-credentials", "--dist=trixie-apollo", "--component=main", - "--no-build", "--build-mode=full", - "--upload", - "${workspaceFolder}/test/debhello", + "${workspaceFolder}/test/fixtures/debhello-quilt", ], "console": "integratedTerminal", "justMyCode": false }, { - "name": "builder_tooling_build_full", + "name": "packtly_upload", "stopOnEntry": true, "type": "debugpy", "request": "launch", @@ -33,8 +31,10 @@ "--credentials-file=${workspaceFolder}/test/aptly-credentials", "--dist=trixie-apollo", "--component=main", + "--no-build", "--build-mode=full", - "${workspaceFolder}/test/debhello", + "--upload", + "${workspaceFolder}/test/fixtures/debhello-quilt", ], "console": "integratedTerminal", "justMyCode": false diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 02306a4..99be25a 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -21,6 +21,44 @@ "problemMatcher": [ "$python" ] + }, + { + "label": "packtly_build_full", + "type": "shell", + "command": "/opt/venv/bin/python", + "args": [ + "-m", "packtly_builder_tooling.cli", + "--aptlyhost=http://localhost:8080", + "--credentials-file=${workspaceFolder}/test/aptly-credentials", + "--dist=trixie-apollo", + "--component=main", + "--build-mode=full", + "${workspaceFolder}/test/fixtures/debhello-quilt" + ], + "options": { + "cwd": "${workspaceFolder}/packtly-builder/tooling" + }, + "problemMatcher": [] + }, + { + "label": "packtly_upload", + "type": "shell", + "command": "/opt/venv/bin/python", + "args": [ + "-m", "packtly_builder_tooling.cli", + "--aptlyhost=http://localhost:8080", + "--credentials-file=${workspaceFolder}/test/aptly-credentials", + "--dist=trixie-apollo", + "--component=main", + "--no-build", + "--build-mode=full", + "--upload", + "${workspaceFolder}/test/fixtures/debhello-quilt" + ], + "options": { + "cwd": "${workspaceFolder}/packtly-builder/tooling" + }, + "problemMatcher": [] } ], "inputs": [ From 2f4bcaa92828b75514f856b1773897c0d07a79b0 Mon Sep 17 00:00:00 2001 From: Thomas Willetal Date: Mon, 13 Jul 2026 07:13:18 +0200 Subject: [PATCH 6/6] Changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad9e43b..fc7cefc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,14 @@ RegEx for release version from file r"^\#\# \[\d{1,}[.]\d{1,}[.]\d{1,}\] \- \d{4}\-\d{2}-\d{2}$" --> +## [1.3.0] - 2026-07-13 +### Added +- Robot Framework integration test environment for end-to-end validation of packtly-builder builds via Podman +- Robot test runner, keywords, and a Debian example build/verification suite +- Debian packaging fixtures (`test/fixtures/debhello-quilt`) for integration testing +- CI workflow for running Robot Framework tests with artifact upload and PR reporting via `robotframework-reporter-action` + + ## [1.2.0] - 2026-07-04 ### Added - Source package build