Buildfixes (#74) #42
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Build COPR packages when package specs change | |
| # Triggers builds in dependency order based on packages/README.md | |
| name: Build COPR Packages | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: false # Don't cancel - we need to cleanup COPR builds properly | |
| on: | |
| push: | |
| branches: | |
| - main | |
| paths: | |
| - 'packages/**' | |
| - '.github/workflows/build-copr-packages.yml' | |
| workflow_dispatch: | |
| inputs: | |
| packages: | |
| description: 'Comma-separated list of packages to build (empty = auto-detect from changes)' | |
| required: false | |
| type: string | |
| rebuild_all: | |
| description: 'Rebuild all packages in dependency order' | |
| required: false | |
| type: boolean | |
| default: false | |
| env: | |
| COPR_PROJECT: binarypie/hypercube | |
| jobs: | |
| detect-changes: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| packages: ${{ steps.detect.outputs.packages }} | |
| matrix: ${{ steps.build-matrix.outputs.matrix }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 # Full history to find last successful build | |
| - name: Get last successful build commit | |
| id: last-success | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| # Find the last successful workflow run on this branch | |
| LAST_SHA=$(gh run list \ | |
| --workflow="Build COPR Packages" \ | |
| --branch=main \ | |
| --status=success \ | |
| --limit=1 \ | |
| --json headSha \ | |
| --jq '.[0].headSha // empty' 2>/dev/null) || LAST_SHA="" | |
| if [[ -n "$LAST_SHA" ]]; then | |
| echo "Last successful build: $LAST_SHA" | |
| echo "sha=$LAST_SHA" >> $GITHUB_OUTPUT | |
| else | |
| echo "No previous successful build found, will use HEAD~1" | |
| echo "sha=" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Install jq | |
| run: sudo apt-get update && sudo apt-get install -y jq | |
| - name: Detect changed packages | |
| id: detect | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| # Source shared package configuration | |
| source ./scripts/packages/config.sh | |
| # Package dependencies are now available via PACKAGE_DEPS | |
| # Build batches are available via BUILD_BATCHES | |
| # Function to get all downstream dependents of a package | |
| get_dependents() { | |
| local pkg=$1 | |
| local dependents="" | |
| for p in "${!PACKAGE_DEPS[@]}"; do | |
| if [[ " ${PACKAGE_DEPS[$p]} " == *" $pkg "* ]]; then | |
| dependents="$dependents $p" | |
| # Recursively get dependents of dependents | |
| dependents="$dependents $(get_dependents $p)" | |
| fi | |
| done | |
| echo "$dependents" | |
| } | |
| # Determine which packages to build | |
| if [[ "${{ inputs.rebuild_all }}" == "true" ]]; then | |
| echo "Rebuilding all packages..." | |
| CHANGED_PKGS="${!PACKAGE_DEPS[*]}" | |
| elif [[ -n "${{ inputs.packages }}" ]]; then | |
| echo "Using manually specified packages..." | |
| CHANGED_PKGS=$(echo "${{ inputs.packages }}" | tr ',' ' ') | |
| else | |
| echo "Detecting changed packages..." | |
| # Compare against last successful build, or HEAD~1 if none | |
| LAST_SHA="${{ steps.last-success.outputs.sha }}" | |
| if [[ -n "$LAST_SHA" ]]; then | |
| echo "Comparing HEAD against last successful build: $LAST_SHA" | |
| COMPARE_REF="$LAST_SHA" | |
| else | |
| echo "Comparing HEAD against HEAD~1" | |
| COMPARE_REF="HEAD~1" | |
| fi | |
| CHANGED_PKGS="" | |
| for dir in packages/*/; do | |
| pkg=$(basename "$dir") | |
| if [[ "$pkg" != "README.md" ]]; then | |
| if git diff --name-only "$COMPARE_REF" HEAD | grep -q "^packages/$pkg/"; then | |
| CHANGED_PKGS="$CHANGED_PKGS $pkg" | |
| fi | |
| fi | |
| done | |
| fi | |
| echo "Initially changed packages: $CHANGED_PKGS" | |
| echo "" | |
| echo "Checking which packages actually need building..." | |
| echo "" | |
| # Use the check-copr-versions script to filter packages | |
| if [[ -z "$CHANGED_PKGS" ]]; then | |
| NEEDS_BUILD="" | |
| else | |
| # Run the version check script | |
| SCRIPT_OUTPUT=$(./scripts/packages/check-copr-versions.sh $CHANGED_PKGS 2>&1) | |
| echo "$SCRIPT_OUTPUT" | |
| # Extract packages that need building from the script output | |
| NEEDS_BUILD=$(echo "$SCRIPT_OUTPUT" | grep "^NEEDS_BUILD_JSON=" | sed 's/^NEEDS_BUILD_JSON=//' | jq -r '.[]' | tr '\n' ' ') | |
| fi | |
| echo "" | |
| echo "Packages that need building: $NEEDS_BUILD" | |
| # Add all downstream dependents | |
| TO_BUILD="$NEEDS_BUILD" | |
| for pkg in $NEEDS_BUILD; do | |
| dependents=$(get_dependents "$pkg") | |
| TO_BUILD="$TO_BUILD $dependents" | |
| done | |
| # Deduplicate | |
| TO_BUILD=$(echo "$TO_BUILD" | tr ' ' '\n' | sort -u | tr '\n' ' ') | |
| echo "Packages to build (including dependents): $TO_BUILD" | |
| # Output as JSON array | |
| if [[ -z "$(echo $TO_BUILD | tr -d ' ')" ]]; then | |
| echo "packages=[]" >> $GITHUB_OUTPUT | |
| else | |
| JSON=$(echo "$TO_BUILD" | tr -s ' ' '\n' | grep -v '^$' | jq -R . | jq -sc .) | |
| echo "packages=$JSON" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Build batch matrix | |
| id: build-matrix | |
| run: | | |
| PACKAGES='${{ steps.detect.outputs.packages }}' | |
| if [[ "$PACKAGES" == "[]" ]]; then | |
| echo "matrix={\"batch\":[]}" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| # Source shared package configuration | |
| source ./scripts/packages/config.sh | |
| # Build batches JSON from BUILD_BATCHES array (in sorted order) | |
| echo '{"batch":[' > /tmp/batches.json | |
| first=true | |
| # Sort batch IDs numerically to ensure correct order | |
| for batch_id in $(echo "${!BUILD_BATCHES[@]}" | tr ' ' '\n' | sort -n); do | |
| if [[ $first == false ]]; then | |
| echo "," >> /tmp/batches.json | |
| fi | |
| first=false | |
| # Convert space-separated packages to JSON array | |
| packages_json=$(echo "${BUILD_BATCHES[$batch_id]}" | tr ' ' '\n' | jq -R . | jq -sc .) | |
| jq -n \ | |
| --argjson id "$batch_id" \ | |
| --argjson packages "$packages_json" \ | |
| '{id: $id, packages: $packages}' >> /tmp/batches.json | |
| done | |
| echo ']}' >> /tmp/batches.json | |
| # Filter batches to only include packages that need building | |
| FILTERED=$(jq -c --argjson pkgs "$PACKAGES" ' | |
| .batch | map( | |
| .packages = (.packages | map(select(. as $p | $pkgs | index($p)))) | |
| | select(.packages | length > 0) | |
| ) | {batch: .} | |
| ' /tmp/batches.json) | |
| echo "matrix=$FILTERED" >> $GITHUB_OUTPUT | |
| echo "Build matrix:" | |
| echo "$FILTERED" | jq . | |
| build-batch: | |
| needs: detect-changes | |
| if: ${{ needs.detect-changes.outputs.matrix != '{"batch":[]}' && needs.detect-changes.outputs.matrix != '' }} | |
| runs-on: ubuntu-latest | |
| strategy: | |
| max-parallel: 1 # Run batches sequentially | |
| fail-fast: true # Stop subsequent batches if one fails (dependencies would fail anyway) | |
| matrix: ${{ fromJson(needs.detect-changes.outputs.matrix) }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Install COPR CLI | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y python3-pip | |
| pip3 install copr-cli | |
| - name: Configure COPR CLI | |
| run: | | |
| mkdir -p ~/.config | |
| cat > ~/.config/copr << EOF | |
| [copr-cli] | |
| login = ${{ secrets.COPR_API_LOGIN }} | |
| username = binarypie | |
| token = ${{ secrets.COPR_API_TOKEN }} | |
| copr_url = https://copr.fedorainfracloud.org | |
| EOF | |
| - name: Build batch ${{ matrix.batch.id }} packages | |
| id: build | |
| run: | | |
| echo "Building batch ${{ matrix.batch.id }}: ${{ join(matrix.batch.packages, ', ') }}" | |
| FAILED="" | |
| BUILD_IDS="" | |
| # Trigger all builds in this batch | |
| for pkg in ${{ join(matrix.batch.packages, ' ') }}; do | |
| echo "" | |
| echo "========================================" | |
| echo "Triggering build for: $pkg" | |
| echo "========================================" | |
| # Trigger SCM build | |
| BUILD_OUTPUT=$(copr-cli build-package \ | |
| --name "$pkg" \ | |
| "${{ env.COPR_PROJECT }}" 2>&1) || { | |
| echo "::error::Failed to trigger build for $pkg" | |
| echo "$BUILD_OUTPUT" | |
| FAILED="$FAILED $pkg" | |
| continue | |
| } | |
| echo "$BUILD_OUTPUT" | |
| # Extract build ID | |
| BUILD_ID=$(echo "$BUILD_OUTPUT" | grep -oP 'Build was added to .+builds/\K\d+' || echo "") | |
| if [[ -n "$BUILD_ID" ]]; then | |
| BUILD_IDS="$BUILD_IDS $BUILD_ID" | |
| echo "Build ID: $BUILD_ID" | |
| fi | |
| done | |
| # Save build IDs for potential cleanup | |
| echo "build_ids=$BUILD_IDS" >> $GITHUB_OUTPUT | |
| # Wait for all builds in this batch to complete | |
| echo "" | |
| echo "========================================" | |
| echo "Waiting for batch ${{ matrix.batch.id }} builds to complete..." | |
| echo "========================================" | |
| for build_id in $BUILD_IDS; do | |
| echo "Waiting for build $build_id..." | |
| copr-cli watch-build "$build_id" || { | |
| echo "::warning::Build $build_id failed or was cancelled" | |
| # Get package name for this build | |
| FAILED="$FAILED (build:$build_id)" | |
| } | |
| done | |
| if [[ -n "$FAILED" ]]; then | |
| echo "" | |
| echo "::error::Some packages failed to build:$FAILED" | |
| exit 1 | |
| fi | |
| echo "" | |
| echo "Batch ${{ matrix.batch.id }} completed successfully!" | |
| - name: Cancel COPR builds on workflow cancellation | |
| if: cancelled() | |
| run: | | |
| echo "Workflow cancelled - cancelling COPR builds..." | |
| BUILD_IDS="${{ steps.build.outputs.build_ids }}" | |
| for build_id in $BUILD_IDS; do | |
| echo "Cancelling COPR build $build_id..." | |
| copr-cli cancel "$build_id" || echo "Could not cancel build $build_id (may have already finished)" | |
| done | |
| echo "COPR build cancellation complete" | |
| - name: Generate batch summary | |
| if: always() | |
| run: | | |
| echo "## Batch ${{ matrix.batch.id }} Build Results" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Packages:** ${{ join(matrix.batch.packages, ', ') }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "[View builds on COPR](https://copr.fedorainfracloud.org/coprs/${{ env.COPR_PROJECT }}/builds/)" >> $GITHUB_STEP_SUMMARY | |
| summary: | |
| needs: [detect-changes, build-batch] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Generate final summary | |
| run: | | |
| echo "## COPR Package Build Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Packages built:** ${{ needs.detect-changes.outputs.packages }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Status:** ${{ needs.build-batch.result }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "[View all builds](https://copr.fedorainfracloud.org/coprs/${{ env.COPR_PROJECT }}/builds/)" >> $GITHUB_STEP_SUMMARY |