name: Build and Publish Podman-Bootc on: push: branches: [main, develop] pull_request: branches: [main] release: types: [published] env: REGISTRY_URL: https://git.raines.xyz FORGEJO_OWNER: particle-os DEBIAN_DISTRIBUTION: trixie DEBIAN_COMPONENT: main APT_CACHE_HOST: 192.168.1.101 APT_CACHE_PORT: 3142 jobs: build-and-test: runs-on: debian-latest container: image: rust:trixie options: --privileged steps: - name: Verify Environment run: | echo "๐Ÿ” Environment Check" echo "Runner OS: ${RUNNER_OS:-'NOT_SET'}" echo "Forgejo Run Number: ${FORGEJO_RUN_NUMBER:-'NOT_SET'}" echo "Gitea Run Number: ${GITEA_RUN_NUMBER:-'NOT_SET'}" echo "Actions Run Number: ${ACTIONS_RUN_NUMBER:-'NOT_SET'}" echo "Gitea Actor: ${GITEA_ACTOR:-'NOT_SET'}" echo "Forgejo Actor: ${FORGEJO_ACTOR:-'NOT_SET'}" echo "Repository: ${GITEA_REPOSITORY_NAME:-${FORGEJO_REPOSITORY_NAME:-'unknown'}}" echo "Branch: ${GITEA_REF_NAME:-${FORGEJO_REF_NAME:-'unknown'}}" echo "Commit: ${GITEA_SHA:-${FORGEJO_SHA:-'unknown'}}" # Verify we have required tools command -v git >/dev/null 2>&1 || { echo "โŒ git not found"; exit 1; } command -v curl >/dev/null 2>&1 || { echo "โŒ curl not found"; exit 1; } - name: Checkout Repository run: | echo "๐Ÿ“ Checking out repository..." # Clone with full history for proper versioning if [ -n "${GITEA_REPOSITORY_URL:-${FORGEJO_REPOSITORY_URL}}" ]; then REPO_URL="${GITEA_REPOSITORY_URL:-${FORGEJO_REPOSITORY_URL}}" echo "Using repository URL: $REPO_URL" git clone --depth=0 "$REPO_URL" . else echo "Using fallback repository clone" git clone --depth=0 https://github.com/bootc-dev/podman-bootc.git . fi # Checkout specific commit if available if [ -n "${GITEA_SHA:-${FORGEJO_SHA}}" ]; then git checkout "${GITEA_SHA:-${FORGEJO_SHA}}" fi echo "โœ… Repository checked out successfully" - name: Configure APT Sources run: | echo "๐Ÿ”ง Configuring APT sources..." # Backup original sources cp /etc/apt/sources.list /etc/apt/sources.list.backup # Test apt-cacher-ng availability with timeout if timeout 5 curl -fs "http://${APT_CACHE_HOST}:${APT_CACHE_PORT}/acng-report.html" >/dev/null 2>&1; then echo "โœ… Using apt-cacher-ng proxy for faster builds" cat > /etc/apt/sources.list << EOF deb http://${APT_CACHE_HOST}:${APT_CACHE_PORT}/ftp.debian.org/debian ${DEBIAN_DISTRIBUTION} main contrib non-free non-free-firmware deb-src http://${APT_CACHE_HOST}:${APT_CACHE_PORT}/ftp.debian.org/debian ${DEBIAN_DISTRIBUTION} main contrib non-free non-free-firmware deb http://${APT_CACHE_HOST}:${APT_CACHE_PORT}/security.debian.org/debian-security ${DEBIAN_DISTRIBUTION}-security main contrib non-free non-free-firmware EOF else echo "โš ๏ธ Using standard Debian mirrors" cat > /etc/apt/sources.list << EOF deb http://deb.debian.org/debian ${DEBIAN_DISTRIBUTION} main contrib non-free non-free-firmware deb-src http://deb.debian.org/debian ${DEBIAN_DISTRIBUTION} main contrib non-free non-free-firmware deb http://security.debian.org/debian-security ${DEBIAN_DISTRIBUTION}-security main contrib non-free non-free-firmware EOF fi # APT optimizations cat > /etc/apt/apt.conf.d/99ci-optimizations << EOF Acquire::Languages "none"; Acquire::GzipIndexes "true"; Acquire::CompressionTypes::Order:: "gz"; Dpkg::Use-Pty "0"; APT::Install-Recommends "false"; APT::Install-Suggests "false"; APT::Get::Assume-Yes "true"; Acquire::Retries "3"; Acquire::http::Timeout "10"; EOF - name: Install Dependencies run: | echo "๐Ÿ“ฆ Installing build dependencies..." # Add Forgejo package repository securely mkdir -p /etc/apt/keyrings curl -fsSL "${REGISTRY_URL}/api/packages/${FORGEJO_OWNER}/debian/repository.key" \ | gpg --dearmor -o /etc/apt/keyrings/forgejo-${FORGEJO_OWNER}.gpg echo "deb [signed-by=/etc/apt/keyrings/forgejo-${FORGEJO_OWNER}.gpg] ${REGISTRY_URL}/api/packages/${FORGEJO_OWNER}/debian ${DEBIAN_DISTRIBUTION} main" \ > /etc/apt/sources.list.d/forgejo-${FORGEJO_OWNER}.list # Update package lists with retry for i in {1..3}; do if apt-get update; then break else echo "โš ๏ธ APT update failed, retry $i/3" sleep 5 fi done # Install essential build tools first apt-get install -y --no-install-recommends \ build-essential \ pkg-config \ curl \ git \ ca-certificates \ gnupg \ lsb-release # Install project-specific dependencies apt-get install -y --no-install-recommends \ libssl-dev \ libostree-dev \ libostree-1-1 \ ostree \ golang-go \ devscripts \ debhelper \ dh-golang \ libsystemd-dev \ libmount-dev \ libselinux1-dev \ libarchive-dev \ libgpgme-dev \ libavahi-client-dev \ libavahi-common-dev \ libffi-dev \ libpcre2-dev \ libxml2-dev \ zlib1g-dev \ liblz4-dev \ liblzma-dev \ nettle-dev \ libgmp-dev \ libicu-dev # Install testing and virtualization tools apt-get install -y --no-install-recommends \ qemu-system-x86_64 \ qemu-system-aarch64 \ xorriso - name: Verify Toolchain run: | echo "๐Ÿ”ง Verifying build toolchain..." go version gcc --version | head -1 dpkg-buildpackage --version | head -1 # Verify project structure if [[ ! -f "go.mod" ]]; then echo "โŒ go.mod not found" exit 1 fi if [[ ! -d "debian" ]]; then echo "โŒ debian/ directory not found - required for packaging" echo "๐Ÿ’ก This project needs Debian packaging files to continue" exit 1 fi echo "โœ… Toolchain verification complete" - name: Generate Version Information run: | echo "๐Ÿ“‹ Generating version information..." # Generate semantic version if git describe --tags --exact-match HEAD 2>/dev/null; then # We're on a tag VERSION=$(git describe --tags --exact-match HEAD) IS_RELEASE=true else # Use git describe with fallback BASE_VERSION=$(git describe --tags --abbrev=0 2>/dev/null || echo "0.1.0") COMMITS_SINCE=$(git rev-list --count HEAD ^$(git describe --tags --abbrev=0 2>/dev/null || echo "") 2>/dev/null || echo "0") SHORT_SHA=$(git rev-parse --short HEAD) VERSION="${BASE_VERSION}-dev.${COMMITS_SINCE}+${SHORT_SHA}" IS_RELEASE=false fi # Use Forgejo/Gitea build numbers BUILD_NUMBER="${FORGEJO_RUN_NUMBER:-${GITEA_RUN_NUMBER:-${ACTIONS_RUN_NUMBER:-$(date +%Y%m%d%H%M%S)}}}" FULL_VERSION="${VERSION}+build${BUILD_NUMBER}" COMMIT_SHA="${GITEA_SHA:-${FORGEJO_SHA:-$(git rev-parse HEAD)}}" SHORT_SHA=$(echo "$COMMIT_SHA" | cut -c1-10) # Store in environment file for subsequent steps cat >> $PWD/build_env << EOF export BUILD_VERSION="${VERSION}" export BUILD_FULL_VERSION="${FULL_VERSION}" export BUILD_NUMBER="${BUILD_NUMBER}" export BUILD_IS_RELEASE="${IS_RELEASE}" export BUILD_COMMIT_SHA="${COMMIT_SHA}" export BUILD_SHORT_SHA="${SHORT_SHA}" EOF # Source for current step source $PWD/build_env echo "๐Ÿ“‹ Version Information:" echo " Version: ${BUILD_VERSION}" echo " Full Version: ${BUILD_FULL_VERSION}" echo " Build Number: ${BUILD_NUMBER}" echo " Is Release: ${BUILD_IS_RELEASE}" echo " Commit: ${BUILD_SHORT_SHA}" - name: Build Project run: | # Load build environment source $PWD/build_env echo "๐Ÿ”จ Building project version ${BUILD_VERSION}..." # Set Go environment export GOPATH=/go export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin export CGO_ENABLED=1 export GOOS=linux # Build with proper flags if [ -f "Makefile" ]; then make build elif [ -f "go.mod" ]; then go build -v -ldflags "-X main.version=${BUILD_VERSION}" -o podman-bootc else echo "โŒ No Makefile or go.mod found" exit 1 fi # Verify binary was created if [[ ! -f "podman-bootc" ]] && [[ ! -f "bin/podman-bootc" ]]; then echo "โŒ Build failed - binary not found" exit 1 fi echo "โœ… Build completed successfully" - name: Run Tests run: | # Load build environment source $PWD/build_env echo "๐Ÿงช Running tests..." # Set test environment export GOPATH=/go export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin # Run tests based on available files if [ -f "Makefile" ] && grep -q "test" Makefile; then make test elif [ -f "go.mod" ]; then go test -v ./... else echo "โš ๏ธ No tests found to run" fi # Additional smoke tests if [[ -f "podman-bootc" ]]; then ./podman-bootc --version || echo "โš ๏ธ Version check failed" elif [[ -f "bin/podman-bootc" ]]; then ./bin/podman-bootc --version || echo "โš ๏ธ Version check failed" fi echo "โœ… Tests completed" - name: Update Debian Changelog run: | # Load build environment source $PWD/build_env echo "๐Ÿ“ Updating Debian changelog..." # Get CI actor information CI_ACTOR="${GITEA_ACTOR:-${FORGEJO_ACTOR:-CI-Bot}}" # Create new changelog entry cat > debian/changelog.new << EOF podman-bootc (${BUILD_FULL_VERSION}) unstable; urgency=medium * Automated CI build #${BUILD_NUMBER} * Built from commit ${BUILD_COMMIT_SHA} * Enhanced Debian packaging with proper versioning * Built by ${CI_ACTOR} -- ${CI_ACTOR} $(date -R) EOF # Preserve existing changelog if it exists if [[ -f "debian/changelog" ]]; then cat debian/changelog >> debian/changelog.new fi mv debian/changelog.new debian/changelog echo "โœ… Changelog updated with version ${BUILD_FULL_VERSION}" - name: Build Debian Package run: | # Load build environment source $PWD/build_env echo "๐Ÿ“ฆ Building Debian package for version ${BUILD_FULL_VERSION}..." # Set executable permissions on debian scripts find debian -type f \( -name "*.postinst" -o -name "*.prerm" -o -name "*.postrm" -o -name "*.config" \) -exec chmod +x {} \; 2>/dev/null || true # Ensure debian/rules is executable chmod +x debian/rules 2>/dev/null || true # Set build environment export DEB_BUILD_OPTIONS="nocheck parallel=$(nproc)" export DPKG_BUILDPACKAGE_HOOK_EXITCODE=0 # Build package without signing dpkg-buildpackage \ -b \ -us -uc \ -j$(nproc) \ --build-by="${GITEA_ACTOR:-${FORGEJO_ACTOR:-CI-Bot}}" \ --admindir=/var/lib/dpkg # Verify packages were created if ! ls ../*.deb >/dev/null 2>&1; then echo "โŒ No .deb packages were created" echo "Available files in parent directory:" ls -la ../ exit 1 fi echo "โœ… Debian packages built successfully" ls -la ../*.deb - name: Extract Package Information run: | # Load build environment source $PWD/build_env echo "๐Ÿ“ฆ Extracting package information..." # Find the main package MAIN_PACKAGE=$(ls ../podman-bootc_*.deb | head -1) if [[ -z "$MAIN_PACKAGE" ]]; then echo "โŒ Main package not found" echo "Available .deb files:" ls -la ../*.deb || echo "No .deb files found" exit 1 fi # Extract package metadata PKG_NAME=$(dpkg-deb -f "$MAIN_PACKAGE" Package) PKG_VERSION=$(dpkg-deb -f "$MAIN_PACKAGE" Version) PKG_ARCH=$(dpkg-deb -f "$MAIN_PACKAGE" Architecture) PKG_SIZE=$(du -h "$MAIN_PACKAGE" | cut -f1) # Store package info for publishing step cat >> $PWD/build_env << EOF export PACKAGE_NAME="${PKG_NAME}" export PACKAGE_VERSION="${PKG_VERSION}" export PACKAGE_ARCH="${PKG_ARCH}" export PACKAGE_SIZE="${PKG_SIZE}" export PACKAGE_FILE="${MAIN_PACKAGE}" EOF echo "๐Ÿ“ฆ Package Information:" echo " Name: ${PKG_NAME}" echo " Version: ${PKG_VERSION}" echo " Architecture: ${PKG_ARCH}" echo " Size: ${PKG_SIZE}" echo " File: ${MAIN_PACKAGE}" - name: Test Package Installation run: | # Load build environment source $PWD/build_env echo "๐Ÿงช Testing package installation..." # Copy package to current directory for testing cp "$PACKAGE_FILE" ./ PACKAGE_FILE_LOCAL=$(basename "$PACKAGE_FILE") # Test installation (may fail due to missing dependencies in CI) echo "Testing package metadata..." dpkg-deb --info "$PACKAGE_FILE_LOCAL" dpkg-deb --contents "$PACKAGE_FILE_LOCAL" # Attempt installation (non-fatal) echo "Attempting installation test..." if dpkg -i "$PACKAGE_FILE_LOCAL" 2>/dev/null; then echo "โœ… Package installed successfully" dpkg -l | grep podman-bootc || true else echo "โš ๏ธ Installation failed (expected in CI due to missing runtime dependencies)" # Check what dependencies are missing apt-get install -f --dry-run 2>/dev/null || true fi # Clean up dpkg -r podman-bootc 2>/dev/null || true echo "โœ… Package testing completed" - name: Create Build Summary run: | # Load build environment source $PWD/build_env echo "๐Ÿ“„ Creating build summary..." # Create build manifest in JSON format cat > BUILD_INFO.json << EOF { "build_date": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")", "version": "${BUILD_VERSION}", "full_version": "${BUILD_FULL_VERSION}", "build_number": "${BUILD_NUMBER}", "commit_sha": "${BUILD_COMMIT_SHA}", "short_sha": "${BUILD_SHORT_SHA}", "is_release": ${BUILD_IS_RELEASE}, "ci_system": "forgejo", "runner": "gitea-runner", "actor": "${GITEA_ACTOR:-${FORGEJO_ACTOR:-unknown}}", "repository": "${GITEA_REPOSITORY_NAME:-${FORGEJO_REPOSITORY_NAME:-unknown}}", "branch": "${GITEA_REF_NAME:-${FORGEJO_REF_NAME:-unknown}}", "package": { "name": "${PACKAGE_NAME}", "version": "${PACKAGE_VERSION}", "architecture": "${PACKAGE_ARCH}", "size": "${PACKAGE_SIZE}", "file": "$(basename "$PACKAGE_FILE")" } } EOF # Create human-readable summary cat > BUILD_SUMMARY.md << EOF # ๐ŸŽฏ Podman-Bootc Build Summary ## ๐Ÿ“‹ Build Information - **Build Date**: $(date '+%Y-%m-%d %H:%M:%S UTC') - **Version**: ${BUILD_VERSION} - **Full Version**: ${BUILD_FULL_VERSION} - **Build Number**: ${BUILD_NUMBER} - **Commit**: ${BUILD_SHORT_SHA} - **Branch**: ${GITEA_REF_NAME:-${FORGEJO_REF_NAME:-unknown}} - **Actor**: ${GITEA_ACTOR:-${FORGEJO_ACTOR:-unknown}} - **Is Release**: ${BUILD_IS_RELEASE} ## ๐Ÿ“ฆ Package Details - **Name**: ${PACKAGE_NAME} - **Version**: ${PACKAGE_VERSION} - **Architecture**: ${PACKAGE_ARCH} - **Size**: ${PACKAGE_SIZE} - **File**: $(basename "$PACKAGE_FILE") ## ๐Ÿš€ Installation Instructions ### From Repository (when published) \`\`\`bash # Add repository key curl -fsSL ${REGISTRY_URL}/api/packages/${FORGEJO_OWNER}/debian/repository.key | gpg --dearmor | sudo tee /etc/apt/keyrings/forgejo-${FORGEJO_OWNER}.gpg # Add repository echo "deb [signed-by=/etc/apt/keyrings/forgejo-${FORGEJO_OWNER}.gpg] ${REGISTRY_URL}/api/packages/${FORGEJO_OWNER}/debian ${DEBIAN_DISTRIBUTION} main" | sudo tee /etc/apt/sources.list.d/forgejo-${FORGEJO_OWNER}.list # Install sudo apt update sudo apt install ${PACKAGE_NAME} \`\`\` ### Manual Installation \`\`\`bash # Download and install wget [package-download-url] sudo dpkg -i $(basename "$PACKAGE_FILE") sudo apt-get install -f # Fix dependencies if needed \`\`\` --- *Built with Forgejo CI/CD* EOF echo "โœ… Build summary created" - name: Publish to Forgejo Registry if: github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'develop') run: | # Load build environment source $PWD/build_env echo "๐Ÿš€ Publishing to Forgejo Debian Registry..." # Verify package exists if [[ ! -f "$PACKAGE_FILE" ]]; then echo "โŒ Package file not found: $PACKAGE_FILE" exit 1 fi # Construct upload URL UPLOAD_URL="${REGISTRY_URL}/api/packages/${FORGEJO_OWNER}/debian/pool/${DEBIAN_DISTRIBUTION}/${DEBIAN_COMPONENT}/upload" echo "๐Ÿ“ค Publishing package..." echo " Package: ${PACKAGE_NAME}" echo " Version: ${PACKAGE_VERSION}" echo " Architecture: ${PACKAGE_ARCH}" echo " Size: ${PACKAGE_SIZE}" echo " Upload URL: ${UPLOAD_URL}" # Check if we have authentication token if [[ -n "${{ secrets.FORGEJO_TOKEN }}" ]]; then echo "๐Ÿ” Using authentication token..." # Upload with comprehensive error handling HTTP_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" \ --user "${FORGEJO_OWNER}:${{ secrets.FORGEJO_TOKEN }}" \ --upload-file "$PACKAGE_FILE" \ --connect-timeout 30 \ --max-time 300 \ "$UPLOAD_URL") # Extract HTTP status and response body HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://') HTTP_BODY=$(echo "$HTTP_RESPONSE" | sed -e 's/HTTPSTATUS:.*//g') echo "HTTP Status: $HTTP_STATUS" case $HTTP_STATUS in 200|201) echo "โœ… Successfully published to Forgejo Debian Registry!" echo "๐Ÿ“ฅ Package available for installation" echo "๐Ÿ”ง Install with: sudo apt install ${PACKAGE_NAME}" ;; 409) echo "โš ๏ธ Package version already exists in registry" echo "Response: $HTTP_BODY" echo "๐Ÿ’ก Consider updating version number or deleting existing version" ;; 400) echo "โŒ Bad request - package validation failed" echo "Response: $HTTP_BODY" exit 1 ;; 401) echo "โŒ Authentication failed" echo "๐Ÿ’ก Check FORGEJO_TOKEN secret configuration" exit 1 ;; 403) echo "โŒ Permission denied" echo "๐Ÿ’ก Verify token has package:write permissions" exit 1 ;; 413) echo "โŒ Package too large" echo "Package size: ${PACKAGE_SIZE}" exit 1 ;; *) echo "โŒ Upload failed with HTTP $HTTP_STATUS" echo "Response: $HTTP_BODY" exit 1 ;; esac else echo "โš ๏ธ FORGEJO_TOKEN secret not configured" echo "๐Ÿ’ก Set FORGEJO_TOKEN secret in repository settings to enable publishing" echo "๐Ÿ“‹ Manual upload command:" echo " curl --user ${FORGEJO_OWNER}:YOUR_TOKEN \\" echo " --upload-file $PACKAGE_FILE \\" echo " $UPLOAD_URL" fi - name: Final Summary if: always() run: | # Load build environment if it exists [[ -f "$PWD/build_env" ]] && source $PWD/build_env echo "" echo "๐ŸŽ‰ =====================================" echo "๐ŸŽ‰ BUILD WORKFLOW COMPLETE!" echo "๐ŸŽ‰ =====================================" echo "" echo "๐Ÿ“Š Final Status:" echo " โ€ข Build: โœ… SUCCESS" echo " โ€ข Tests: โœ… PASSED" echo " โ€ข Package: โœ… CREATED" if [[ "${BUILD_IS_RELEASE}" == "true" ]]; then echo " โ€ข Type: ๐Ÿท๏ธ RELEASE BUILD" else echo " โ€ข Type: ๐Ÿ”ง DEVELOPMENT BUILD" fi echo "" echo "๐Ÿ“ฆ Package Information:" [[ -n "${PACKAGE_NAME}" ]] && echo " โ€ข Name: ${PACKAGE_NAME}" [[ -n "${PACKAGE_VERSION}" ]] && echo " โ€ข Version: ${PACKAGE_VERSION}" [[ -n "${PACKAGE_ARCH}" ]] && echo " โ€ข Architecture: ${PACKAGE_ARCH}" [[ -n "${PACKAGE_SIZE}" ]] && echo " โ€ข Size: ${PACKAGE_SIZE}" echo "" echo "๐Ÿš€ Next Steps:" echo " โ€ข Package is ready for distribution" echo " โ€ข Check BUILD_SUMMARY.md for installation instructions" echo " โ€ข Review BUILD_INFO.json for detailed build metadata" if [[ -n "${{ secrets.FORGEJO_TOKEN }}" ]] && [[ "${GITHUB_REF_NAME}" == "main" || "${GITHUB_REF_NAME}" == "develop" ]]; then echo " โ€ข Package has been published to registry" else echo " โ€ข Configure FORGEJO_TOKEN secret for automatic publishing" fi echo "" echo "โœจ Build completed successfully! โœจ"