name: Build Conda-Pack Environment on: workflow_dispatch: inputs: branch: description: '选择要构建的分支' required: true default: 'dev' type: string platforms: description: '选择构建平台 (逗号分隔): linux-64, osx-64, osx-arm64, win-64' required: false default: 'win-64' type: string jobs: build-conda-pack: strategy: fail-fast: false matrix: include: - os: ubuntu-latest platform: linux-64 env_file: unilabos-linux-64.yaml script_ext: sh - os: macos-13 # Intel platform: osx-64 env_file: unilabos-osx-64.yaml script_ext: sh - os: macos-latest # ARM64 platform: osx-arm64 env_file: unilabos-osx-arm64.yaml script_ext: sh - os: windows-latest platform: win-64 env_file: unilabos-win64.yaml script_ext: bat runs-on: ${{ matrix.os }} defaults: run: # Windows needs PowerShell for conda/mamba, Unix uses bash shell: ${{ matrix.platform == 'win-64' && 'pwsh' || 'bash -el {0}' }} steps: - name: Check if platform should be built id: should_build shell: bash run: | if [[ -z "${{ github.event.inputs.platforms }}" ]]; then echo "should_build=true" >> $GITHUB_OUTPUT elif [[ "${{ github.event.inputs.platforms }}" == *"${{ matrix.platform }}"* ]]; then echo "should_build=true" >> $GITHUB_OUTPUT else echo "should_build=false" >> $GITHUB_OUTPUT fi - uses: actions/checkout@v4 if: steps.should_build.outputs.should_build == 'true' with: ref: ${{ github.event.inputs.branch }} fetch-depth: 0 - name: Setup Miniforge (with mamba) if: steps.should_build.outputs.should_build == 'true' uses: conda-incubator/setup-miniconda@v3 with: miniforge-version: latest use-mamba: true python-version: '3.11.11' channels: conda-forge,robostack-staging,uni-lab,defaults channel-priority: flexible activate-environment: unilab auto-activate-base: true auto-update-conda: false show-channel-urls: true - name: Install conda-pack, unilabos and dependencies if: steps.should_build.outputs.should_build == 'true' run: | echo "Installing unilabos and dependencies to unilab environment..." echo "Using mamba for faster and more reliable dependency resolution..." mamba install uni-lab::unilabos conda-pack -c uni-lab -c robostack-staging -c conda-forge -y - name: Get latest ros-humble-unilabos-msgs version (Windows) if: steps.should_build.outputs.should_build == 'true' && matrix.platform == 'win-64' id: msgs_version_win run: | Write-Host "Checking installed ros-humble-unilabos-msgs version..." $version = (conda list ros-humble-unilabos-msgs --json | ConvertFrom-Json)[0].version Write-Output "installed_version=$version" >> $env:GITHUB_OUTPUT Write-Host "Installed ros-humble-unilabos-msgs version: $version" - name: Get latest ros-humble-unilabos-msgs version (Unix) if: steps.should_build.outputs.should_build == 'true' && matrix.platform != 'win-64' id: msgs_version_unix shell: bash run: | echo "Checking installed ros-humble-unilabos-msgs version..." VERSION=$(conda list ros-humble-unilabos-msgs --json | python -c "import sys, json; pkgs=json.load(sys.stdin); print(pkgs[0]['version'] if pkgs else 'not-found')") echo "installed_version=$VERSION" >> $GITHUB_OUTPUT echo "Installed ros-humble-unilabos-msgs version: $VERSION" - name: Check for newer ros-humble-unilabos-msgs if: steps.should_build.outputs.should_build == 'true' run: | echo "Checking for available ros-humble-unilabos-msgs versions..." mamba search ros-humble-unilabos-msgs -c uni-lab -c robostack-staging -c conda-forge --info || echo "Search completed" echo "Updating ros-humble-unilabos-msgs to latest version..." mamba update ros-humble-unilabos-msgs -c uni-lab -c robostack-staging -c conda-forge -y || echo "Already at latest version" - name: Install latest unilabos from source if: steps.should_build.outputs.should_build == 'true' run: | echo "Uninstalling existing unilabos..." pip uninstall unilabos -y || echo "unilabos not installed via pip" echo "Installing unilabos from source (branch: ${{ github.event.inputs.branch }})..." pip install . echo "Verifying installation..." pip show unilabos - name: Display environment info if: steps.should_build.outputs.should_build == 'true' run: | echo "=== Environment Information ===" conda env list echo "" echo "=== Installed Packages ===" conda list | grep -E "(unilabos|ros-humble-unilabos-msgs)" || conda list echo "" echo "=== Python Packages ===" pip list | grep unilabos || pip list - name: Verify environment integrity if: steps.should_build.outputs.should_build == 'true' run: | echo "Verifying Python version..." python -c "import sys; print(f'Python version: {sys.version}')" echo "Verifying unilabos import..." python -c "import unilabos; print(f'UniLabOS version: {unilabos.__version__}')" || echo "Warning: Could not import unilabos" echo "Checking critical packages..." python -c "import rclpy; print('ROS2 rclpy: OK')" echo "Running comprehensive verification script..." python scripts/verify_installation.py || echo "Warning: Verification script reported issues" echo "Environment verification complete!" - name: Pack conda environment if: steps.should_build.outputs.should_build == 'true' run: | echo "Packing unilab environment with conda-pack..." conda pack -n unilab -o unilab-env-${{ matrix.platform }}.tar.gz --ignore-missing-files echo "Pack file created:" ls -lh unilab-env-${{ matrix.platform }}.tar.gz - name: Prepare Windows distribution package if: steps.should_build.outputs.should_build == 'true' && matrix.platform == 'win-64' run: | Write-Host "==========================================" Write-Host "Creating distribution package..." Write-Host "Platform: ${{ matrix.platform }}" Write-Host "==========================================" New-Item -ItemType Directory -Force -Path dist-package | Out-Null # Copy packed environment Write-Host "Adding: unilab-env-${{ matrix.platform }}.tar.gz" Copy-Item unilab-env-${{ matrix.platform }}.tar.gz dist-package/ # Copy installation script Write-Host "Adding: install_unilab.bat" Copy-Item scripts/install_unilab.bat dist-package/ # Copy verification script Write-Host "Adding: verify_installation.py" Copy-Item scripts/verify_installation.py dist-package/ # Create README using Python script Write-Host "Creating: README.txt" python scripts/create_readme.py ${{ matrix.platform }} ${{ github.event.inputs.branch }} dist-package/README.txt Write-Host "" Write-Host "Distribution package contents:" Get-ChildItem dist-package | Format-Table Name, Length Write-Host "" - name: Prepare Unix/Linux distribution package if: steps.should_build.outputs.should_build == 'true' && matrix.platform != 'win-64' shell: bash run: | echo "==========================================" echo "Creating distribution package..." echo "Platform: ${{ matrix.platform }}" echo "==========================================" mkdir -p dist-package # Copy packed environment echo "Adding: unilab-env-${{ matrix.platform }}.tar.gz" cp unilab-env-${{ matrix.platform }}.tar.gz dist-package/ # Copy installation script echo "Adding: install_unilab.sh" cp scripts/install_unilab.sh dist-package/ chmod +x dist-package/install_unilab.sh # Copy verification script echo "Adding: verify_installation.py" cp scripts/verify_installation.py dist-package/ # Create README using Python script echo "Creating: README.txt" python scripts/create_readme.py ${{ matrix.platform }} ${{ github.event.inputs.branch }} dist-package/README.txt echo "" echo "Distribution package contents:" ls -lh dist-package/ echo "" - name: Create Windows ZIP archive if: steps.should_build.outputs.should_build == 'true' && matrix.platform == 'win-64' run: | Write-Host "==========================================" Write-Host "Creating Windows ZIP archive (ZIP64 support for large files)..." Write-Host "Archive: unilab-pack-${{ matrix.platform }}.zip" Write-Host "Contents: install_unilab.bat + unilab-env-${{ matrix.platform }}.tar.gz + extras" Write-Host "" # Use Python script with ZIP64 support instead of PowerShell Compress-Archive # PowerShell Compress-Archive has a 2GB limitation python scripts/create_zip_archive.py dist-package unilab-pack-${{ matrix.platform }}.zip Write-Host "==========================================" Write-Host "" Write-Host "Final package created:" Get-ChildItem unilab-pack-* | Format-Table Name, Length Write-Host "" Write-Host "Users can now:" Write-Host " 1. Download unilab-pack-${{ matrix.platform }}.zip" Write-Host " 2. Extract it" Write-Host " 3. Run install_unilab.bat" Write-Host "" - name: Create Unix/Linux TAR.GZ archive if: steps.should_build.outputs.should_build == 'true' && matrix.platform != 'win-64' shell: bash run: | echo "==========================================" echo "Creating Unix/Linux TAR.GZ archive..." echo "Archive: unilab-pack-${{ matrix.platform }}.tar.gz" echo "Contents: install_unilab.sh + unilab-env-${{ matrix.platform }}.tar.gz + extras" tar -czf unilab-pack-${{ matrix.platform }}.tar.gz -C dist-package . echo "==========================================" echo "" echo "Final package created:" ls -lh unilab-pack-* echo "" echo "Users can now:" echo " 1. Download unilab-pack-${{ matrix.platform }}.tar.gz" echo " 2. Extract it: tar -xzf unilab-pack-${{ matrix.platform }}.tar.gz" echo " 3. Run: bash install_unilab.sh" echo "" - name: Upload distribution package if: steps.should_build.outputs.should_build == 'true' uses: actions/upload-artifact@v4 with: name: unilab-pack-${{ matrix.platform }}-${{ github.event.inputs.branch }} path: unilab-pack-* retention-days: 90 if-no-files-found: error - name: Display package info if: steps.should_build.outputs.should_build == 'true' run: | echo "==========================================" echo "Build Summary" echo "==========================================" echo "Platform: ${{ matrix.platform }}" echo "Branch: ${{ github.event.inputs.branch }}" echo "Python version: 3.11.11" echo "" echo "Package contents:" if [ "${{ matrix.platform }}" == "win-64" ]; then echo " - unilab-pack-${{ matrix.platform }}.zip" else echo " - unilab-pack-${{ matrix.platform }}.tar.gz" fi echo " - unilab-env-${{ matrix.platform }}.tar.gz (packed environment)" echo " - install_unilab script" echo " - verify_installation.py" echo " - README.txt" echo "" echo "Package size:" ls -lh unilab-pack-* 2>/dev/null || ls -lh unilab-env-${{ matrix.platform }}.tar.gz echo "" echo "Download the artifact and run the install script!" echo "=========================================="