diff --git a/.github/workflows/engine-compat.yml b/.github/workflows/engine-compat.yml new file mode 100644 index 00000000000..b9ff942d38a --- /dev/null +++ b/.github/workflows/engine-compat.yml @@ -0,0 +1,80 @@ +name: Node Packages Engine Compatibility Check + +on: + workflow_call: + inputs: + node-versions: + description: 'Comma-separated Node.js versions, e.g. 22.20.0, 22, 24.0.0, 24' + required: true + type: string + +permissions: + contents: read + pull-requests: write + +jobs: + engine-compat: + name: Engine compatibility + runs-on: ubuntu-24.04 + steps: + + - uses: actions/checkout@v6 + + - name: Check engines and report + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NODE_VERSIONS: ${{ inputs.node-versions }} + run: | + # Load nvm (pre-installed on GitHub runners) + export NVM_DIR="$HOME/.nvm" && . "$NVM_DIR/nvm.sh" + + PR="${{ github.event.pull_request.number }}" + MARKER="" + FAILED=false + TABLE="| Node | Result | Incompatible Packages |\n|---|---|---|" + + # Loop through each requested Node version + IFS=',' read -ra VERSIONS <<< "$NODE_VERSIONS" + for V in "${VERSIONS[@]}"; do + V=$(echo "$V" | xargs) # trim whitespace + nvm install "$V" --no-progress > /dev/null 2>&1 + nvm use "$V" > /dev/null 2>&1 + VER=$(node --version) + + # Dry-run install to collect EBADENGINE warnings without actually installing. + # awk extracts "package@version (node range)" from multi-line warning blocks. + # sort -u deduplicates (npm may warn about the same package multiple times). + PKGS=$(npm ci --dry-run 2>&1 \ + | awk -F"'" '/EBADENGINE.*package:/{pkg=$2} /EBADENGINE.*node:/{if(pkg){print pkg" (node "$2")"; pkg=""}}' \ + | sort -u | tr '\n' ',' | sed 's/,$//' | sed 's/,/, /g') + + if [ -n "$PKGS" ]; then + FAILED=true + # Escape pipe characters so they don't break the markdown table + SAFE=$(echo "$PKGS" | sed 's/|/\\|/g') + TABLE="$TABLE\n| $VER | ❌ Fail | $SAFE |" + else + TABLE="$TABLE\n| $VER | ✅ Pass | — |" + fi + done + + # Build the comment body + if [ "$FAILED" = true ]; then ICON="❌"; else ICON="✅"; fi + printf '%s\n## %s Engine Compatibility\n\n%b\n' "$MARKER" "$ICON" "$TABLE" > /tmp/comment.md + + # Update existing comment (matched by HTML marker) or create a new one + OLD=$(gh api "repos/${{ github.repository }}/issues/${PR}/comments" \ + --jq "[.[] | select(.body | contains(\"$MARKER\"))][0].id" 2>/dev/null || true) + if [ -n "$OLD" ] && [ "$OLD" != "null" ]; then + gh api --method PATCH "repos/${{ github.repository }}/issues/comments/$OLD" -F body=@/tmp/comment.md + else + gh pr comment "$PR" --body-file /tmp/comment.md + fi + + # Add "blocked" label on failure, remove it on success + if [ "$FAILED" = true ]; then + gh label create blocked --color D93F0B 2>/dev/null || true + gh pr edit "$PR" --add-label blocked + else + gh pr edit "$PR" --remove-label blocked 2>/dev/null || true + fi diff --git a/.github/workflows/github-ci.yml b/.github/workflows/github-ci.yml index 18cf8c99bd5..7269e7bbf3a 100644 --- a/.github/workflows/github-ci.yml +++ b/.github/workflows/github-ci.yml @@ -10,8 +10,15 @@ on: permissions: contents: read + pull-requests: write jobs: + engine-compat: + if: github.event_name == 'pull_request' + uses: ./.github/workflows/engine-compat.yml + with: + node-versions: '22.20.0, 22, 24.0.0, 24' + test: name: General checks and tests runs-on: ubuntu-24.04 @@ -25,7 +32,7 @@ jobs: node-version: 22.20.0 - name: Install dependencies - run: npm ci --engine-strict # --engine-strict is used to fail-fast if deps require node versions unsupported by the repo + run: npm ci - name: Check package.json "engines" consistency run: |