Create new Node.js patch #266
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
name: Create new Node.js patch | |
on: | |
workflow_dispatch: | |
inputs: | |
nodeVersion: | |
description: 'Node.js version (e.g. 20.11.0)' | |
default: '' | |
type: string | |
required: true | |
patchFile: | |
description: 'Patch version to use (e.g. 20.11.0). Leave empty to use the matching major patch' | |
default: '' | |
type: string | |
required: false | |
jobs: | |
build: | |
permissions: | |
contents: write | |
pull-requests: write | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Checkout nodejs and create new patch | |
run: | | |
set +e # Don't exit on errors, we want to handle them ourselves | |
# find the patch file by checking the patch file matching major version input node version | |
MAJOR_VERSION=$(echo ${{ inputs.nodeVersion }} | cut -d'.' -f1) | |
echo "Node.js major version: $MAJOR_VERSION" | |
if [ -z "${{ inputs.patchFile }}" ]; then | |
PATCH_FILE=$(ls patches/node.v$MAJOR_VERSION.*.patch) | |
else | |
PATCH_FILE=patches/node.v${{ inputs.patchFile }}.cpp.patch | |
fi | |
# extract patch version from PATCH_FILE. E.g. node.v20.11.1.cpp.patch --> 20.11.1 | |
PATCH_VERSION=$(echo $PATCH_FILE | grep -oP 'node.v\K[0-9]+\.[0-9]+\.[0-9]+') | |
echo "Patch file: $PATCH_FILE" | |
# check if patch file exists | |
if [ ! -f "$PATCH_FILE" ]; then | |
echo "No patch file found for Node.js version ${{ inputs.nodeVersion }}" | |
exit 1 | |
fi | |
cd .. | |
echo "Cloning Node.js repository" | |
git clone -b v${{ inputs.nodeVersion }} --single-branch https://github.com/nodejs/node.git | |
cd node | |
# Try to apply the patch cleanly first | |
echo "Applying patch $PATCH_FILE" | |
git apply --check ../pkg-fetch/$PATCH_FILE | |
PATCH_CHECK_RESULT=$? | |
if [ $PATCH_CHECK_RESULT -eq 0 ]; then | |
echo "✅ Patch $PATCH_FILE applies cleanly" | |
git apply ../pkg-fetch/$PATCH_FILE | |
echo "PATCH_STATUS=clean" >> $GITHUB_ENV | |
else | |
echo "⚠️ Patch $PATCH_FILE does not apply cleanly, attempting conflict resolution" | |
# Apply patch with --reject to create .rej files | |
git apply --reject ../pkg-fetch/$PATCH_FILE || true | |
# Check if we have any .rej files | |
REJECT_COUNT=$(find . -name "*.rej" -type f | wc -l) | |
if [ $REJECT_COUNT -eq 0 ]; then | |
echo "ℹ️ No reject files found, patch applied partially" | |
echo "PATCH_STATUS=partial" >> $GITHUB_ENV | |
else | |
echo "🤖 Found $REJECT_COUNT reject files, using AI to resolve conflicts" | |
# Use our Python script to resolve conflicts | |
if [ -n "${{ secrets.OPENAI_KEY }}" ]; then | |
echo "Using OpenAI API for conflict resolution" | |
python3 ../pkg-fetch/.github/scripts/openai_resolver.py . "${{ secrets.OPENAI_KEY }}" > resolution_output.txt 2>&1 | |
RESOLUTION_RESULT=$? | |
else | |
echo "No OpenAI API key found, creating manual resolution files only" | |
python3 ../pkg-fetch/.github/scripts/openai_resolver.py . "dummy" "create_manual_only" > resolution_output.txt 2>&1 | |
RESOLUTION_RESULT=1 | |
fi | |
# Extract results from Python script output | |
CONFLICTS_RESOLVED=$(grep "CONFLICTS_RESOLVED=" resolution_output.txt | cut -d'=' -f2) | |
TOTAL_CONFLICTS=$(grep "TOTAL_CONFLICTS=" resolution_output.txt | cut -d'=' -f2) | |
HAS_UNRESOLVED=$(grep "HAS_UNRESOLVED=" resolution_output.txt | cut -d'=' -f2) | |
FAILED_FILES_LINE=$(grep "FAILED_FILES=" resolution_output.txt | cut -d'=' -f2) | |
echo "PATCH_STATUS=conflicts" >> $GITHUB_ENV | |
echo "CONFLICTS_RESOLVED=${CONFLICTS_RESOLVED:-0}" >> $GITHUB_ENV | |
echo "TOTAL_CONFLICTS=${TOTAL_CONFLICTS:-0}" >> $GITHUB_ENV | |
# Show resolution summary | |
cat resolution_output.txt | |
# Check if we have unresolved conflicts - if so, exit without creating PR | |
if [ "${HAS_UNRESOLVED:-false}" = "True" ]; then | |
echo "❌ There are unresolved conflicts. Exiting without creating PR." | |
echo "Please resolve the conflicts manually and re-run the workflow." | |
exit 1 | |
fi | |
fi | |
fi | |
# Only proceed with patch creation if we got here (no unresolved conflicts) | |
echo "✅ All conflicts resolved or patch applied successfully. Creating new patch file." | |
# Store resolution output for PR body if it exists | |
if [ -f "../node/resolution_output.txt" ]; then | |
echo "RESOLUTION_OUTPUT<<EOF" >> $GITHUB_ENV | |
cat ../node/resolution_output.txt >> $GITHUB_ENV | |
echo "EOF" >> $GITHUB_ENV | |
# delete resolution output file | |
rm -f ../node/resolution_output.txt | |
else | |
echo "RESOLUTION_OUTPUT=" >> $GITHUB_ENV | |
fi | |
# delete old patch file and create new one | |
rm -rf ../pkg-fetch/$PATCH_FILE | |
git add -A | |
git diff --staged --src-prefix=node/ --dst-prefix=node/ > ../pkg-fetch/patches/node.v${{ inputs.nodeVersion }}.cpp.patch | |
# Update patches.json | |
echo "Updating patches.json" | |
cd ../pkg-fetch/patches | |
sed -i "s/\"v$PATCH_VERSION\": \[\"node.v$PATCH_VERSION.cpp.patch\"\]/\"v${{ inputs.nodeVersion }}\": \[\"node.v${{ inputs.nodeVersion }}.cpp.patch\"\]/" patches.json | |
# Set default values for environment variables if not already set | |
echo "PATCH_STATUS=${PATCH_STATUS:-clean}" >> $GITHUB_ENV | |
echo "HAS_UNRESOLVED=${HAS_UNRESOLVED:-false}" >> $GITHUB_ENV | |
echo "CREATE_PR=true" >> $GITHUB_ENV | |
cd .. | |
- name: Create Pull Request | |
if: env.CREATE_PR == 'true' | |
uses: peter-evans/create-pull-request@v4 | |
with: | |
token: ${{ secrets.GITHUB_TOKEN }} | |
commit-message: "feat: add v${{ inputs.nodeVersion }} patch" | |
title: "feat: add v${{ inputs.nodeVersion }} patch" | |
body: | | |
## Node.js Patch Update to v${{ inputs.nodeVersion }} | |
This PR updates the Node.js patch to version ${{ inputs.nodeVersion }}. | |
The workflow automatically attempts to resolve patch conflicts using AI when the OpenAI API key is available. | |
${{ env.RESOLUTION_OUTPUT && '### AI Resolution Details' || '' }} | |
${{ env.RESOLUTION_OUTPUT }} | |
branch: "nodejs-v${{ inputs.nodeVersion }}" | |
base: "main" | |
delete-branch: true | |
labels: "enhancement,nodejs" | |
draft: false | |