diff --git a/.github/scripts/deb-install-test.sh b/.github/scripts/deb-install-test.sh new file mode 100755 index 000000000..d60648eea --- /dev/null +++ b/.github/scripts/deb-install-test.sh @@ -0,0 +1,270 @@ +#!/bin/bash +# ────────────────────────────────────────────────────────────────────────────── +# DEB Package Installation Test for Devolutions Gateway +# +# Runs inside an Ubuntu container to validate: +# - Package installs correctly via dpkg/apt +# - Expected files and directories are present +# - Binary is functional (--help, --config-init-only) +# - systemd unit file is installed (part of the .deb package) +# - Default configuration file is generated +# +# LIMITATION — systemd in containers: +# Docker containers do not normally run systemd, so the postinst script +# skips config initialization and service enablement (both gated on +# /run/systemd/system). This script compensates by running +# --config-init-only manually. Full service start/stop validation is +# best-effort and only attempted when systemd is detected. +# ────────────────────────────────────────────────────────────────────────────── + +set -euo pipefail + +# ── Test bookkeeping ───────────────────────────────────────────────────────── + +TESTS_PASSED=0 +TESTS_FAILED=0 + +pass() { + echo "✅ PASS: $1" + TESTS_PASSED=$((TESTS_PASSED + 1)) +} + +fail() { + echo "❌ FAIL: $1" + TESTS_FAILED=$((TESTS_FAILED + 1)) +} + +info() { + echo "ℹ️ $1" +} + +warn() { + echo "⚠️ WARN: $1" +} + +diagnostics() { + echo "" + echo "── Diagnostics ──────────────────────────────────────────────" + echo "" + echo "Package metadata:" + dpkg -s "$PACKAGE_NAME" 2>/dev/null || echo " (not installed)" + echo "" + echo "Package file list:" + dpkg -L "$PACKAGE_NAME" 2>/dev/null || echo " (not installed)" + echo "" + echo "Config directory:" + ls -la /etc/devolutions-gateway/ 2>/dev/null || echo " (not found)" + echo "" + echo "Binary info:" + ls -la /usr/bin/devolutions-gateway 2>/dev/null || echo " (not found)" + file /usr/bin/devolutions-gateway 2>/dev/null || true + echo "" + echo "Webapp directory:" + ls -laR /usr/share/devolutions-gateway/webapp/ 2>/dev/null | head -40 || echo " (not found)" + echo "" + echo "Library directory:" + ls -la /usr/lib/devolutions-gateway/ 2>/dev/null || echo " (not found)" + echo "" + echo "systemd unit files:" + find /lib/systemd /usr/lib/systemd /etc/systemd -name '*devolutions*' 2>/dev/null || echo " (none found)" + echo "────────────────────────────────────────────────────────────" +} + +summary() { + echo "" + echo "════════════════════════════════════════════════════════════════" + echo " Test Summary: $TESTS_PASSED passed, $TESTS_FAILED failed" + echo "════════════════════════════════════════════════════════════════" + if [ "$TESTS_FAILED" -gt 0 ]; then + exit 1 + fi +} + +# ── Validate environment ───────────────────────────────────────────────────── + +: "${PACKAGE_FILE:?PACKAGE_FILE must be set}" +: "${VERSION:?VERSION must be set}" +: "${PACKAGE_NAME:?PACKAGE_NAME must be set}" + +echo "════════════════════════════════════════════════════════════════" +echo " DEB Package Installation Test" +echo " Package: $(basename "$PACKAGE_FILE")" +echo " Version: $VERSION" +echo " Container: $(cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d= -f2 | tr -d '\"')" +echo "════════════════════════════════════════════════════════════════" +echo "" + +# ── Install the package ────────────────────────────────────────────────────── + +info "Updating apt and installing prerequisites…" +export DEBIAN_FRONTEND=noninteractive +apt-get update -qq +apt-get install -y -qq file > /dev/null 2>&1 + +info "Installing package: $(basename "$PACKAGE_FILE")" + +# Use apt-get install with the .deb path; this resolves dependencies +# automatically. Show output only on failure. +INSTALL_LOG=$(mktemp) +if apt-get install -y "$PACKAGE_FILE" > "$INSTALL_LOG" 2>&1; then + pass "Package installation succeeded" +else + echo "Installation output:" + cat "$INSTALL_LOG" + fail "Package installation failed" + diagnostics + summary +fi +rm -f "$INSTALL_LOG" + +# ── Package metadata ───────────────────────────────────────────────────────── + +info "Checking package metadata…" + +if dpkg -s "$PACKAGE_NAME" > /dev/null 2>&1; then + pass "Package is registered in dpkg database" +else + fail "Package not found in dpkg database" +fi + +INSTALLED_VERSION=$(dpkg -s "$PACKAGE_NAME" 2>/dev/null | grep '^Version:' | awk '{print $2}') +if echo "$INSTALLED_VERSION" | grep -q "$VERSION"; then + pass "Installed version ($INSTALLED_VERSION) contains expected version ($VERSION)" +else + fail "Version mismatch: installed=$INSTALLED_VERSION expected contains=$VERSION" +fi + +# ── File existence checks ──────────────────────────────────────────────────── + +info "Checking expected files and directories…" + +# Main binary. +if [ -x /usr/bin/devolutions-gateway ]; then + pass "Main binary exists and is executable: /usr/bin/devolutions-gateway" +else + fail "Main binary missing or not executable: /usr/bin/devolutions-gateway" +fi + +# Native library. +if [ -f /usr/lib/devolutions-gateway/libxmf.so ]; then + pass "Native library exists: /usr/lib/devolutions-gateway/libxmf.so" +else + fail "Native library missing: /usr/lib/devolutions-gateway/libxmf.so" +fi + +# Webapp directory. +if [ -d /usr/share/devolutions-gateway/webapp ]; then + pass "Webapp directory exists: /usr/share/devolutions-gateway/webapp/" +else + fail "Webapp directory missing: /usr/share/devolutions-gateway/webapp/" +fi + +# Webapp client — expect at least an index.html. +if find /usr/share/devolutions-gateway/webapp/client -name 'index.html' 2>/dev/null | grep -q .; then + pass "Webapp client contains index.html" +else + fail "Webapp client missing index.html" +fi + +# Config directory (the postinst creates this unconditionally). +if [ -d /etc/devolutions-gateway ]; then + pass "Config directory exists: /etc/devolutions-gateway/" +else + fail "Config directory missing: /etc/devolutions-gateway/" +fi + +# ── systemd unit file ──────────────────────────────────────────────────────── +# The .deb package installs the unit file via dh_installsystemd, +# so it should be present regardless of whether systemd is running. + +info "Checking systemd unit file…" + +UNIT_FILE="" +for path in \ + /lib/systemd/system/devolutions-gateway.service \ + /usr/lib/systemd/system/devolutions-gateway.service; do + if [ -f "$path" ]; then + UNIT_FILE="$path" + break + fi +done + +if [ -n "$UNIT_FILE" ]; then + pass "systemd unit file installed: $UNIT_FILE" + + if grep -q '/usr/bin/devolutions-gateway' "$UNIT_FILE"; then + pass "Unit file references correct binary path" + else + fail "Unit file does not reference /usr/bin/devolutions-gateway" + fi +else + fail "systemd unit file not found in expected locations" +fi + +# ── Binary functionality ───────────────────────────────────────────────────── + +info "Checking binary functionality…" + +HELP_OUTPUT=$(/usr/bin/devolutions-gateway --help 2>&1) && HELP_RC=$? || HELP_RC=$? +if [ "$HELP_RC" -eq 0 ] || echo "$HELP_OUTPUT" | grep -qi 'gateway\|usage\|help'; then + pass "Binary responds to --help" +else + fail "Binary does not respond to --help (exit code: $HELP_RC)" +fi + +# ── Config initialization ──────────────────────────────────────────────────── +# The postinst runs --config-init-only only when systemd is present. +# In a container without systemd we run it manually. + +info "Checking config initialization…" + +if [ ! -f /etc/devolutions-gateway/gateway.json ]; then + info "Config file not generated by postinst (expected without systemd)." + info "Running config initialization manually…" + + if /usr/bin/devolutions-gateway --config-init-only > /dev/null 2>&1; then + pass "Config initialization command succeeded" + else + fail "Config initialization command failed" + fi +fi + +if [ -f /etc/devolutions-gateway/gateway.json ]; then + pass "Default config file exists: /etc/devolutions-gateway/gateway.json" +else + fail "Default config file missing after initialization: /etc/devolutions-gateway/gateway.json" +fi + +# ── Package file list completeness ─────────────────────────────────────────── + +info "Checking package file list completeness…" + +FILE_COUNT=$(dpkg -L "$PACKAGE_NAME" | wc -l) +if [ "$FILE_COUNT" -gt 5 ]; then + pass "Package file list contains $FILE_COUNT entries" +else + fail "Package file list suspiciously small ($FILE_COUNT entries)" +fi + +# ── Best-effort: service startup ───────────────────────────────────────────── + +info "[Best-effort] Checking service startup…" +warn "systemd service startup testing is best-effort in containers." +warn "Full service validation requires a real systemd environment." + +if [ -d /run/systemd/system ]; then + info "systemd detected; attempting service start…" + if systemctl start devolutions-gateway 2>&1; then + pass "[Best-effort] Service started successfully" + systemctl status devolutions-gateway 2>&1 || true + else + warn "Service start failed (expected in some container environments)." + fi +else + info "No systemd detected; skipping service startup test." +fi + +# ── Final output ───────────────────────────────────────────────────────────── + +diagnostics +summary diff --git a/.github/scripts/rpm-install-test.sh b/.github/scripts/rpm-install-test.sh new file mode 100755 index 000000000..9ee2384a0 --- /dev/null +++ b/.github/scripts/rpm-install-test.sh @@ -0,0 +1,293 @@ +#!/bin/bash +# ────────────────────────────────────────────────────────────────────────────── +# RPM Package Installation Test for Devolutions Gateway +# +# Runs inside a Rocky Linux 9 (RHEL 9-compatible) container to validate: +# - Package installs correctly via rpm +# - Expected files and directories are present +# - Binary is functional (--help, --config-init-only) +# - Service registration creates the expected systemd unit file +# - Default configuration file is generated +# +# LIMITATION — systemd in containers: +# Docker containers do not normally run systemd. The RPM postinst +# script (after-install) gates ALL service-related actions on the +# presence of /run/systemd/system. This means: +# - Config initialization is skipped. +# - Service registration is skipped (no unit file is created). +# - Service enable/start is skipped. +# This script compensates by running --config-init-only and +# service register manually. +# +# DIFFERENCE FROM DEB: +# The .deb package includes the systemd unit file directly (installed +# by dpkg via dh_installsystemd). The .rpm package does NOT bundle the +# unit file; instead, the postinst calls `devolutions-gateway service +# register` to create it at install time. This means that in a container +# without systemd, the unit file will only exist if we manually run +# `service register`. +# ────────────────────────────────────────────────────────────────────────────── + +set -euo pipefail + +# ── Test bookkeeping ───────────────────────────────────────────────────────── + +TESTS_PASSED=0 +TESTS_FAILED=0 + +pass() { + echo "✅ PASS: $1" + TESTS_PASSED=$((TESTS_PASSED + 1)) +} + +fail() { + echo "❌ FAIL: $1" + TESTS_FAILED=$((TESTS_FAILED + 1)) +} + +info() { + echo "ℹ️ $1" +} + +warn() { + echo "⚠️ WARN: $1" +} + +diagnostics() { + echo "" + echo "── Diagnostics ──────────────────────────────────────────────" + echo "" + echo "Package metadata:" + rpm -qi "$PACKAGE_NAME" 2>/dev/null || echo " (not installed)" + echo "" + echo "Package file list:" + rpm -ql "$PACKAGE_NAME" 2>/dev/null || echo " (not installed)" + echo "" + echo "Config directory:" + ls -la /etc/devolutions-gateway/ 2>/dev/null || echo " (not found)" + echo "" + echo "Binary info:" + ls -la /usr/bin/devolutions-gateway 2>/dev/null || echo " (not found)" + file /usr/bin/devolutions-gateway 2>/dev/null || true + echo "" + echo "Webapp directory:" + ls -laR /usr/share/devolutions-gateway/webapp/ 2>/dev/null | head -40 || echo " (not found)" + echo "" + echo "Library directory:" + ls -la /usr/lib/devolutions-gateway/ 2>/dev/null || echo " (not found)" + echo "" + echo "systemd unit files:" + find /lib/systemd /usr/lib/systemd /etc/systemd -name '*devolutions*' 2>/dev/null || echo " (none found)" + echo "────────────────────────────────────────────────────────────" +} + +summary() { + echo "" + echo "════════════════════════════════════════════════════════════════" + echo " Test Summary: $TESTS_PASSED passed, $TESTS_FAILED failed" + echo "════════════════════════════════════════════════════════════════" + if [ "$TESTS_FAILED" -gt 0 ]; then + exit 1 + fi +} + +# ── Validate environment ───────────────────────────────────────────────────── + +: "${PACKAGE_FILE:?PACKAGE_FILE must be set}" +: "${VERSION:?VERSION must be set}" +: "${PACKAGE_NAME:?PACKAGE_NAME must be set}" + +echo "════════════════════════════════════════════════════════════════" +echo " RPM Package Installation Test" +echo " Package: $(basename "$PACKAGE_FILE")" +echo " Version: $VERSION" +echo " Container: $(cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d= -f2 | tr -d '\"')" +echo "════════════════════════════════════════════════════════════════" +echo "" + +# ── Install the package ────────────────────────────────────────────────────── + +info "Installing prerequisites…" +dnf install -y -q file > /dev/null 2>&1 || true + +info "Installing package: $(basename "$PACKAGE_FILE")" + +# Use rpm -ivh directly. Dependencies are minimal (glibc) and should +# already be present in the base image. +INSTALL_LOG=$(mktemp) +if rpm -ivh "$PACKAGE_FILE" > "$INSTALL_LOG" 2>&1; then + pass "Package installation succeeded" +else + echo "Installation output:" + cat "$INSTALL_LOG" + fail "Package installation failed" + diagnostics + summary +fi +rm -f "$INSTALL_LOG" + +# ── Package metadata ───────────────────────────────────────────────────────── + +info "Checking package metadata…" + +if rpm -qi "$PACKAGE_NAME" > /dev/null 2>&1; then + pass "Package is registered in RPM database" +else + fail "Package not found in RPM database" +fi + +INSTALLED_VERSION=$(rpm -qi "$PACKAGE_NAME" 2>/dev/null | grep '^Version' | awk -F: '{print $2}' | tr -d ' ') +if echo "$INSTALLED_VERSION" | grep -q "$VERSION"; then + pass "Installed version ($INSTALLED_VERSION) contains expected version ($VERSION)" +else + fail "Version mismatch: installed=$INSTALLED_VERSION expected contains=$VERSION" +fi + +# ── File existence checks ──────────────────────────────────────────────────── + +info "Checking expected files and directories…" + +# Main binary. +if [ -x /usr/bin/devolutions-gateway ]; then + pass "Main binary exists and is executable: /usr/bin/devolutions-gateway" +else + fail "Main binary missing or not executable: /usr/bin/devolutions-gateway" +fi + +# Native library. +if [ -f /usr/lib/devolutions-gateway/libxmf.so ]; then + pass "Native library exists: /usr/lib/devolutions-gateway/libxmf.so" +else + fail "Native library missing: /usr/lib/devolutions-gateway/libxmf.so" +fi + +# Webapp directory. +if [ -d /usr/share/devolutions-gateway/webapp ]; then + pass "Webapp directory exists: /usr/share/devolutions-gateway/webapp/" +else + fail "Webapp directory missing: /usr/share/devolutions-gateway/webapp/" +fi + +# Webapp client — expect at least an index.html. +if find /usr/share/devolutions-gateway/webapp/client -name 'index.html' 2>/dev/null | grep -q .; then + pass "Webapp client contains index.html" +else + fail "Webapp client missing index.html" +fi + +# Config directory (the postinst creates this unconditionally). +if [ -d /etc/devolutions-gateway ]; then + pass "Config directory exists: /etc/devolutions-gateway/" +else + fail "Config directory missing: /etc/devolutions-gateway/" +fi + +# ── Binary functionality ───────────────────────────────────────────────────── + +info "Checking binary functionality…" + +HELP_OUTPUT=$(/usr/bin/devolutions-gateway --help 2>&1) && HELP_RC=$? || HELP_RC=$? +if [ "$HELP_RC" -eq 0 ] || echo "$HELP_OUTPUT" | grep -qi 'gateway\|usage\|help'; then + pass "Binary responds to --help" +else + fail "Binary does not respond to --help (exit code: $HELP_RC)" +fi + +# ── Config initialization ──────────────────────────────────────────────────── +# RPM postinst runs --config-init-only only when systemd is present. +# In a container without systemd we run it manually. + +info "Checking config initialization…" + +if [ ! -f /etc/devolutions-gateway/gateway.json ]; then + info "Config file not generated by postinst (expected without systemd)." + info "Running config initialization manually…" + + if /usr/bin/devolutions-gateway --config-init-only > /dev/null 2>&1; then + pass "Config initialization command succeeded" + else + fail "Config initialization command failed" + fi +fi + +if [ -f /etc/devolutions-gateway/gateway.json ]; then + pass "Default config file exists: /etc/devolutions-gateway/gateway.json" +else + fail "Default config file missing after initialization: /etc/devolutions-gateway/gateway.json" +fi + +# ── Service registration ───────────────────────────────────────────────────── +# The RPM does NOT bundle the systemd unit file. The postinst calls +# `devolutions-gateway service register` to create it. In containers +# without systemd, the postinst skips this, so we try it manually. + +info "Checking service registration…" +info "Running service registration manually…" + +SERVICE_REG_OUTPUT=$(/usr/bin/devolutions-gateway service register 2>&1) && SERVICE_REG_RC=$? || SERVICE_REG_RC=$? +if [ "$SERVICE_REG_RC" -eq 0 ]; then + pass "Service registration command succeeded" +else + warn "Service registration returned exit code $SERVICE_REG_RC (may require systemd)." + info "Output: $SERVICE_REG_OUTPUT" +fi + +# Check for unit file in expected locations. +UNIT_FILE="" +for path in \ + /etc/systemd/system/devolutions-gateway.service \ + /lib/systemd/system/devolutions-gateway.service \ + /usr/lib/systemd/system/devolutions-gateway.service; do + if [ -f "$path" ]; then + UNIT_FILE="$path" + break + fi +done + +if [ -n "$UNIT_FILE" ]; then + pass "systemd unit file exists: $UNIT_FILE" + + if grep -q '/usr/bin/devolutions-gateway' "$UNIT_FILE"; then + pass "Unit file references correct binary path" + else + fail "Unit file does not reference /usr/bin/devolutions-gateway" + fi +else + # Not a hard failure: service register may require a running systemd. + warn "systemd unit file not found after registration attempt." + info "This is expected in container environments without systemd." +fi + +# ── Package file list completeness ─────────────────────────────────────────── + +info "Checking package file list completeness…" + +FILE_COUNT=$(rpm -ql "$PACKAGE_NAME" | wc -l) +if [ "$FILE_COUNT" -gt 5 ]; then + pass "Package file list contains $FILE_COUNT entries" +else + fail "Package file list suspiciously small ($FILE_COUNT entries)" +fi + +# ── Best-effort: service startup ───────────────────────────────────────────── + +info "[Best-effort] Checking service startup…" +warn "systemd service startup testing is best-effort in containers." +warn "Full service validation requires a real systemd environment." + +if [ -d /run/systemd/system ]; then + info "systemd detected; attempting service start…" + if systemctl start devolutions-gateway 2>&1; then + pass "[Best-effort] Service started successfully" + systemctl status devolutions-gateway 2>&1 || true + else + warn "Service start failed (expected in some container environments)." + fi +else + info "No systemd detected; skipping service startup test." +fi + +# ── Final output ───────────────────────────────────────────────────────────── + +diagnostics +summary diff --git a/.github/workflows/linux-install-test.yml b/.github/workflows/linux-install-test.yml new file mode 100644 index 000000000..e2193b9ed --- /dev/null +++ b/.github/workflows/linux-install-test.yml @@ -0,0 +1,221 @@ +name: Linux Install Tests + +# ────────────────────────────────────────────────────────────────────────────── +# PURPOSE: +# Smoke-test Linux .deb and .rpm packages produced by the CI workflow. +# Catches packaging regressions before release: missing files, broken +# installs, service registration issues, configuration initialization +# failures, and obvious startup problems. +# +# DESIGN: +# - Separate reusable workflow (workflow_call + workflow_dispatch + schedule). +# - Consumes the merged `devolutions-gateway` artifact from ci.yml. +# - Runs package installation tests inside Docker containers on +# GitHub-hosted runners (x86_64 only). +# - DEB lane: Ubuntu 22.04 container (not 18.04; the package requires +# libc6 >= 2.31, which rules out Ubuntu 18.04's glibc 2.27). +# - RPM lane: Rocky Linux 9 container (RHEL 9-compatible). +# - Tests are split into: +# 1. Mandatory package smoke tests (must pass). +# 2. Best-effort systemd service tests (informational only). +# +# TRADEOFFS: +# - Separate workflow: Keeps the main CI fast; install tests can run +# independently or be chained into a release pipeline. +# - GitHub-hosted runners: Sufficient for package QA; no self-hosted +# infrastructure required. +# - Container-based: Close enough to real distros for catching packaging +# regressions, though not a perfect replica of production systems. +# - RHEL 9-compatible (Rocky Linux 9): Free, widely-used RHEL 9 rebuild; +# no exact RHEL version matching is required. +# - x86_64 only: GitHub-hosted runners are x86_64; ARM64 packages would +# require QEMU or ARM runners, not worth the complexity for v1. +# - Service testing is best-effort: systemd inside Docker containers is +# unreliable. Full service validation requires a real systemd environment. +# ────────────────────────────────────────────────────────────────────────────── + +on: + # DELETE ME + push: + branches: + - master + pull_request: + types: [opened, synchronize, reopened] + workflow_call: + inputs: + run-id: + description: > + CI workflow run ID to download artifacts from. + Defaults to the current run ID (for chaining after ci.yml). + type: string + required: false + workflow_dispatch: + inputs: + run-id: + description: > + CI workflow run ID to download artifacts from. + Leave empty to use the latest successful CI run on the default branch. + type: string + required: false + schedule: + # Weekly on Monday at 06:00 UTC. + - cron: "0 6 * * 1" + +permissions: + contents: read + actions: read + +jobs: + preflight: + name: Preflight + runs-on: ubuntu-latest + outputs: + run-id: ${{ steps.resolve.outputs.run-id }} + version: ${{ steps.version.outputs.version }} + + steps: + - name: Resolve CI run ID + id: resolve + shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + + # Priority: + # 1. Explicit input (workflow_dispatch or workflow_call with run-id). + # 2. Current run ID (workflow_call without run-id — artifacts + # from the calling workflow persist in the same run). + # 3. Latest successful CI run on default branch (schedule trigger). + + RUN_ID="${{ inputs.run-id }}" + + if [ -n "$RUN_ID" ]; then + echo "Using provided run ID: $RUN_ID" + elif [ "${{ github.event_name }}" = "schedule" ]; then + echo "Schedule trigger: finding latest successful CI run on default branch…" + RUN_ID=$(gh run list \ + --workflow ci.yml \ + --status success \ + --branch "${{ github.event.repository.default_branch }}" \ + --limit 1 \ + --json databaseId \ + --jq '.[0].databaseId' \ + --repo "$GITHUB_REPOSITORY") + + if [ -z "$RUN_ID" ] || [ "$RUN_ID" = "null" ]; then + echo "::error::No successful CI run found on default branch" + exit 1 + fi + echo "Found latest successful CI run: $RUN_ID" + else + RUN_ID="${{ github.run_id }}" + echo "Using current run ID: $RUN_ID" + fi + + # FIXME + echo "run-id=23235073993" >> "$GITHUB_OUTPUT" + + - name: Download version artifact + shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh run download "${{ steps.resolve.outputs.run-id }}" \ + -n version \ + --repo "$GITHUB_REPOSITORY" + + - name: Read version + id: version + shell: bash + run: | + VERSION=$(head -1 VERSION) + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "::notice::Testing packages for version $VERSION from run ${{ steps.resolve.outputs.run-id }}" + + install-test: + name: ${{ matrix.display-name }} + needs: [preflight] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - package-type: deb + display-name: "DEB Install Test (Ubuntu 22.04)" + container-image: "ubuntu:22.04" + test-script: ".github/scripts/deb-install-test.sh" + package-glob: "linux/x86_64/*.deb" + - package-type: rpm + display-name: "RPM Install Test (Rocky Linux 9)" + container-image: "rockylinux:9" + test-script: ".github/scripts/rpm-install-test.sh" + package-glob: "linux/x86_64/*.rpm" + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download gateway artifacts + shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh run download "${{ needs.preflight.outputs.run-id }}" \ + -n devolutions-gateway \ + -D gateway-artifacts \ + --repo "$GITHUB_REPOSITORY" + + - name: Locate package file + id: find-package + shell: bash + run: | + set -euo pipefail + + PACKAGE_FILE=$(find gateway-artifacts -path '*/${{ matrix.package-glob }}' -type f | head -1) + + if [ -z "$PACKAGE_FILE" ]; then + echo "::error::No ${{ matrix.package-type }} package found matching '${{ matrix.package-glob }}'" + echo "Available files in gateway-artifacts:" + find gateway-artifacts -type f | sort + exit 1 + fi + + echo "Found package: $PACKAGE_FILE" + echo "package-file=$PACKAGE_FILE" >> "$GITHUB_OUTPUT" + echo "package-basename=$(basename "$PACKAGE_FILE")" >> "$GITHUB_OUTPUT" + + - name: Run install tests in container + shell: bash + run: | + set -euo pipefail + + chmod +x "${{ matrix.test-script }}" + + # Strip the gateway-artifacts/ prefix so the path is relative to the mount point. + PACKAGE_REL_PATH="${{ steps.find-package.outputs.package-file }}" + PACKAGE_IN_CONTAINER="/artifacts/${PACKAGE_REL_PATH#gateway-artifacts/}" + + docker run --rm \ + -v "${{ github.workspace }}:/workspace:ro" \ + -v "${{ github.workspace }}/gateway-artifacts:/artifacts:ro" \ + -e "PACKAGE_FILE=$PACKAGE_IN_CONTAINER" \ + -e "VERSION=${{ needs.preflight.outputs.version }}" \ + -e "PACKAGE_NAME=devolutions-gateway" \ + "${{ matrix.container-image }}" \ + /workspace/${{ matrix.test-script }} + + - name: Write job summary + if: always() + shell: bash + run: | + { + echo "## ${{ matrix.display-name }}" + echo "" + echo "| Property | Value |" + echo "|----------|-------|" + echo "| Package | \`${{ steps.find-package.outputs.package-basename }}\` |" + echo "| Version | \`${{ needs.preflight.outputs.version }}\` |" + echo "| Container | \`${{ matrix.container-image }}\` |" + echo "| CI Run | \`${{ needs.preflight.outputs.run-id }}\` |" + } >> "$GITHUB_STEP_SUMMARY"