From 7d8a929e2df51d868aa8fa88323c824d81d83345 Mon Sep 17 00:00:00 2001 From: Thomas Willetal Date: Thu, 16 Jul 2026 11:11:21 +0200 Subject: [PATCH 1/3] ROF test with packtly backend --- test/robot/keywords/aptly.resource | 136 +++++++++++ test/robot/keywords/utils.resource | 33 +++ test/robot/suites/debhello_aptly.robot | 248 ++++++++++++++++++++ test/robot/suites/packtly-infra.compose.yml | 27 +++ 4 files changed, 444 insertions(+) create mode 100644 test/robot/keywords/utils.resource create mode 100644 test/robot/suites/debhello_aptly.robot create mode 100644 test/robot/suites/packtly-infra.compose.yml diff --git a/test/robot/keywords/aptly.resource b/test/robot/keywords/aptly.resource index b3ad4c1..6150659 100644 --- a/test/robot/keywords/aptly.resource +++ b/test/robot/keywords/aptly.resource @@ -1,9 +1,23 @@ *** Settings *** Documentation Keywords for generating Aptly credentials used in integration tests. Library OperatingSystem +Library Process +Library String *** Keywords *** +Create Packtly Data Volume + [Documentation] Create the external Podman volume used by the Packtly Infra container. + [Arguments] ${volume} + Run Process podman volume rm --force ${volume} + ${result}= Run Process podman volume create ${volume} + Should Be Equal As Integers ${result.rc} 0 ${result.stderr} + +Remove Packtly Data Volume + [Documentation] Remove the Podman volume created for this test suite. + [Arguments] ${volume} + Run Process podman volume rm --force ${volume} + Generate Aptly Credentials [Documentation] Generate a simple aptly credentials file [Arguments] ${path} @@ -11,3 +25,125 @@ Generate Aptly Credentials ... ${password}=password Create File ${path} username=${username}\npassword=${password} + +Generate Packtly Htpasswd + [Documentation] Generate a Packtly basic-auth file using the Packtly Compose service. + [Arguments] ${compose_file} + ... ${project_name} + ... ${username}=admin + ... ${password}=password + + ${result}= Run Process + ... podman-compose + ... --file ${compose_file} + ... --project-name ${project_name} + ... run --no-deps --rm -T + ... --entrypoint /usr/local/bin/gen_htpasswd + ... packtly + ... ${username} + ... ${password} + Log ${result.stdout} + Log ${result.stderr} + Should Be Equal As Integers ${result.rc} 0 ${result.stderr} + +Get Podman Volume Mountpoint + [Documentation] Return the host mountpoint of a Podman volume. + [Arguments] ${volume} + + ${result}= Run Process + ... podman volume inspect + ... --format {{.Mountpoint}} + ... ${volume} + Should Be Equal As Integers ${result.rc} 0 ${result.stderr} + ${mountpoint}= Strip String ${result.stdout} + RETURN ${mountpoint} + +Install Packtly Public Files + [Documentation] Copy the GPG public signing key directly into the Packtly data volume's mountpoint. + ... The infra service reads it from /opt/packtly/public/repo_signing.key. + [Arguments] ${volume} ${public_key} + + ${mountpoint}= Get Podman Volume Mountpoint ${volume} + Create Directory ${mountpoint}/public + Copy File ${public_key} ${mountpoint}/public/repo_signing.key + +Import Podman Secret + [Documentation] Replace a Podman secret with the contents of ${secret_file}. + [Arguments] ${secret_name} ${secret_file} + + Run Process podman secret rm --ignore ${secret_name} + ${result}= Run Process + ... podman secret create + ... ${secret_name} + ... ${secret_file} + Should Be Equal As Integers ${result.rc} 0 ${result.stderr} + +Remove Podman Secret + [Documentation] Remove a Podman secret. + [Arguments] ${secret_name} + + Run Process podman secret rm --ignore ${secret_name} + +Start Podman Compose Service + [Documentation] Start services from ${compose_file} in the background. + [Arguments] ${compose_file} ${project_name} + + ${result}= Run Process + ... podman-compose + ... --file ${compose_file} + ... --project-name ${project_name} + ... up --detach + Log ${result.stdout} + Log ${result.stderr} + Should Be Equal As Integers ${result.rc} 0 ${result.stderr} + +Stop Podman Compose Service + [Documentation] Stop services from ${compose_file} without removing external resources. + [Arguments] ${compose_file} ${project_name} + + Run Process + ... podman-compose + ... --file ${compose_file} + ... --project-name ${project_name} + ... down + +Exec In Packtly Service + [Documentation] Execute a command inside the running Packtly Infra service container. + [Arguments] ${compose_file} ${project_name} @{command} + + ${result}= Run Process + ... podman-compose + ... --file ${compose_file} + ... --project-name ${project_name} + ... exec -T packtly @{command} + Log ${result.stdout} + Log ${result.stderr} + Should Be Equal As Integers ${result.rc} 0 ${result.stderr} + +Wait Until Packtly Service Ready + [Documentation] Wait until the Packtly Infra service accepts exec calls. + [Arguments] ${compose_file} ${project_name} ${timeout}=30s ${retry_interval}=2s + + Wait Until Keyword Succeeds ${timeout} ${retry_interval} + ... Exec In Packtly Service ${compose_file} ${project_name} true + +Import Packtly GPG Key + [Documentation] Import the GPG signing key into the running Packtly Infra service. + [Arguments] ${compose_file} ${project_name} + + Exec In Packtly Service ${compose_file} ${project_name} /usr/local/bin/entrypoint_gpg + +Create Packtly Repo + [Documentation] Create an Aptly repository in the running Packtly Infra service. + [Arguments] ${compose_file} ${project_name} ${repo} + + Exec In Packtly Service ${compose_file} ${project_name} + ... create_repo -d ${repo}[dist] -c ${repo}[component] + ... -m ${repo}[description] -n ${repo}[name] + +Publish Packtly Repos + [Documentation] Publish one or more Aptly repositories in the running Packtly Infra service. + [Arguments] ${compose_file} ${project_name} @{repo_names} + + ${repos}= Catenate SEPARATOR=, @{repo_names} + Exec In Packtly Service ${compose_file} ${project_name} publish_repo -r ${repos} diff --git a/test/robot/keywords/utils.resource b/test/robot/keywords/utils.resource new file mode 100644 index 0000000..a92d4d8 --- /dev/null +++ b/test/robot/keywords/utils.resource @@ -0,0 +1,33 @@ +*** Settings *** +Documentation Common utility keywords for Robot Framework integration tests. +Library OperatingSystem +Library Process +Library String + + +*** Keywords *** +Run Process And Log + [Documentation] Run a process and log the return code, stdout, and stderr. + [Arguments] @{command} + + ${result}= Run Process @{command} + + Log RC: ${result.rc} + Log STDOUT:\n${result.stdout} + Log STDERR:\n${result.stderr} + + Should Be Equal As Integers ${result.rc} 0 + + RETURN ${result} + +Execute In Test Container + [Documentation] Execute a shell command inside a container. + [Arguments] ${container} ${command} + + Run Process And Log + ... podman + ... exec + ... ${container} + ... sh + ... -c + ... ${command} diff --git a/test/robot/suites/debhello_aptly.robot b/test/robot/suites/debhello_aptly.robot new file mode 100644 index 0000000..b54dff2 --- /dev/null +++ b/test/robot/suites/debhello_aptly.robot @@ -0,0 +1,248 @@ +*** Settings *** +Documentation Integration tests for building and verifying a debhello quilt-format Debian package. +... The package is built with packtly-builder. +Library OperatingSystem +Library Process +Resource ../keywords/git.resource +Resource ../keywords/gpg.resource +Resource ../keywords/aptly.resource +Resource ../keywords/utils.resource + +Suite Setup Prepare Test Environment +Suite Teardown Cleanup Test Environment + + +*** Variables *** +${FIXTURES_DIR} ${CURDIR}/../../fixtures +${DEBHELLO_DIR} ${FIXTURES_DIR}/debhello-quilt +${CONTAINER_IMAGE} packtly-builder:latest +${WORKSPACE} ${TEMPDIR}/debhello-aptly-build +${KEYS_DIR} ${WORKSPACE}/keys +${PACKTLY_CREDENTIALS} ${WORKSPACE}/aptly-credentials +${PACKTLY_GPG_KEY_SECRET} packtly_gpg_private_key +${PACKTLY_GPG_PASS_SECRET} packtly_gpg_passphrase +${PACKTLY_DATA_VOLUME} robot_debhello_aptly_data +${PACKTLY_USER} admin +${PACKTLY_PASSWORD} password +${PACKTLY_COMPOSE_FILE} ${CURDIR}/packtly-infra.compose.yml +${PACKTLY_COMPOSE_PROJECT} robot-debhello-aptly +${PACKTLY_NETWORK} robot_debhello_aptly_net +&{PACKTLY_REPO} dist=trixie-apollo +... component=main +... description=Debhello Aptly test repo +... name=trixie-apollo-main +${TEST_CONTAINER} robot-debhello-install + + +*** Test Cases *** +Debhello Quilt Build + [Documentation] Test building debhello package with packtly-builder + [Tags] build + Run Debhello Quilt Build + +Packtly Infra Repository Is Accessible + [Documentation] Verify the Packtly Apt repository is accessible from a Debian container. + [Tags] install + Start Debian Test Container + Import Repository Key + Configure Debian Apt Repository + +Install Binary Package + [Documentation] Verify the debhello package can be installed from the Packtly Apt repository. + [Tags] install + Execute In Test Container + ... ${TEST_CONTAINER} + ... apt-get install -y debhello + + Execute In Test Container + ... ${TEST_CONTAINER} + ... dpkg -s debhello + + Execute In Test Container + ... ${TEST_CONTAINER} + ... hello + +Download Source Package + [Documentation] Verify the debhello source package can be downloaded from the Packtly Apt repository. + [Tags] install + Execute In Test Container + ... ${TEST_CONTAINER} + ... apt-get source debhello + + +*** Keywords *** +Remove Generated GPG Secrets + [Documentation] Remove the Podman secrets created for this test suite. + Remove Podman Secret + ... ${PACKTLY_GPG_KEY_SECRET} + Remove Podman Secret + ... ${PACKTLY_GPG_PASS_SECRET} + +Cleanup Packtly Infra Container + [Documentation] Stop the packtly infra container and remove its data volume. + Stop Podman Compose Service + ... ${PACKTLY_COMPOSE_FILE} + ... ${PACKTLY_COMPOSE_PROJECT} + Remove Generated GPG Secrets + Remove Packtly Data Volume + ... ${PACKTLY_DATA_VOLUME} + +Cleanup Test Environment + [Documentation] Cleanup the temporary workspace after the debhello-aptly build test. + Cleanup Packtly Infra Container + Stop Debian Test Container + IF '${WORKSPACE}' != '' + Remove Directory ${WORKSPACE} recursive=True + END + +Import Generated GPG Secrets + [Documentation] Import the generated GPG private key and passphrase as Podman secrets. + Import Podman Secret + ... ${PACKTLY_GPG_KEY_SECRET} + ... ${KEYS_DIR}/private/repo_signing_private.key + Import Podman Secret + ... ${PACKTLY_GPG_PASS_SECRET} + ... ${KEYS_DIR}/private/repo_signing_private_pass + +Prepare Packtly Infra Container + [Documentation] Prepare the packtly infra container + + Cleanup Packtly Infra Container + Prepare Packtly Key Material + Prepare Packtly Data Volume + Start And Configure Packtly Service + +Prepare Packtly Key Material + [Documentation] Generate the signing key and import its private parts as Podman secrets. + Generate GPG Keys ${KEYS_DIR} ${CONTAINER_IMAGE} + Import Generated GPG Secrets + +Prepare Packtly Data Volume + [Documentation] Populate a newly created Packtly data volume with public configuration. + Create Packtly Data Volume + ... ${PACKTLY_DATA_VOLUME} + Install Packtly Public Files + ... ${PACKTLY_DATA_VOLUME} + ... ${KEYS_DIR}/public/repo_signing.key + Generate Packtly Htpasswd + ... ${PACKTLY_COMPOSE_FILE} + ... ${PACKTLY_COMPOSE_PROJECT} + ... ${PACKTLY_USER} + ... ${PACKTLY_PASSWORD} + Generate Aptly Credentials + ... ${PACKTLY_CREDENTIALS} + ... ${PACKTLY_USER} + ... ${PACKTLY_PASSWORD} + +Start And Configure Packtly Service + [Documentation] Start Packtly and create its published Aptly repository. + Start Podman Compose Service + ... ${PACKTLY_COMPOSE_FILE} + ... ${PACKTLY_COMPOSE_PROJECT} + Wait Until Packtly Service Ready + ... ${PACKTLY_COMPOSE_FILE} + ... ${PACKTLY_COMPOSE_PROJECT} + Import Packtly GPG Key + ... ${PACKTLY_COMPOSE_FILE} + ... ${PACKTLY_COMPOSE_PROJECT} + Create Packtly Repo + ... ${PACKTLY_COMPOSE_FILE} + ... ${PACKTLY_COMPOSE_PROJECT} + ... ${PACKTLY_REPO} + Publish Packtly Repos + ... ${PACKTLY_COMPOSE_FILE} + ... ${PACKTLY_COMPOSE_PROJECT} + ... ${PACKTLY_REPO}[name] + +Prepare Test Environment + [Documentation] Prepare a temporary workspace for the debhello-aptly build test. + Run Process git clean -fdx cwd=${FIXTURES_DIR} + Create Directory ${WORKSPACE} + Create Directory ${WORKSPACE}/logs + Prepare Packtly Infra Container + Copy Directory ${DEBHELLO_DIR} ${WORKSPACE}/debhello-quilt + +Run Debhello Quilt Build + [Documentation] packtly-builder build of the debhello-quilt package inside a container. + [Arguments] ${dist}=${PACKTLY_REPO}[dist] + ... ${component}=${PACKTLY_REPO}[component] + + ${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 ${PACKTLY_CREDENTIALS}:/run/secrets/aptly-credentials:Z,ro + ... -v ${WORKSPACE}/logs:/logs:Z + ... -e APTLYHOST\=http://packtly:80 + ... --network ${PACKTLY_NETWORK} + ... ${CONTAINER_IMAGE} + ... /workspace/debhello-quilt + ... --log-file /logs/build.log + ... --dist ${dist} + ... --component ${component} + ... --build-mode full + ... --upload + + Log File ${WORKSPACE}/logs/build.log + Copy File ${WORKSPACE}/logs/build.log ${CURDIR}/../results/debhello_aptly.log + Should Be Equal As Integers ${result.rc} 0 + ... Build failed with rc ${result.rc}. See stdout/stderr and build.log above. + +Start Debian Test Container + [Documentation] Start a Debian container for testing the installation of the debhello package + [Tags] install + ${result}= Run Process + ... podman run -d + ... --name ${TEST_CONTAINER} + ... --network ${PACKTLY_NETWORK} + ... debian:trixie + ... sleep infinity + Should Be Equal As Integers ${result.rc} 0 + +Import Repository Key + [Documentation] Import the Packtly repository signing key into the Debian test container. + [Tags] install + Execute In Test Container + ... ${TEST_CONTAINER} + ... apt-get update && apt-get install -y gnupg wget dpkg-dev + + ${keyring_cmd}= Catenate SEPARATOR=${EMPTY} + ... wget -O- http://packtly:80/repo_signing.key + ... | gpg --dearmor + ... > /usr/share/keyrings/packtly-archive-keyring.gpg + + Execute In Test Container + ... ${TEST_CONTAINER} + ... bash -c "${keyring_cmd}" + +Configure Debian Apt Repository + [Documentation] Configure the Debian test container to use the Packtly Apt repository. + [Tags] install + + ${sources}= Catenate SEPARATOR=\n + ... Types: deb deb-src + ... URIs: http://packtly:80 + ... Suites: ${PACKTLY_REPO}[dist] + ... Components: ${PACKTLY_REPO}[component] + ... Signed-By: /usr/share/keyrings/packtly-archive-keyring.gpg + + ${cmd}= Catenate SEPARATOR=${EMPTY} + ... cat <<'EOF' > /etc/apt/sources.list.d/packtly.sources + ... \n${sources} + ... \nEOF + + Execute In Test Container + ... ${TEST_CONTAINER} + ... bash -c "${cmd}" + + Execute In Test Container + ... ${TEST_CONTAINER} + ... apt-get update + +Stop Debian Test Container + [Documentation] Stop and remove the Debian test container. + [Tags] install + Run Process + ... podman rm -f ${TEST_CONTAINER} diff --git a/test/robot/suites/packtly-infra.compose.yml b/test/robot/suites/packtly-infra.compose.yml new file mode 100644 index 0000000..4ce0408 --- /dev/null +++ b/test/robot/suites/packtly-infra.compose.yml @@ -0,0 +1,27 @@ +version: "4" +services: + packtly: + image: ghcr.io/packtly/packtly-infra:1.1.0 + networks: + - packtlynet + volumes: + - packtly_data:/opt/packtly + secrets: + - packtly_gpg_private_key + - packtly_gpg_passphrase + +secrets: + packtly_gpg_private_key: + external: true + packtly_gpg_passphrase: + external: true + +volumes: + packtly_data: + external: true + name: robot_debhello_aptly_data + +networks: + packtlynet: + driver: bridge + name: robot_debhello_aptly_net From 7ae2ae1134d95292cdd1125b530255d85edf6cfa Mon Sep 17 00:00:00 2001 From: Thomas Willetal Date: Mon, 20 Jul 2026 18:44:33 +0200 Subject: [PATCH 2/3] Change log level from warning to info for missing upstream files in is_already_deployed function --- packtly-builder/tooling/packtly_builder_tooling/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packtly-builder/tooling/packtly_builder_tooling/cli.py b/packtly-builder/tooling/packtly_builder_tooling/cli.py index b6e5d44..a6cc60b 100755 --- a/packtly-builder/tooling/packtly_builder_tooling/cli.py +++ b/packtly-builder/tooling/packtly_builder_tooling/cli.py @@ -75,7 +75,7 @@ def is_already_deployed( if aptmanager.upstream_file_exists(Path(f), source_host=aptlyhost): logger.info("[EXISTS] %s is already deployed upstream", Path(f).name) else: - logger.warning("[MISSING] %s is not deployed upstream", Path(f).name) + logger.info("[NEW] %s is not deployed upstream", Path(f).name) upstream_exists = False if not upstream_exists: From f7cb5ae0fc9fedfac4534985edfce0c45b889eff Mon Sep 17 00:00:00 2001 From: Thomas Willetal Date: Wed, 22 Jul 2026 06:53:19 +0200 Subject: [PATCH 3/3] changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc7cefc..916eb6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ RegEx for release version from file r"^\#\# \[\d{1,}[.]\d{1,}[.]\d{1,}\] \- \d{4}\-\d{2}-\d{2}$" --> +## [1.3.1] - 2026-07-22 +### Fixed +- Change log level from warning to info for missing upstream files in is_already_deployed function + ## [1.3.0] - 2026-07-13 ### Added - Robot Framework integration test environment for end-to-end validation of packtly-builder builds via Podman