From d1f347bf7f0e46f7b6a9c495eba8b73552f12c80 Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 14 Aug 2025 14:18:56 +0200 Subject: [PATCH 1/8] STAC-0 Add docker build. --- .github/workflows/build.yml | 12 ++ .github/workflows/docker.yml | 116 ++++++++++ Dockerfile | 66 ++++++ Makefile | 205 ++++++++++++++++-- PACKAGING.md | 134 ++++++++++++ README.md | 67 +++++- build.py | 401 ++++++++++++++++++++++++++++++++++- build_requirements.txt | 1 + docker-build.sh | 315 +++++++++++++++++++++++++++ integrations_finder.py | 62 ++++-- 10 files changed, 1334 insertions(+), 45 deletions(-) create mode 100644 .github/workflows/docker.yml create mode 100644 Dockerfile create mode 100644 PACKAGING.md create mode 100755 docker-build.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5791581..88a47c0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,6 +46,18 @@ jobs: run: | python -m pip install --upgrade pip pip install -r build_requirements.txt + + # Install system package tools based on platform + if [ "${{ matrix.platform }}" = "linux" ]; then + sudo apt-get update + sudo apt-get install -y dpkg-dev rpm rpm-build + elif [ "${{ matrix.platform }}" = "win" ]; then + # WiX tools would need to be installed here for Windows MSI creation + echo "WiX tools installation would go here for MSI creation" + elif [ "${{ matrix.platform }}" = "macos" ]; then + # pkgbuild is available by default on macOS + echo "pkgbuild is available by default on macOS" + fi - name: Build executable run: | diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..74f2abb --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,116 @@ +name: Build and Push Docker Images + +on: + push: + branches: [ main, develop ] + tags: [ 'v*' ] + pull_request: + branches: [ main ] + +env: + REGISTRY: ghcr.io + REPO: stackvista/agent-integrations-finder + IMAGE_NAME: ${{ env.REGISTRY }}/${{ env.REPO }} + +jobs: + docker-build: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha,prefix={{branch}}- + type=raw,value=latest,enable={{is_default_branch}} + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r build_requirements.txt + + - name: Build and push Docker images + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Build individual architecture images + if: github.event_name != 'pull_request' + run: | + # Build amd64 image + docker buildx build \ + --platform linux/amd64 \ + --tag ${{ env.IMAGE_NAME }}:${{ github.sha }}-amd64 \ + --tag ${{ env.IMAGE_NAME }}:${{ github.ref_name }}-amd64 \ + --push \ + . + + # Build arm64 image + docker buildx build \ + --platform linux/arm64 \ + --tag ${{ env.IMAGE_NAME }}:${{ github.sha }}-arm64 \ + --tag ${{ env.IMAGE_NAME }}:${{ github.ref_name }}-arm64 \ + --push \ + . + + - name: Create multi-architecture manifest + if: github.event_name != 'pull_request' + run: | + # Create manifest with git SHA + docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${{ github.sha }} \ + ${{ env.IMAGE_NAME }}:${{ github.sha }}-amd64 \ + ${{ env.IMAGE_NAME }}:${{ github.sha }}-arm64 + + # Create manifest with branch/tag name + docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${{ github.ref_name }} \ + ${{ env.IMAGE_NAME }}:${{ github.ref_name }}-amd64 \ + ${{ env.IMAGE_NAME }}:${{ github.ref_name }}-arm64 + + - name: Show image info + run: | + echo "Built images:" + docker images ${{ env.IMAGE_NAME }} || true + echo "" + echo "Available tags:" + echo "- ${{ env.IMAGE_NAME }}:${{ github.sha }}" + echo "- ${{ env.IMAGE_NAME }}:${{ github.sha }}-amd64" + echo "- ${{ env.IMAGE_NAME }}:${{ github.sha }}-arm64" + if [[ "${{ github.ref_name }}" != "${{ github.sha }}" ]]; then + echo "- ${{ env.IMAGE_NAME }}:${{ github.ref_name }}" + echo "- ${{ env.IMAGE_NAME }}:${{ github.ref_name }}-amd64" + echo "- ${{ env.IMAGE_NAME }}:${{ github.ref_name }}-arm64" + fi diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1eeab77 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,66 @@ +# Multi-stage Dockerfile for Agent Integrations Finder +# Stage 1: Build stage +FROM python:3.11-slim AS builder + +# Install build dependencies +RUN apt-get update && apt-get install -y \ + gcc \ + g++ \ + make \ + zip \ + tar \ + gzip \ + dpkg-dev \ + && rm -rf /var/lib/apt/lists/* + +# Set working directory +WORKDIR /app + +# Copy requirements and install Python dependencies +COPY requirements.txt build_requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt -r build_requirements.txt + +# Copy source code +COPY . . + +# Build the executable for the target architecture +ARG TARGETARCH +RUN if [ "$TARGETARCH" = "amd64" ]; then \ + python build.py linux-x86_64; \ + elif [ "$TARGETARCH" = "arm64" ]; then \ + python build.py linux-aarch64; \ + else \ + echo "Unsupported architecture: $TARGETARCH"; \ + exit 1; \ + fi + +# Stage 2: Runtime stage +FROM python:3.11-slim AS runtime + +# Install minimal runtime dependencies +RUN apt-get update && apt-get install -y \ + libglib2.0-0 \ + && rm -rf /var/lib/apt/lists/* + +# Create non-root user +RUN useradd --create-home --shell /bin/bash app + +# Set working directory +WORKDIR /app + +# Copy Python dependencies from builder stage +COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages/ + +# Copy the application source +COPY --from=builder /app/integrations_finder.py /app/ + +# Switch to non-root user +USER app + +# Set environment variables +ENV PYTHONPATH=/usr/local/lib/python3.11/site-packages +ENV PATH=/usr/local/bin:$PATH + +# Default command +ENTRYPOINT ["python", "/app/integrations_finder.py"] +CMD ["--help"] diff --git a/Makefile b/Makefile index 6d8b9d4..f9a6bf4 100644 --- a/Makefile +++ b/Makefile @@ -1,31 +1,84 @@ -# Makefile for SUSE Observability Integrations Finder -# Cross-platform build targets +# Makefile for Agent Integrations Finder +# Cross-platform build and packaging targets -.PHONY: help clean install-deps build-all build-linux-x86_64 build-linux-aarch64 build-macos-x86_64 build-macos-aarch64 build-win-x86_64 +.PHONY: help clean install-deps install-system-deps build-all package-all \ + build-linux-x86_64 build-linux-aarch64 build-macos-x86_64 build-macos-aarch64 build-win-x86_64 \ + package-linux-x86_64 package-linux-aarch64 package-macos-x86_64 package-macos-aarch64 package-win-x86_64 \ + deb-linux-x86_64 deb-linux-aarch64 rpm-linux-x86_64 rpm-linux-aarch64 \ + msi-win-x86_64 pkg-macos-x86_64 pkg-macos-aarch64 \ + docker-build docker-push docker-amd64 docker-arm64 docker-cleanup \ + test run-gui run-cli # Default target help: - @echo "SUSE Observability Integrations Finder - Build Targets" + @echo "Agent Integrations Finder - Build and Packaging Targets" @echo "" - @echo "Available targets:" - @echo " install-deps - Install build dependencies" - @echo " clean - Clean build artifacts" - @echo " build-all - Build for all platforms" - @echo " build-linux-x86_64 - Build Linux x86_64 executable" - @echo " build-linux-aarch64 - Build Linux aarch64 executable" - @echo " build-macos-x86_64 - Build macOS x86_64 executable" - @echo " build-macos-aarch64 - Build macOS aarch64 executable" - @echo " build-win-x86_64 - Build Windows x86_64 executable" + @echo "Dependencies:" + @echo " install-deps - Install Python build dependencies" + @echo " install-system-deps - Install system packaging tools (Linux)" + @echo "" + @echo "Build Targets:" + @echo " build-all - Build executables for all platforms" + @echo " build-linux-x86_64 - Build Linux x86_64 executable" + @echo " build-linux-aarch64 - Build Linux aarch64 executable" + @echo " build-macos-x86_64 - Build macOS x86_64 executable" + @echo " build-macos-aarch64 - Build macOS aarch64 executable" + @echo " build-win-x86_64 - Build Windows x86_64 executable" + @echo "" + @echo "Package Targets:" + @echo " package-all - Build and package for all platforms" + @echo " package-linux-x86_64 - Build and package Linux x86_64 (.tar.gz, .deb, .rpm)" + @echo " package-linux-aarch64- Build and package Linux aarch64 (.tar.gz, .deb, .rpm)" + @echo " package-macos-x86_64 - Build and package macOS x86_64 (.tar.gz, .pkg)" + @echo " package-macos-aarch64- Build and package macOS aarch64 (.tar.gz, .pkg)" + @echo " package-win-x86_64 - Build and package Windows x86_64 (.zip, .msi)" + @echo "" + @echo "Docker Targets:" + @echo " docker-build - Build Docker images for all architectures" + @echo " docker-push - Build and push Docker images to registry" + @echo " docker-amd64 - Build Docker image for amd64 only" + @echo " docker-arm64 - Build Docker image for arm64 only" + @echo " docker-cleanup - Clean up local Docker images" + @echo "" + @echo "Individual Package Targets:" + @echo " deb-linux-x86_64 - Create .deb package for Linux x86_64" + @echo " deb-linux-aarch64 - Create .deb package for Linux aarch64" + @echo " rpm-linux-x86_64 - Create .rpm package for Linux x86_64" + @echo " rpm-linux-aarch64 - Create .rpm package for Linux aarch64" + @echo " msi-win-x86_64 - Create .msi package for Windows x86_64" + @echo " pkg-macos-x86_64 - Create .pkg package for macOS x86_64" + @echo " pkg-macos-aarch64 - Create .pkg package for macOS aarch64" + @echo "" + @echo "Development Targets:" + @echo " test - Run tests" + @echo " run-gui - Run GUI application" + @echo " run-cli - Run CLI application with demo" + @echo " clean - Clean build artifacts" @echo "" @echo "Examples:" - @echo " make build-linux-x86_64" - @echo " make build-all" + @echo " make install-deps install-system-deps" + @echo " make package-linux-x86_64" + @echo " make deb-linux-x86_64" + @echo " make docker-build" + @echo " make docker-push" + @echo " make package-all" + @echo " make test" -# Install build dependencies +# Install Python build dependencies install-deps: - @echo "Installing build dependencies..." + @echo "Installing Python build dependencies..." pip install -r build_requirements.txt - @echo "Build dependencies installed." + @echo "Python build dependencies installed." + +# Install system packaging tools (Linux only) +install-system-deps: + @echo "Installing system packaging tools..." + @if [ "$$(uname)" = "Linux" ]; then \ + sudo apt-get update && sudo apt-get install -y dpkg-dev rpm rpm-build; \ + echo "System packaging tools installed."; \ + else \ + echo "System packaging tools installation skipped (not on Linux)"; \ + fi # Clean build artifacts clean: @@ -33,39 +86,153 @@ clean: rm -rf build/ rm -rf dist/ rm -rf packages/ + rm -rf temp_*/ rm -f *.spec @echo "Clean complete." -# Build all platforms +# Build all platforms (executables only) build-all: build-linux-x86_64 build-linux-aarch64 build-macos-x86_64 build-macos-aarch64 build-win-x86_64 @echo "All builds completed!" +# Package all platforms (executables + system packages) +package-all: package-linux-x86_64 package-linux-aarch64 package-macos-x86_64 package-macos-aarch64 package-win-x86_64 + @echo "All packages created!" + @echo "Available packages:" + @ls -la packages/ 2>/dev/null || echo "No packages found" + # Linux x86_64 build-linux-x86_64: @echo "Building Linux x86_64..." python3 build.py linux-x86_64 +package-linux-x86_64: build-linux-x86_64 + @echo "Packaging Linux x86_64 completed" + # Linux aarch64 build-linux-aarch64: @echo "Building Linux aarch64..." python3 build.py linux-aarch64 +package-linux-aarch64: build-linux-aarch64 + @echo "Packaging Linux aarch64 completed" + # macOS x86_64 build-macos-x86_64: @echo "Building macOS x86_64..." python3 build.py macos-x86_64 +package-macos-x86_64: build-macos-x86_64 + @echo "Packaging macOS x86_64 completed" + # macOS aarch64 build-macos-aarch64: @echo "Building macOS aarch64..." python3 build.py macos-aarch64 +package-macos-aarch64: build-macos-aarch64 + @echo "Packaging macOS aarch64 completed" + # Windows x86_64 build-win-x86_64: @echo "Building Windows x86_64..." python3 build.py win-x86_64 +package-win-x86_64: build-win-x86_64 + @echo "Packaging Windows x86_64 completed" + +# Individual package format targets +# Linux .deb packages +deb-linux-x86_64: build-linux-x86_64 + @echo "Creating .deb package for Linux x86_64..." + @python3 build.py linux-x86_64 --create-deb-only + +deb-linux-aarch64: build-linux-aarch64 + @echo "Creating .deb package for Linux aarch64..." + @python3 build.py linux-aarch64 --create-deb-only + +# Linux .rpm packages +rpm-linux-x86_64: build-linux-x86_64 + @echo "Creating .rpm package for Linux x86_64..." + @python3 build.py linux-x86_64 --create-rpm-only + +rpm-linux-aarch64: build-linux-aarch64 + @echo "Creating .rpm package for Linux aarch64..." + @python3 build.py linux-aarch64 --create-rpm-only + +# Windows .msi package +msi-win-x86_64: build-win-x86_64 + @echo "Creating .msi package for Windows x86_64..." + @python3 build.py win-x86_64 --create-msi-only + +# macOS .pkg packages +pkg-macos-x86_64: build-macos-x86_64 + @echo "Creating .pkg package for macOS x86_64..." + @python3 build.py macos-x86_64 --create-pkg-only + +pkg-macos-aarch64: build-macos-aarch64 + @echo "Creating .pkg package for macOS aarch64..." + @python3 build.py macos-aarch64 --create-pkg-only + +# Docker targets +docker-build: + @echo "Building Docker images for all architectures..." + @./docker-build.sh build + +docker-push: + @echo "Building and pushing Docker images to registry..." + @./docker-build.sh push + +docker-amd64: + @echo "Building Docker image for amd64..." + @./docker-build.sh amd64 + +docker-arm64: + @echo "Building Docker image for arm64..." + @./docker-build.sh arm64 + +docker-cleanup: + @echo "Cleaning up Docker images..." + @./docker-build.sh cleanup + +# Development targets +test: + @echo "Running tests..." + python3 test_finder.py + @echo "Tests completed." + +run-gui: + @echo "Starting GUI application..." + python3 integrations_finder.py gui + +run-cli: + @echo "Running CLI demo..." + python3 integrations_finder.py find a1b2c3d4 + # Quick build for current platform build-current: @echo "Building for current platform..." python3 build.py all + +# Show package information +list-packages: + @echo "Available packages:" + @if [ -d packages ]; then \ + ls -la packages/; \ + else \ + echo "No packages directory found. Run 'make package-all' first."; \ + fi + +# Show build information +info: + @echo "Agent Integrations Finder Build Information" + @echo "==========================================" + @echo "Python version: $$(python3 --version)" + @echo "Platform: $$(uname -s) $$(uname -m)" + @echo "Build directory: $$(pwd)" + @echo "" + @echo "Available build tools:" + @command -v dpkg-deb >/dev/null 2>&1 && echo "✓ dpkg-deb (for .deb packages)" || echo "✗ dpkg-deb (for .deb packages)" + @command -v rpmbuild >/dev/null 2>&1 && echo "✓ rpmbuild (for .rpm packages)" || echo "✗ rpmbuild (for .rpm packages)" + @command -v pkgbuild >/dev/null 2>&1 && echo "✓ pkgbuild (for .pkg packages)" || echo "✗ pkgbuild (for .pkg packages)" + @command -v candle >/dev/null 2>&1 && echo "✓ WiX candle (for .msi packages)" || echo "✗ WiX candle (for .msi packages)" + @command -v light >/dev/null 2>&1 && echo "✓ WiX light (for .msi packages)" || echo "✗ WiX light (for .msi packages)" diff --git a/PACKAGING.md b/PACKAGING.md new file mode 100644 index 0000000..4010885 --- /dev/null +++ b/PACKAGING.md @@ -0,0 +1,134 @@ +# Packaging System + +The Agent Integrations Finder build system creates multiple package formats for different platforms and use cases. + +## Package Formats + +### Linux Packages + +#### Archive Packages +- **`.tar.gz`**: Portable archive containing the executable and dependencies + - `agent-integrations-finder-linux-x86_64.tar.gz` + - `agent-integrations-finder-linux-aarch64.tar.gz` + +#### System Packages +- **`.deb`**: Debian/Ubuntu package for easy installation + - `agent-integrations-finder_1.0.0_amd64.deb` + - `agent-integrations-finder_1.0.0_aarch64.deb` + - Installs executable to `/usr/local/bin/agent-integrations-finder` + - Dependencies in `/usr/local/bin/_internal/` + +- **`.rpm`**: Red Hat/Fedora/CentOS package for easy installation + - `agent-integrations-finder-1.0.0-1.x86_64.rpm` + - `agent-integrations-finder-1.0.0-1.aarch64.rpm` + - Installs executable to `/usr/local/bin/agent-integrations-finder` + - Dependencies in `/usr/local/bin/_internal/` + +### Windows Packages + +#### Archive Packages +- **`.zip`**: Portable archive containing the executable and dependencies + - `agent-integrations-finder-win-x86_64.zip` + +#### System Packages +- **`.msi`**: Microsoft Installer package for easy installation + - `agent-integrations-finder-1.0.0-x86_64.msi` + - Installs to `C:\Program Files\agent-integrations-finder\` + - Creates Start Menu shortcuts + - Handles uninstallation + +### macOS Packages + +#### Archive Packages +- **`.tar.gz`**: Portable archive containing the executable and dependencies + - `agent-integrations-finder-macos-x86_64.tar.gz` + - `agent-integrations-finder-macos-aarch64.tar.gz` + +#### System Packages +- **`.pkg`**: macOS Package Installer for easy installation + - `agent-integrations-finder-1.0.0-x86_64.pkg` + - `agent-integrations-finder-1.0.0-aarch64.pkg` + - Installs executable to `/usr/local/bin/agent-integrations-finder` + - Dependencies in `/usr/local/bin/_internal/` + +## Installation Methods + +### Linux + +#### Using .deb package (Debian/Ubuntu) +```bash +sudo dpkg -i agent-integrations-finder_1.0.0_amd64.deb +``` + +#### Using .rpm package (Red Hat/Fedora/CentOS) +```bash +sudo rpm -i agent-integrations-finder-1.0.0-1.x86_64.rpm +``` + +#### Using .tar.gz archive +```bash +tar -xzf agent-integrations-finder-linux-x86_64.tar.gz +cd agent-integrations-finder +./agent-integrations-finder --help +``` + +### Windows + +#### Using .msi package +1. Double-click the `.msi` file +2. Follow the installation wizard +3. Use from Start Menu or `C:\Program Files\agent-integrations-finder\` + +#### Using .zip archive +1. Extract the `.zip` file +2. Run `agent-integrations-finder.exe` from the extracted folder + +### macOS + +#### Using .pkg package +1. Double-click the `.pkg` file +2. Follow the installation wizard +3. Use from Terminal: `agent-integrations-finder --help` + +#### Using .tar.gz archive +```bash +tar -xzf agent-integrations-finder-macos-x86_64.tar.gz +cd agent-integrations-finder +./agent-integrations-finder --help +``` + +## Build Requirements + +### Local Development (Linux) +- **Python 3.11+** +- **PyInstaller**: `pip install -r build_requirements.txt` +- **dpkg-dev**: For .deb package creation (Ubuntu/Debian) +- **rpm-build**: For .rpm package creation (Red Hat/Fedora) + +### GitHub Actions +- **Linux runners**: Include dpkg-dev and rpm-build tools +- **Windows runners**: Would need WiX tools for .msi creation +- **macOS runners**: Include pkgbuild by default + +## Package Contents + +All packages include: +- **Executable**: `agent-integrations-finder` (or `.exe` on Windows) +- **Dependencies**: All required Python libraries and system dependencies +- **Assets**: Application icons and resources +- **Documentation**: Built-in help and usage information + +## Version Management + +Package versions are managed in the build script: +- **Version**: `1.0.0` (configurable in `build.py`) +- **Architecture**: `x86_64`, `aarch64` (automatically detected) +- **Platform**: `linux`, `win`, `macos` (automatically detected) + +## Customization + +To modify package contents or metadata: +1. Edit the package creation methods in `build.py` +2. Update version numbers in the build script +3. Modify package descriptions and metadata +4. Add additional files or dependencies as needed diff --git a/README.md b/README.md index e3e274a..2f198b7 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,48 @@ A tool to trace from SUSE Observability Agent container tags to the correspondin ### Option 2: Use Pre-built Executables -Download the latest release from the [Releases page](https://github.com/StackVista/stackstate-agent-integrations/releases) and extract the appropriate package for your platform. +Download the latest release from the [Releases page](https://github.com/StackVista/stackstate-agent-integrations/releases) and choose the appropriate package for your platform: + +#### Archive Packages (Portable) +- **Linux**: `agent-integrations-finder-linux-x86_64.tar.gz` or `agent-integrations-finder-linux-aarch64.tar.gz` +- **Windows**: `agent-integrations-finder-win-x86_64.zip` +- **macOS**: `agent-integrations-finder-macos-x86_64.tar.gz` or `agent-integrations-finder-macos-aarch64.tar.gz` + +#### System Packages (Easy Installation) +- **Linux (Debian/Ubuntu)**: `agent-integrations-finder_1.0.0_amd64.deb` +- **Linux (Red Hat/Fedora)**: `agent-integrations-finder-1.0.0-1.x86_64.rpm` +- **Windows**: `agent-integrations-finder-1.0.0-x86_64.msi` +- **macOS**: `agent-integrations-finder-1.0.0-x86_64.pkg` + +For detailed installation instructions, see [PACKAGING.md](PACKAGING.md). ## Installation +### Using Docker (Recommended) +The easiest way to run Agent Integrations Finder is using Docker: + +```bash +# Pull and run the latest version +docker run --rm ghcr.io/stackvista/agent-integrations-finder:latest --help + +# Run with a specific version +docker run --rm ghcr.io/stackvista/agent-integrations-finder:v1.0.0 --help + +# Run GUI (requires X11 forwarding on Linux/macOS) +docker run --rm -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix \ + ghcr.io/stackvista/agent-integrations-finder:latest gui + +# Run CLI with specific SHA +docker run --rm ghcr.io/stackvista/agent-integrations-finder:latest find a1b2c3d4 +``` + +**Available Docker Images:** +- `ghcr.io/stackvista/agent-integrations-finder:latest` - Latest stable version +- `ghcr.io/stackvista/agent-integrations-finder:v1.0.0` - Specific version +- `ghcr.io/stackvista/agent-integrations-finder:` - Specific commit +- `ghcr.io/stackvista/agent-integrations-finder:-amd64` - AMD64 architecture only +- `ghcr.io/stackvista/agent-integrations-finder:-arm64` - ARM64 architecture only + ### From Source ```bash @@ -132,6 +170,33 @@ Icons are automatically detected and used based on platform requirements. The `c 1. **Direct Build**: `python build.py -` 2. **Docker Build**: `./build-docker.sh -` 3. **Makefile**: `make build--` +4. **Docker Images**: `make docker-build` or `./docker-build.sh build` + +### Docker Build System + +The project includes a comprehensive Docker build system for creating multi-architecture container images: + +```bash +# Build Docker images for all architectures (local) +make docker-build + +# Build and push to GitHub Container Registry +make docker-push + +# Build specific architecture +make docker-amd64 +make docker-arm64 + +# Clean up Docker images +make docker-cleanup +``` + +**Docker Build Features:** +- Multi-architecture support (AMD64, ARM64) +- Automatic tagging with git SHA and version tags +- GitHub Container Registry integration +- Multi-architecture manifests +- Build caching for faster builds **Note**: Windows builds use Python's built-in `zipfile` module for packaging, ensuring compatibility across all Windows environments. diff --git a/build.py b/build.py index 2081f15..f1f20df 100755 --- a/build.py +++ b/build.py @@ -177,6 +177,328 @@ def build(self, target_platform, target_arch): print(f"stderr: {e.stderr}") return False + def create_deb_package(self, target_platform, target_arch, source_dir, output_dir): + """Create .deb package for Debian/Ubuntu""" + print("Creating .deb package...") + + # Create package structure + package_name = "agent-integrations-finder" + package_version = "1.0.0" + + # Convert architecture names to Debian format + deb_arch = target_arch.replace("x86_64", "amd64").replace("aarch64", "arm64") + deb_name = f"{package_name}_{package_version}_{deb_arch}.deb" + deb_path = output_dir / deb_name + + # Create temporary directory structure + temp_dir = self.project_root / "temp_deb" + if temp_dir.exists(): + shutil.rmtree(temp_dir) + temp_dir.mkdir() + + # Create DEBIAN control file + debian_dir = temp_dir / "DEBIAN" + debian_dir.mkdir() + + control_content = f"""Package: {package_name} +Version: {package_version} +Architecture: {deb_arch} +Maintainer: SUSE Observability Team +Description: Agent Integrations Finder + A tool to trace from SUSE Observability Agent container tags to the corresponding integrations source code. + Provides both CLI and GUI interfaces for finding integration source code. + Installs executable to /usr/local/bin/agent-integrations-finder +""" + + with open(debian_dir / "control", "w") as f: + f.write(control_content) + + # Create usr/local/bin directory and copy executable + bin_dir = temp_dir / "usr" / "local" / "bin" + bin_dir.mkdir(parents=True) + + # Copy the executable + executable = source_dir / "agent-integrations-finder" + if executable.exists(): + shutil.copy2(executable, bin_dir / "agent-integrations-finder") + os.chmod(bin_dir / "agent-integrations-finder", 0o755) + + # Copy _internal directory to /usr/local/bin (where PyInstaller expects it) + bin_internal_dir = temp_dir / "usr" / "local" / "bin" / "_internal" + bin_internal_dir.mkdir(parents=True) + + internal_dir = source_dir / "_internal" + if internal_dir.exists(): + shutil.copytree(internal_dir, bin_internal_dir, dirs_exist_ok=True) + + # Create .deb package using dpkg-deb + try: + cmd = ["dpkg-deb", "--build", str(temp_dir), str(deb_path)] + subprocess.run(cmd, check=True) + print(f"Created .deb package: {deb_path}") + except (subprocess.CalledProcessError, FileNotFoundError): + print("Warning: dpkg-deb not available, skipping .deb package creation") + finally: + # Clean up + shutil.rmtree(temp_dir) + + def create_rpm_package(self, target_platform, target_arch, source_dir, output_dir): + """Create .rpm package for Red Hat/Fedora/CentOS""" + print("Creating .rpm package...") + + # Create package structure + package_name = "agent-integrations-finder" + package_version = "1.0.0" + rpm_name = f"{package_name}-{package_version}-1.{target_arch}.rpm" + rpm_path = output_dir / rpm_name + + # Create temporary directory structure + temp_dir = self.project_root / "temp_rpm" + if temp_dir.exists(): + shutil.rmtree(temp_dir) + temp_dir.mkdir() + + # Create RPM build structure + rpm_build_dir = temp_dir / "rpmbuild" + rpm_build_dir.mkdir() + + # Create SPEC file + spec_content = f"""Name: {package_name} +Version: {package_version} +Release: 1 +Summary: Agent Integrations Finder +License: BSD-3-Clause +URL: https://github.com/StackVista/Integrations-Finder +BuildArch: {target_arch} + +%description +A tool to trace from SUSE Observability Agent container tags to the corresponding integrations source code. +Provides both CLI and GUI interfaces for finding integration source code. + +%files +%defattr(-,root,root,-) +/usr/local/bin/agent-integrations-finder +/usr/local/lib/{package_name}/ + +%post +chmod +x /usr/local/bin/agent-integrations-finder + +%clean +rm -rf $RPM_BUILD_ROOT +""" + + spec_file = temp_dir / f"{package_name}.spec" + with open(spec_file, "w") as f: + f.write(spec_content) + + # Create buildroot structure + buildroot = rpm_build_dir / "BUILDROOT" / f"{package_name}-{package_version}-1.{target_arch}" + buildroot.mkdir(parents=True) + + # Copy files to buildroot + bin_dir = buildroot / "usr" / "local" / "bin" + bin_dir.mkdir(parents=True) + + executable = source_dir / "agent-integrations-finder" + if executable.exists(): + shutil.copy2(executable, bin_dir / "agent-integrations-finder") + os.chmod(bin_dir / "agent-integrations-finder", 0o755) + + lib_dir = buildroot / "usr" / "local" / "lib" / package_name + lib_dir.mkdir(parents=True) + + internal_dir = source_dir / "_internal" + if internal_dir.exists(): + shutil.copytree(internal_dir, lib_dir / "_internal") + + # Try to build RPM using rpmbuild + try: + cmd = ["rpmbuild", "--define", f"_topdir {rpm_build_dir}", "-bb", str(spec_file)] + subprocess.run(cmd, check=True) + + # Find and copy the built RPM + rpm_dir = rpm_build_dir / "RPMS" / target_arch + if rpm_dir.exists(): + for rpm_file in rpm_dir.glob("*.rpm"): + shutil.copy2(rpm_file, rpm_path) + print(f"Created .rpm package: {rpm_path}") + break + except (subprocess.CalledProcessError, FileNotFoundError): + print("Warning: rpmbuild not available, skipping .rpm package creation") + finally: + # Clean up + shutil.rmtree(temp_dir) + + def create_msi_package(self, target_platform, target_arch, source_dir, output_dir): + """Create .msi package for Windows""" + print("Creating .msi package...") + + # Create package structure + package_name = "agent-integrations-finder" + package_version = "1.0.0" + msi_name = f"{package_name}-{package_version}-{target_arch}.msi" + msi_path = output_dir / msi_name + + # Create temporary directory structure + temp_dir = self.project_root / "temp_msi" + if temp_dir.exists(): + shutil.rmtree(temp_dir) + temp_dir.mkdir() + + # Copy files to temp directory + program_files = temp_dir / "Program Files" / package_name + program_files.mkdir(parents=True) + + # Copy the executable + executable = source_dir / "agent-integrations-finder.exe" + if executable.exists(): + shutil.copy2(executable, program_files / "agent-integrations-finder.exe") + + # Copy _internal directory + internal_dir = source_dir / "_internal" + if internal_dir.exists(): + shutil.copytree(internal_dir, program_files / "_internal") + + # Create WiX XML file for MSI + wix_content = f""" + + + + + + + + + + + + + + + + + + + + + + + + + + + +""" + + wix_file = temp_dir / f"{package_name}.wxs" + with open(wix_file, "w") as f: + f.write(wix_content) + + # Try to build MSI using WiX + try: + cmd = ["candle", str(wix_file), "-out", str(temp_dir / f"{package_name}.wixobj")] + subprocess.run(cmd, check=True) + + cmd = ["light", str(temp_dir / f"{package_name}.wixobj"), "-out", str(msi_path)] + subprocess.run(cmd, check=True) + + print(f"Created .msi package: {msi_path}") + except (subprocess.CalledProcessError, FileNotFoundError): + print("Warning: WiX tools not available, skipping .msi package creation") + finally: + # Clean up + shutil.rmtree(temp_dir) + + def create_pkg_package(self, target_platform, target_arch, source_dir, output_dir): + """Create .pkg package for macOS""" + print("Creating .pkg package...") + + # Create package structure + package_name = "agent-integrations-finder" + package_version = "1.0.0" + pkg_name = f"{package_name}-{package_version}-{target_arch}.pkg" + pkg_path = output_dir / pkg_name + + # Create temporary directory structure + temp_dir = self.project_root / "temp_pkg" + if temp_dir.exists(): + shutil.rmtree(temp_dir) + temp_dir.mkdir() + + # Create package structure + pkg_root = temp_dir / "pkgroot" + pkg_root.mkdir() + + # Copy files to /usr/local/bin and /usr/local/lib + bin_dir = pkg_root / "usr" / "local" / "bin" + bin_dir.mkdir(parents=True) + + executable = source_dir / "agent-integrations-finder" + if executable.exists(): + shutil.copy2(executable, bin_dir / "agent-integrations-finder") + os.chmod(bin_dir / "agent-integrations-finder", 0o755) + + lib_dir = pkg_root / "usr" / "local" / "lib" / package_name + lib_dir.mkdir(parents=True) + + internal_dir = source_dir / "_internal" + if internal_dir.exists(): + shutil.copytree(internal_dir, lib_dir / "_internal") + + # Create package info + info_dir = temp_dir / "package_info" + info_dir.mkdir() + + info_content = f""" + + + + + + + + + + + + +""" + + with open(info_dir / "PackageInfo", "w") as f: + f.write(info_content) + + # Create postinstall script + postinstall_content = """#!/bin/bash +chmod +x /usr/local/bin/agent-integrations-finder +""" + + with open(info_dir / "postinstall", "w") as f: + f.write(postinstall_content) + os.chmod(info_dir / "postinstall", 0o755) + + # Try to build pkg using pkgbuild + try: + cmd = [ + "pkgbuild", + "--root", + str(pkg_root), + "--identifier", + f"com.suse.observability.{package_name}", + "--version", + package_version, + "--install-location", + "/", + str(pkg_path), + ] + subprocess.run(cmd, check=True) + print(f"Created .pkg package: {pkg_path}") + except (subprocess.CalledProcessError, FileNotFoundError): + print("Warning: pkgbuild not available, skipping .pkg package creation") + finally: + # Clean up + shutil.rmtree(temp_dir) + def package(self, target_platform, target_arch): """Package the built executable""" print(f"Packaging for {target_platform}-{target_arch}...") @@ -194,7 +516,16 @@ def package(self, target_platform, target_arch): output_dir = self.project_root / "packages" output_dir.mkdir(exist_ok=True) - # Package based on platform + # Create system packages first + if target_platform == "linux": + self.create_deb_package(target_platform, target_arch, source_dir, output_dir) + self.create_rpm_package(target_platform, target_arch, source_dir, output_dir) + elif target_platform == "win": + self.create_msi_package(target_platform, target_arch, source_dir, output_dir) + elif target_platform == "macos": + self.create_pkg_package(target_platform, target_arch, source_dir, output_dir) + + # Package based on platform (original tar.gz/zip packages) if target_platform == "linux": # Create tar.gz archive_name = f"agent-integrations-finder-{target_platform}-{target_arch}.tar.gz" @@ -244,11 +575,13 @@ def package(self, target_platform, target_arch): print(f"Package created: {archive_path}") return True + pass + def main(): """Main build function""" if len(sys.argv) < 2 or sys.argv[1] in ["-h", "--help", "help"]: - print("Usage: python build.py ") + print("Usage: python build.py [options]") print("Targets:") print(" linux-x86_64") print(" linux-aarch64") @@ -256,25 +589,46 @@ def main(): print(" macos-aarch64") print(" win-x86_64") print(" all") + print(" docker-amd64") + print(" docker-arm64") + print(" docker-all") + print("") + print("Options:") + print(" --create-deb-only - Create only .deb package (Linux)") + print(" --create-rpm-only - Create only .rpm package (Linux)") + print(" --create-msi-only - Create only .msi package (Windows)") + print(" --create-pkg-only - Create only .pkg package (macOS)") print("") print("Examples:") print(" python build.py linux-x86_64") + print(" python build.py linux-x86_64 --create-deb-only") + print(" python build.py docker-all") print(" python build.py all") sys.exit(1) target = sys.argv[1] builder = Builder() + # Check for package-only options + create_deb_only = "--create-deb-only" in sys.argv + create_rpm_only = "--create-rpm-only" in sys.argv + create_msi_only = "--create-msi-only" in sys.argv + create_pkg_only = "--create-pkg-only" in sys.argv + targets = { "linux-x86_64": ("linux", "x86_64"), "linux-aarch64": ("linux", "aarch64"), "macos-x86_64": ("macos", "x86_64"), "macos-aarch64": ("macos", "aarch64"), "win-x86_64": ("win", "x86_64"), + "docker-amd64": ("docker", "amd64"), + "docker-arm64": ("docker", "arm64"), } if target == "all": build_targets = targets.values() + elif target == "docker-all": + build_targets = [("docker", "amd64"), ("docker", "arm64")] elif target in targets: build_targets = [targets[target]] else: @@ -290,8 +644,47 @@ def main(): print(f"Building {platform_name}-{arch}") print(f"{'=' * 50}") - if builder.build(platform_name, arch): - builder.package(platform_name, arch) + if platform_name == "docker": + # Handle Docker builds + print(f"Building Docker image for {arch}...") + if builder.build("linux", arch.replace("amd64", "x86_64").replace("arm64", "aarch64")): + print(f"Docker build preparation completed for {arch}") + else: + print(f"Failed to prepare Docker build for {arch}") + sys.exit(1) + elif builder.build(platform_name, arch): + # Handle package-only options + if create_deb_only and platform_name == "linux": + builder.create_deb_package( + platform_name, + arch, + builder.get_platform_dist_dir(platform_name, arch) / "agent-integrations-finder", + builder.project_root / "packages", + ) + elif create_rpm_only and platform_name == "linux": + builder.create_rpm_package( + platform_name, + arch, + builder.get_platform_dist_dir(platform_name, arch) / "agent-integrations-finder", + builder.project_root / "packages", + ) + elif create_msi_only and platform_name == "win": + builder.create_msi_package( + platform_name, + arch, + builder.get_platform_dist_dir(platform_name, arch) / "agent-integrations-finder", + builder.project_root / "packages", + ) + elif create_pkg_only and platform_name == "macos": + builder.create_pkg_package( + platform_name, + arch, + builder.get_platform_dist_dir(platform_name, arch) / "agent-integrations-finder", + builder.project_root / "packages", + ) + else: + # Normal packaging (all formats) + builder.package(platform_name, arch) else: print(f"Failed to build {platform_name}-{arch}") sys.exit(1) diff --git a/build_requirements.txt b/build_requirements.txt index 4adb79a..d3983c7 100644 --- a/build_requirements.txt +++ b/build_requirements.txt @@ -2,3 +2,4 @@ pyinstaller>=6.0.0 requests>=2.31.0 click>=8.1.0 pillow>=10.0.0 +PyQt6>=6.5.0 diff --git a/docker-build.sh b/docker-build.sh new file mode 100755 index 0000000..f1eb89b --- /dev/null +++ b/docker-build.sh @@ -0,0 +1,315 @@ +#!/bin/bash + +# Docker build script for Agent Integrations Finder +# Supports multi-architecture builds and GitHub Container Registry + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$SCRIPT_DIR" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to print colored output +print_status() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +print_step() { + echo -e "${BLUE}[STEP]${NC} $1" +} + +# Configuration +REGISTRY="ghcr.io" +REPO="stackvista/agent-integrations-finder" +IMAGE_NAME="${REGISTRY}/${REPO}" + +# Get git information +GIT_SHA=$(git rev-parse --short=8 HEAD) +GIT_TAG=$(git describe --tags --exact-match 2>/dev/null || echo "") + +# Check if Docker is available +check_docker() { + if ! command -v docker &> /dev/null; then + print_error "Docker is not installed or not in PATH" + exit 1 + fi + + if ! docker info &> /dev/null; then + print_error "Docker is not running or you don't have permissions" + exit 1 + fi +} + +# Check if docker buildx is available +check_buildx() { + if ! docker buildx version &> /dev/null; then + print_error "Docker buildx is not available" + exit 1 + fi +} + +# Create and use buildx builder +setup_builder() { + print_step "Setting up Docker buildx builder..." + + # Create a new builder if it doesn't exist + if ! docker buildx inspect multiarch-builder &> /dev/null; then + docker buildx create --name multiarch-builder --use + else + docker buildx use multiarch-builder + fi + + # Bootstrap the builder + docker buildx inspect --bootstrap +} + +# Build for a specific architecture +build_architecture() { + local arch=$1 + local platform="linux/${arch}" + + print_step "Building for ${arch}..." + + # Build the executable first + print_status "Building executable for ${arch}..." + # Convert architecture names for build.py + build_arch=${arch} + if [[ "${arch}" == "amd64" ]]; then + build_arch="x86_64" + elif [[ "${arch}" == "arm64" ]]; then + build_arch="aarch64" + fi + python3 build.py linux-${build_arch} + + # Build Docker image + print_status "Building Docker image for ${arch}..." + docker buildx build \ + --platform ${platform} \ + --tag ${IMAGE_NAME}:${GIT_SHA}-${arch} \ + --file Dockerfile \ + --load \ + . + + # Tag with version if this is a release + if [[ -n "${GIT_TAG}" ]]; then + print_status "Tagging release image for ${arch}..." + docker tag ${IMAGE_NAME}:${GIT_SHA}-${arch} ${IMAGE_NAME}:${GIT_TAG}-${arch} + fi +} + +# Create multi-architecture manifest +create_manifest() { + print_step "Creating multi-architecture manifest..." + + # Build for both architectures + build_architecture "amd64" + build_architecture "arm64" + + # Create manifest with git SHA + print_status "Creating manifest with tag: ${GIT_SHA}" + docker buildx build \ + --platform linux/amd64,linux/arm64 \ + --tag ${IMAGE_NAME}:${GIT_SHA} \ + --file Dockerfile \ + --push \ + . + + # Create manifest with version tag if this is a release + if [[ -n "${GIT_TAG}" ]]; then + print_status "Creating release manifest with tag: ${GIT_TAG}" + docker buildx build \ + --platform linux/amd64,linux/arm64 \ + --tag ${IMAGE_NAME}:${GIT_TAG} \ + --file Dockerfile \ + --push \ + . + fi +} + +# Push individual architecture images +push_architectures() { + print_step "Pushing individual architecture images..." + + # Push amd64 image + print_status "Pushing amd64 image..." + docker push ${IMAGE_NAME}:${GIT_SHA}-amd64 + + # Push arm64 image + print_status "Pushing arm64 image..." + docker push ${IMAGE_NAME}:${GIT_SHA}-arm64 + + # Push versioned images if this is a release + if [[ -n "${GIT_TAG}" ]]; then + print_status "Pushing versioned images..." + docker push ${IMAGE_NAME}:${GIT_TAG}-amd64 + docker push ${IMAGE_NAME}:${GIT_TAG}-arm64 + fi +} + +# Build and push all images +build_and_push() { + print_step "Building and pushing all images..." + + # Build for both architectures and create manifest + docker buildx build \ + --platform linux/amd64,linux/arm64 \ + --tag ${IMAGE_NAME}:${GIT_SHA} \ + --tag ${IMAGE_NAME}:${GIT_SHA}-amd64 \ + --tag ${IMAGE_NAME}:${GIT_SHA}-arm64 \ + --file Dockerfile \ + --push \ + . + + # Add version tags if this is a release + if [[ -n "${GIT_TAG}" ]]; then + print_status "Adding version tags..." + docker buildx build \ + --platform linux/amd64,linux/arm64 \ + --tag ${IMAGE_NAME}:${GIT_TAG} \ + --tag ${IMAGE_NAME}:${GIT_TAG}-amd64 \ + --tag ${IMAGE_NAME}:${GIT_TAG}-arm64 \ + --file Dockerfile \ + --push \ + . + fi +} + +# Build only (no push) +build_only() { + print_step "Building images (no push)..." + + # Build for both architectures + build_architecture "amd64" + build_architecture "arm64" + + # Create local manifest + print_status "Creating local manifest..." + docker buildx build \ + --platform linux/amd64,linux/arm64 \ + --tag ${IMAGE_NAME}:${GIT_SHA} \ + --file Dockerfile \ + --load \ + . +} + +# Clean up Docker images +cleanup() { + print_step "Cleaning up Docker images..." + + # Remove local images + docker rmi ${IMAGE_NAME}:${GIT_SHA}-amd64 2>/dev/null || true + docker rmi ${IMAGE_NAME}:${GIT_SHA}-arm64 2>/dev/null || true + docker rmi ${IMAGE_NAME}:${GIT_SHA} 2>/dev/null || true + + if [[ -n "${GIT_TAG}" ]]; then + docker rmi ${IMAGE_NAME}:${GIT_TAG}-amd64 2>/dev/null || true + docker rmi ${IMAGE_NAME}:${GIT_TAG}-arm64 2>/dev/null || true + docker rmi ${IMAGE_NAME}:${GIT_TAG} 2>/dev/null || true + fi +} + +# Show help +show_help() { + echo "Docker build script for Agent Integrations Finder" + echo "" + echo "Usage: $0 [COMMAND]" + echo "" + echo "Commands:" + echo " build - Build images for all architectures (no push)" + echo " push - Build and push all images to registry" + echo " manifest - Create multi-architecture manifest" + echo " amd64 - Build only for amd64 architecture" + echo " arm64 - Build only for arm64 architecture" + echo " cleanup - Clean up local Docker images" + echo " help - Show this help message" + echo "" + echo "Environment:" + echo " GITHUB_TOKEN - GitHub token for pushing to registry" + echo "" + echo "Examples:" + echo " $0 build" + echo " $0 push" + echo " GITHUB_TOKEN=xxx $0 push" +} + +# Main function +main() { + local command=${1:-help} + + print_status "Starting Docker build for Agent Integrations Finder" + print_status "Git SHA: ${GIT_SHA}" + if [[ -n "${GIT_TAG}" ]]; then + print_status "Git Tag: ${GIT_TAG}" + fi + print_status "Registry: ${REGISTRY}" + print_status "Repository: ${REPO}" + + # Check prerequisites + check_docker + check_buildx + setup_builder + + # Execute command + case "$command" in + build) + build_only + ;; + push) + if [[ -z "${GITHUB_TOKEN}" ]]; then + print_error "GITHUB_TOKEN environment variable is required for pushing" + exit 1 + fi + # Login to GitHub Container Registry + echo "${GITHUB_TOKEN}" | docker login ${REGISTRY} -u USERNAME --password-stdin + build_and_push + ;; + manifest) + create_manifest + push_architectures + ;; + amd64) + build_architecture "amd64" + ;; + arm64) + build_architecture "arm64" + ;; + cleanup) + cleanup + ;; + help|--help|-h) + show_help + ;; + *) + print_error "Unknown command: $command" + show_help + exit 1 + ;; + esac + + print_status "Docker build completed successfully!" +} + +# Parse command line arguments +case "${1:-}" in + -h|--help|help) + show_help + exit 0 + ;; + *) + main "$@" + ;; +esac diff --git a/integrations_finder.py b/integrations_finder.py index 4318e5f..79f91af 100644 --- a/integrations_finder.py +++ b/integrations_finder.py @@ -13,21 +13,28 @@ import click import requests -from PyQt6.QtCore import Qt, QThread, QUrl, pyqtSignal -from PyQt6.QtGui import QDesktopServices, QFont, QPixmap -from PyQt6.QtWidgets import ( - QApplication, - QHBoxLayout, - QLabel, - QLineEdit, - QMainWindow, - QMessageBox, - QProgressBar, - QPushButton, - QTextEdit, - QVBoxLayout, - QWidget, -) + +# Import PyQt6 only when needed for GUI functionality +try: + from PyQt6.QtCore import Qt, QThread, QUrl, pyqtSignal + from PyQt6.QtGui import QDesktopServices, QFont, QPixmap + from PyQt6.QtWidgets import ( + QApplication, + QHBoxLayout, + QLabel, + QLineEdit, + QMainWindow, + QMessageBox, + QProgressBar, + QPushButton, + QTextEdit, + QVBoxLayout, + QWidget, + ) + + PYQT6_AVAILABLE = True +except ImportError: + PYQT6_AVAILABLE = False class IntegrationsFinder: @@ -340,13 +347,21 @@ def run(self): self.finished.emit(success, message) -class IntegrationsFinderGUI(QMainWindow): - """GUI for the Agent Integrations Finder tool.""" +if PYQT6_AVAILABLE: - def __init__(self): - super().__init__() - self.finder = IntegrationsFinder() - self.init_ui() + class IntegrationsFinderGUI(QMainWindow): + """GUI for the Agent Integrations Finder tool.""" + + def __init__(self): + super().__init__() + self.finder = IntegrationsFinder() + self.init_ui() + +else: + # Dummy class for when PyQt6 is not available + class IntegrationsFinderGUI: + def __init__(self): + pass def init_ui(self): """Initialize the user interface.""" @@ -578,6 +593,11 @@ def find(input_string): @cli.command() def gui(): """Launch the graphical user interface.""" + if not PYQT6_AVAILABLE: + click.echo("Error: PyQt6 is not available. GUI mode requires PyQt6 to be installed.") + click.echo("Please install PyQt6 with: pip install PyQt6") + sys.exit(1) + app = QApplication(sys.argv) window = IntegrationsFinderGUI() window.show() From 64c06892a976c00f593e1793773c14b23b168bae Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 14 Aug 2025 14:23:42 +0200 Subject: [PATCH 2/8] STAC-0 Add docker build. [2] --- .github/workflows/docker.yml | 40 ++++++++++++++++---------------- integrations_finder.py | 45 +++++++++++++++++++++--------------- 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 74f2abb..6aa1b81 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -10,7 +10,7 @@ on: env: REGISTRY: ghcr.io REPO: stackvista/agent-integrations-finder - IMAGE_NAME: ${{ env.REGISTRY }}/${{ env.REPO }} + IMAGE_NAME: ghcr.io/stackvista/agent-integrations-finder jobs: docker-build: @@ -30,7 +30,7 @@ jobs: if: github.event_name != 'pull_request' uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} @@ -38,7 +38,7 @@ jobs: id: meta uses: docker/metadata-action@v5 with: - images: ${{ env.IMAGE_NAME }} + images: ghcr.io/stackvista/agent-integrations-finder tags: | type=ref,event=branch type=ref,event=pr @@ -74,16 +74,16 @@ jobs: # Build amd64 image docker buildx build \ --platform linux/amd64 \ - --tag ${{ env.IMAGE_NAME }}:${{ github.sha }}-amd64 \ - --tag ${{ env.IMAGE_NAME }}:${{ github.ref_name }}-amd64 \ + --tag ghcr.io/stackvista/agent-integrations-finder:${{ github.sha }}-amd64 \ + --tag ghcr.io/stackvista/agent-integrations-finder:${{ github.ref_name }}-amd64 \ --push \ . # Build arm64 image docker buildx build \ --platform linux/arm64 \ - --tag ${{ env.IMAGE_NAME }}:${{ github.sha }}-arm64 \ - --tag ${{ env.IMAGE_NAME }}:${{ github.ref_name }}-arm64 \ + --tag ghcr.io/stackvista/agent-integrations-finder:${{ github.sha }}-arm64 \ + --tag ghcr.io/stackvista/agent-integrations-finder:${{ github.ref_name }}-arm64 \ --push \ . @@ -91,26 +91,26 @@ jobs: if: github.event_name != 'pull_request' run: | # Create manifest with git SHA - docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${{ github.sha }} \ - ${{ env.IMAGE_NAME }}:${{ github.sha }}-amd64 \ - ${{ env.IMAGE_NAME }}:${{ github.sha }}-arm64 + docker buildx imagetools create -t ghcr.io/stackvista/agent-integrations-finder:${{ github.sha }} \ + ghcr.io/stackvista/agent-integrations-finder:${{ github.sha }}-amd64 \ + ghcr.io/stackvista/agent-integrations-finder:${{ github.sha }}-arm64 # Create manifest with branch/tag name - docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${{ github.ref_name }} \ - ${{ env.IMAGE_NAME }}:${{ github.ref_name }}-amd64 \ - ${{ env.IMAGE_NAME }}:${{ github.ref_name }}-arm64 + docker buildx imagetools create -t ghcr.io/stackvista/agent-integrations-finder:${{ github.ref_name }} \ + ghcr.io/stackvista/agent-integrations-finder:${{ github.ref_name }}-amd64 \ + ghcr.io/stackvista/agent-integrations-finder:${{ github.ref_name }}-arm64 - name: Show image info run: | echo "Built images:" - docker images ${{ env.IMAGE_NAME }} || true + docker images ghcr.io/stackvista/agent-integrations-finder || true echo "" echo "Available tags:" - echo "- ${{ env.IMAGE_NAME }}:${{ github.sha }}" - echo "- ${{ env.IMAGE_NAME }}:${{ github.sha }}-amd64" - echo "- ${{ env.IMAGE_NAME }}:${{ github.sha }}-arm64" + echo "- ghcr.io/stackvista/agent-integrations-finder:${{ github.sha }}" + echo "- ghcr.io/stackvista/agent-integrations-finder:${{ github.sha }}-amd64" + echo "- ghcr.io/stackvista/agent-integrations-finder:${{ github.sha }}-arm64" if [[ "${{ github.ref_name }}" != "${{ github.sha }}" ]]; then - echo "- ${{ env.IMAGE_NAME }}:${{ github.ref_name }}" - echo "- ${{ env.IMAGE_NAME }}:${{ github.ref_name }}-amd64" - echo "- ${{ env.IMAGE_NAME }}:${{ github.ref_name }}-arm64" + echo "- ghcr.io/stackvista/agent-integrations-finder:${{ github.ref_name }}" + echo "- ghcr.io/stackvista/agent-integrations-finder:${{ github.ref_name }}-amd64" + echo "- ghcr.io/stackvista/agent-integrations-finder:${{ github.ref_name }}-arm64" fi diff --git a/integrations_finder.py b/integrations_finder.py index 79f91af..779cfe3 100644 --- a/integrations_finder.py +++ b/integrations_finder.py @@ -321,30 +321,37 @@ def find_integrations(self, input_string: str) -> Tuple[bool, str]: return True, success_message, is_branch -class WorkerThread(QThread): - """Worker thread for GUI to prevent blocking.""" +if PYQT6_AVAILABLE: + class WorkerThread(QThread): + """Worker thread for GUI to prevent blocking.""" - finished = pyqtSignal(bool, str) + finished = pyqtSignal(bool, str) - def __init__(self, finder: IntegrationsFinder, input_string: str): - super().__init__() - self.finder = finder - self.input_string = input_string + def __init__(self, finder: IntegrationsFinder, input_string: str): + super().__init__() + self.finder = finder + self.input_string = input_string - def run(self): - result = self.finder.find_integrations(self.input_string) - if len(result) == 3: - success, message, is_branch = result - else: - # Backward compatibility - success, message = result - is_branch = False + def run(self): + result = self.finder.find_integrations(self.input_string) + if len(result) == 3: + success, message, is_branch = result + else: + # Backward compatibility + success, message = result + is_branch = False - # Add branch indicator to message for GUI detection - if is_branch: - message += "\n[BRANCH_VERSION_DETECTED]" + # Add branch indicator to message for GUI detection + if is_branch: + message += "\n[BRANCH_VERSION_DETECTED]" - self.finished.emit(success, message) + self.finished.emit(success, message) +else: + # Dummy class for when PyQt6 is not available + class WorkerThread: + def __init__(self, finder: IntegrationsFinder, input_string: str): + self.finder = finder + self.input_string = input_string if PYQT6_AVAILABLE: From ef7081171e9f70425b8a0baa2dd184e56c000940 Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 14 Aug 2025 14:25:02 +0200 Subject: [PATCH 3/8] STAC-0 Add docker build. [3] --- integrations_finder.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/integrations_finder.py b/integrations_finder.py index 779cfe3..090dd69 100644 --- a/integrations_finder.py +++ b/integrations_finder.py @@ -322,6 +322,7 @@ def find_integrations(self, input_string: str) -> Tuple[bool, str]: if PYQT6_AVAILABLE: + class WorkerThread(QThread): """Worker thread for GUI to prevent blocking.""" @@ -346,6 +347,7 @@ def run(self): message += "\n[BRANCH_VERSION_DETECTED]" self.finished.emit(success, message) + else: # Dummy class for when PyQt6 is not available class WorkerThread: From b413cea6cb6c7b821d6c4e95353982aeb9acc2d9 Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 14 Aug 2025 14:36:52 +0200 Subject: [PATCH 4/8] STAC-0 Add docker build. [4] --- .github/workflows/build.yml | 2 +- Makefile | 18 ++----- PACKAGING.md | 11 +---- build.py | 98 +------------------------------------ 4 files changed, 8 insertions(+), 121 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 88a47c0..707387e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,7 +50,7 @@ jobs: # Install system package tools based on platform if [ "${{ matrix.platform }}" = "linux" ]; then sudo apt-get update - sudo apt-get install -y dpkg-dev rpm rpm-build + sudo apt-get install -y dpkg-dev elif [ "${{ matrix.platform }}" = "win" ]; then # WiX tools would need to be installed here for Windows MSI creation echo "WiX tools installation would go here for MSI creation" diff --git a/Makefile b/Makefile index f9a6bf4..ff37379 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ .PHONY: help clean install-deps install-system-deps build-all package-all \ build-linux-x86_64 build-linux-aarch64 build-macos-x86_64 build-macos-aarch64 build-win-x86_64 \ package-linux-x86_64 package-linux-aarch64 package-macos-x86_64 package-macos-aarch64 package-win-x86_64 \ - deb-linux-x86_64 deb-linux-aarch64 rpm-linux-x86_64 rpm-linux-aarch64 \ + deb-linux-x86_64 deb-linux-aarch64 \ msi-win-x86_64 pkg-macos-x86_64 pkg-macos-aarch64 \ docker-build docker-push docker-amd64 docker-arm64 docker-cleanup \ test run-gui run-cli @@ -27,8 +27,8 @@ help: @echo "" @echo "Package Targets:" @echo " package-all - Build and package for all platforms" - @echo " package-linux-x86_64 - Build and package Linux x86_64 (.tar.gz, .deb, .rpm)" - @echo " package-linux-aarch64- Build and package Linux aarch64 (.tar.gz, .deb, .rpm)" + @echo " package-linux-x86_64 - Build and package Linux x86_64 (.tar.gz, .deb)" + @echo " package-linux-aarch64- Build and package Linux aarch64 (.tar.gz, .deb)" @echo " package-macos-x86_64 - Build and package macOS x86_64 (.tar.gz, .pkg)" @echo " package-macos-aarch64- Build and package macOS aarch64 (.tar.gz, .pkg)" @echo " package-win-x86_64 - Build and package Windows x86_64 (.zip, .msi)" @@ -43,8 +43,6 @@ help: @echo "Individual Package Targets:" @echo " deb-linux-x86_64 - Create .deb package for Linux x86_64" @echo " deb-linux-aarch64 - Create .deb package for Linux aarch64" - @echo " rpm-linux-x86_64 - Create .rpm package for Linux x86_64" - @echo " rpm-linux-aarch64 - Create .rpm package for Linux aarch64" @echo " msi-win-x86_64 - Create .msi package for Windows x86_64" @echo " pkg-macos-x86_64 - Create .pkg package for macOS x86_64" @echo " pkg-macos-aarch64 - Create .pkg package for macOS aarch64" @@ -74,7 +72,7 @@ install-deps: install-system-deps: @echo "Installing system packaging tools..." @if [ "$$(uname)" = "Linux" ]; then \ - sudo apt-get update && sudo apt-get install -y dpkg-dev rpm rpm-build; \ + sudo apt-get update && sudo apt-get install -y dpkg-dev; \ echo "System packaging tools installed."; \ else \ echo "System packaging tools installation skipped (not on Linux)"; \ @@ -150,14 +148,7 @@ deb-linux-aarch64: build-linux-aarch64 @echo "Creating .deb package for Linux aarch64..." @python3 build.py linux-aarch64 --create-deb-only -# Linux .rpm packages -rpm-linux-x86_64: build-linux-x86_64 - @echo "Creating .rpm package for Linux x86_64..." - @python3 build.py linux-x86_64 --create-rpm-only -rpm-linux-aarch64: build-linux-aarch64 - @echo "Creating .rpm package for Linux aarch64..." - @python3 build.py linux-aarch64 --create-rpm-only # Windows .msi package msi-win-x86_64: build-win-x86_64 @@ -232,7 +223,6 @@ info: @echo "" @echo "Available build tools:" @command -v dpkg-deb >/dev/null 2>&1 && echo "✓ dpkg-deb (for .deb packages)" || echo "✗ dpkg-deb (for .deb packages)" - @command -v rpmbuild >/dev/null 2>&1 && echo "✓ rpmbuild (for .rpm packages)" || echo "✗ rpmbuild (for .rpm packages)" @command -v pkgbuild >/dev/null 2>&1 && echo "✓ pkgbuild (for .pkg packages)" || echo "✗ pkgbuild (for .pkg packages)" @command -v candle >/dev/null 2>&1 && echo "✓ WiX candle (for .msi packages)" || echo "✗ WiX candle (for .msi packages)" @command -v light >/dev/null 2>&1 && echo "✓ WiX light (for .msi packages)" || echo "✗ WiX light (for .msi packages)" diff --git a/PACKAGING.md b/PACKAGING.md index 4010885..cef2e02 100644 --- a/PACKAGING.md +++ b/PACKAGING.md @@ -18,11 +18,7 @@ The Agent Integrations Finder build system creates multiple package formats for - Installs executable to `/usr/local/bin/agent-integrations-finder` - Dependencies in `/usr/local/bin/_internal/` -- **`.rpm`**: Red Hat/Fedora/CentOS package for easy installation - - `agent-integrations-finder-1.0.0-1.x86_64.rpm` - - `agent-integrations-finder-1.0.0-1.aarch64.rpm` - - Installs executable to `/usr/local/bin/agent-integrations-finder` - - Dependencies in `/usr/local/bin/_internal/` + ### Windows Packages @@ -60,10 +56,7 @@ The Agent Integrations Finder build system creates multiple package formats for sudo dpkg -i agent-integrations-finder_1.0.0_amd64.deb ``` -#### Using .rpm package (Red Hat/Fedora/CentOS) -```bash -sudo rpm -i agent-integrations-finder-1.0.0-1.x86_64.rpm -``` + #### Using .tar.gz archive ```bash diff --git a/build.py b/build.py index f1f20df..e416120 100755 --- a/build.py +++ b/build.py @@ -242,93 +242,6 @@ def create_deb_package(self, target_platform, target_arch, source_dir, output_di # Clean up shutil.rmtree(temp_dir) - def create_rpm_package(self, target_platform, target_arch, source_dir, output_dir): - """Create .rpm package for Red Hat/Fedora/CentOS""" - print("Creating .rpm package...") - - # Create package structure - package_name = "agent-integrations-finder" - package_version = "1.0.0" - rpm_name = f"{package_name}-{package_version}-1.{target_arch}.rpm" - rpm_path = output_dir / rpm_name - - # Create temporary directory structure - temp_dir = self.project_root / "temp_rpm" - if temp_dir.exists(): - shutil.rmtree(temp_dir) - temp_dir.mkdir() - - # Create RPM build structure - rpm_build_dir = temp_dir / "rpmbuild" - rpm_build_dir.mkdir() - - # Create SPEC file - spec_content = f"""Name: {package_name} -Version: {package_version} -Release: 1 -Summary: Agent Integrations Finder -License: BSD-3-Clause -URL: https://github.com/StackVista/Integrations-Finder -BuildArch: {target_arch} - -%description -A tool to trace from SUSE Observability Agent container tags to the corresponding integrations source code. -Provides both CLI and GUI interfaces for finding integration source code. - -%files -%defattr(-,root,root,-) -/usr/local/bin/agent-integrations-finder -/usr/local/lib/{package_name}/ - -%post -chmod +x /usr/local/bin/agent-integrations-finder - -%clean -rm -rf $RPM_BUILD_ROOT -""" - - spec_file = temp_dir / f"{package_name}.spec" - with open(spec_file, "w") as f: - f.write(spec_content) - - # Create buildroot structure - buildroot = rpm_build_dir / "BUILDROOT" / f"{package_name}-{package_version}-1.{target_arch}" - buildroot.mkdir(parents=True) - - # Copy files to buildroot - bin_dir = buildroot / "usr" / "local" / "bin" - bin_dir.mkdir(parents=True) - - executable = source_dir / "agent-integrations-finder" - if executable.exists(): - shutil.copy2(executable, bin_dir / "agent-integrations-finder") - os.chmod(bin_dir / "agent-integrations-finder", 0o755) - - lib_dir = buildroot / "usr" / "local" / "lib" / package_name - lib_dir.mkdir(parents=True) - - internal_dir = source_dir / "_internal" - if internal_dir.exists(): - shutil.copytree(internal_dir, lib_dir / "_internal") - - # Try to build RPM using rpmbuild - try: - cmd = ["rpmbuild", "--define", f"_topdir {rpm_build_dir}", "-bb", str(spec_file)] - subprocess.run(cmd, check=True) - - # Find and copy the built RPM - rpm_dir = rpm_build_dir / "RPMS" / target_arch - if rpm_dir.exists(): - for rpm_file in rpm_dir.glob("*.rpm"): - shutil.copy2(rpm_file, rpm_path) - print(f"Created .rpm package: {rpm_path}") - break - except (subprocess.CalledProcessError, FileNotFoundError): - print("Warning: rpmbuild not available, skipping .rpm package creation") - finally: - # Clean up - shutil.rmtree(temp_dir) - def create_msi_package(self, target_platform, target_arch, source_dir, output_dir): """Create .msi package for Windows""" print("Creating .msi package...") @@ -519,7 +432,6 @@ def package(self, target_platform, target_arch): # Create system packages first if target_platform == "linux": self.create_deb_package(target_platform, target_arch, source_dir, output_dir) - self.create_rpm_package(target_platform, target_arch, source_dir, output_dir) elif target_platform == "win": self.create_msi_package(target_platform, target_arch, source_dir, output_dir) elif target_platform == "macos": @@ -595,7 +507,6 @@ def main(): print("") print("Options:") print(" --create-deb-only - Create only .deb package (Linux)") - print(" --create-rpm-only - Create only .rpm package (Linux)") print(" --create-msi-only - Create only .msi package (Windows)") print(" --create-pkg-only - Create only .pkg package (macOS)") print("") @@ -611,7 +522,6 @@ def main(): # Check for package-only options create_deb_only = "--create-deb-only" in sys.argv - create_rpm_only = "--create-rpm-only" in sys.argv create_msi_only = "--create-msi-only" in sys.argv create_pkg_only = "--create-pkg-only" in sys.argv @@ -661,13 +571,7 @@ def main(): builder.get_platform_dist_dir(platform_name, arch) / "agent-integrations-finder", builder.project_root / "packages", ) - elif create_rpm_only and platform_name == "linux": - builder.create_rpm_package( - platform_name, - arch, - builder.get_platform_dist_dir(platform_name, arch) / "agent-integrations-finder", - builder.project_root / "packages", - ) + elif create_msi_only and platform_name == "win": builder.create_msi_package( platform_name, From c0bc7222ceab247cf128e63c524524b251af70de Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 14 Aug 2025 15:19:47 +0200 Subject: [PATCH 5/8] STAC-0 Add docker build. [5] --- .github/workflows/docker.yml | 30 ++++++++++++--- docker-build.sh | 71 +++++++++++++++++------------------- 2 files changed, 57 insertions(+), 44 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 6aa1b81..61209ed 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -75,7 +75,6 @@ jobs: docker buildx build \ --platform linux/amd64 \ --tag ghcr.io/stackvista/agent-integrations-finder:${{ github.sha }}-amd64 \ - --tag ghcr.io/stackvista/agent-integrations-finder:${{ github.ref_name }}-amd64 \ --push \ . @@ -83,9 +82,24 @@ jobs: docker buildx build \ --platform linux/arm64 \ --tag ghcr.io/stackvista/agent-integrations-finder:${{ github.sha }}-arm64 \ - --tag ghcr.io/stackvista/agent-integrations-finder:${{ github.ref_name }}-arm64 \ --push \ . + + # Add version tags if this is a release (tag push) + if [[ "${{ github.ref }}" == refs/tags/* ]]; then + VERSION_TAG="${{ github.ref_name }}" + echo "Creating version tags: $VERSION_TAG" + + # Tag amd64 image with version + docker tag ghcr.io/stackvista/agent-integrations-finder:${{ github.sha }}-amd64 \ + ghcr.io/stackvista/agent-integrations-finder:$VERSION_TAG-amd64 + docker push ghcr.io/stackvista/agent-integrations-finder:$VERSION_TAG-amd64 + + # Tag arm64 image with version + docker tag ghcr.io/stackvista/agent-integrations-finder:${{ github.sha }}-arm64 \ + ghcr.io/stackvista/agent-integrations-finder:$VERSION_TAG-arm64 + docker push ghcr.io/stackvista/agent-integrations-finder:$VERSION_TAG-arm64 + fi - name: Create multi-architecture manifest if: github.event_name != 'pull_request' @@ -95,10 +109,14 @@ jobs: ghcr.io/stackvista/agent-integrations-finder:${{ github.sha }}-amd64 \ ghcr.io/stackvista/agent-integrations-finder:${{ github.sha }}-arm64 - # Create manifest with branch/tag name - docker buildx imagetools create -t ghcr.io/stackvista/agent-integrations-finder:${{ github.ref_name }} \ - ghcr.io/stackvista/agent-integrations-finder:${{ github.ref_name }}-amd64 \ - ghcr.io/stackvista/agent-integrations-finder:${{ github.ref_name }}-arm64 + # Create manifest with version tag if this is a release + if [[ "${{ github.ref }}" == refs/tags/* ]]; then + VERSION_TAG="${{ github.ref_name }}" + echo "Creating version manifest: $VERSION_TAG" + docker buildx imagetools create -t ghcr.io/stackvista/agent-integrations-finder:$VERSION_TAG \ + ghcr.io/stackvista/agent-integrations-finder:$VERSION_TAG-amd64 \ + ghcr.io/stackvista/agent-integrations-finder:$VERSION_TAG-arm64 + fi - name: Show image info run: | diff --git a/docker-build.sh b/docker-build.sh index f1eb89b..80506eb 100755 --- a/docker-build.sh +++ b/docker-build.sh @@ -119,25 +119,23 @@ create_manifest() { build_architecture "amd64" build_architecture "arm64" - # Create manifest with git SHA - print_status "Creating manifest with tag: ${GIT_SHA}" + # Prepare tags + local tags="--tag ${IMAGE_NAME}:${GIT_SHA}" + + # Add version tag if this is a release + if [[ -n "${GIT_TAG}" ]]; then + print_status "Adding version tag: ${GIT_TAG}" + tags="${tags} --tag ${IMAGE_NAME}:${GIT_TAG}" + fi + + # Create manifest + print_status "Creating manifest with tags: ${GIT_SHA}${GIT_TAG:+ and ${GIT_TAG}}" docker buildx build \ --platform linux/amd64,linux/arm64 \ - --tag ${IMAGE_NAME}:${GIT_SHA} \ + ${tags} \ --file Dockerfile \ --push \ . - - # Create manifest with version tag if this is a release - if [[ -n "${GIT_TAG}" ]]; then - print_status "Creating release manifest with tag: ${GIT_TAG}" - docker buildx build \ - --platform linux/amd64,linux/arm64 \ - --tag ${IMAGE_NAME}:${GIT_TAG} \ - --file Dockerfile \ - --push \ - . - fi } # Push individual architecture images @@ -164,28 +162,22 @@ push_architectures() { build_and_push() { print_step "Building and pushing all images..." + # Prepare tags + local tags="--tag ${IMAGE_NAME}:${GIT_SHA} --tag ${IMAGE_NAME}:${GIT_SHA}-amd64 --tag ${IMAGE_NAME}:${GIT_SHA}-arm64" + + # Add version tags if this is a release + if [[ -n "${GIT_TAG}" ]]; then + print_status "Adding version tags..." + tags="${tags} --tag ${IMAGE_NAME}:${GIT_TAG} --tag ${IMAGE_NAME}:${GIT_TAG}-amd64 --tag ${IMAGE_NAME}:${GIT_TAG}-arm64" + fi + # Build for both architectures and create manifest docker buildx build \ --platform linux/amd64,linux/arm64 \ - --tag ${IMAGE_NAME}:${GIT_SHA} \ - --tag ${IMAGE_NAME}:${GIT_SHA}-amd64 \ - --tag ${IMAGE_NAME}:${GIT_SHA}-arm64 \ + ${tags} \ --file Dockerfile \ --push \ . - - # Add version tags if this is a release - if [[ -n "${GIT_TAG}" ]]; then - print_status "Adding version tags..." - docker buildx build \ - --platform linux/amd64,linux/arm64 \ - --tag ${IMAGE_NAME}:${GIT_TAG} \ - --tag ${IMAGE_NAME}:${GIT_TAG}-amd64 \ - --tag ${IMAGE_NAME}:${GIT_TAG}-arm64 \ - --file Dockerfile \ - --push \ - . - fi } # Build only (no push) @@ -196,14 +188,17 @@ build_only() { build_architecture "amd64" build_architecture "arm64" - # Create local manifest - print_status "Creating local manifest..." - docker buildx build \ - --platform linux/amd64,linux/arm64 \ - --tag ${IMAGE_NAME}:${GIT_SHA} \ - --file Dockerfile \ - --load \ - . + # Note: Cannot create multi-arch manifest locally with --load + # Individual architecture images are already built and loaded + print_status "Individual architecture images built and loaded locally" + print_status "Available images:" + print_status " ${IMAGE_NAME}:${GIT_SHA}-amd64" + print_status " ${IMAGE_NAME}:${GIT_SHA}-arm64" + + if [[ -n "${GIT_TAG}" ]]; then + print_status " ${IMAGE_NAME}:${GIT_TAG}-amd64" + print_status " ${IMAGE_NAME}:${GIT_TAG}-arm64" + fi } # Clean up Docker images From 25fa4ea2067e799950a1b49dca90ae258ee09ccb Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 14 Aug 2025 15:42:45 +0200 Subject: [PATCH 6/8] STAC-0 Add docker build. [6] --- docker-build.sh | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/docker-build.sh b/docker-build.sh index 80506eb..ac38937 100755 --- a/docker-build.sh +++ b/docker-build.sh @@ -162,22 +162,28 @@ push_architectures() { build_and_push() { print_step "Building and pushing all images..." - # Prepare tags - local tags="--tag ${IMAGE_NAME}:${GIT_SHA} --tag ${IMAGE_NAME}:${GIT_SHA}-amd64 --tag ${IMAGE_NAME}:${GIT_SHA}-arm64" - - # Add version tags if this is a release - if [[ -n "${GIT_TAG}" ]]; then - print_status "Adding version tags..." - tags="${tags} --tag ${IMAGE_NAME}:${GIT_TAG} --tag ${IMAGE_NAME}:${GIT_TAG}-amd64 --tag ${IMAGE_NAME}:${GIT_TAG}-arm64" - fi - # Build for both architectures and create manifest docker buildx build \ --platform linux/amd64,linux/arm64 \ - ${tags} \ + --tag ${IMAGE_NAME}:${GIT_SHA} \ + --tag ${IMAGE_NAME}:${GIT_SHA}-amd64 \ + --tag ${IMAGE_NAME}:${GIT_SHA}-arm64 \ --file Dockerfile \ --push \ . + + # Add version tags if this is a release + if [[ -n "${GIT_TAG}" ]]; then + print_status "Adding version tags..." + docker buildx build \ + --platform linux/amd64,linux/arm64 \ + --tag ${IMAGE_NAME}:${GIT_TAG} \ + --tag ${IMAGE_NAME}:${GIT_TAG}-amd64 \ + --tag ${IMAGE_NAME}:${GIT_TAG}-arm64 \ + --file Dockerfile \ + --push \ + . + fi } # Build only (no push) From 3cae0ca614a6e49741c7e4e6d7b656942320f1bc Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 14 Aug 2025 15:51:35 +0200 Subject: [PATCH 7/8] STAC-0 Add docker build. [7] --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 61209ed..c929157 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -44,7 +44,7 @@ jobs: type=ref,event=pr type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} - type=sha,prefix={{branch}}- + type=sha type=raw,value=latest,enable={{is_default_branch}} - name: Set up Python From 2cd225291e8004ba703dda49dafa87c6f5fefe16 Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 14 Aug 2025 16:39:46 +0200 Subject: [PATCH 8/8] STAC-0 Add docker build. [8] --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 707387e..e2f6563 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -58,6 +58,7 @@ jobs: # pkgbuild is available by default on macOS echo "pkgbuild is available by default on macOS" fi + shell: bash - name: Build executable run: |