chore: import upstream snapshot with attribution
Auto Update PR / update-prs (push) Has been cancelled
CI / format-check (push) Has been cancelled
CI / test (3.10) (push) Has been cancelled
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / live-api-tests (push) Has been cancelled
CI / plugin-integration-test (push) Has been cancelled
CI / ollama-integration-test (push) Has been cancelled
CI / test-fork-pr (push) Has been cancelled
Auto Update PR / update-prs (push) Has been cancelled
CI / format-check (push) Has been cancelled
CI / test (3.10) (push) Has been cancelled
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / live-api-tests (push) Has been cancelled
CI / plugin-integration-test (push) Has been cancelled
CI / ollama-integration-test (push) Has been cancelled
CI / test-fork-pr (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
# Copyright 2025 Google LLC.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
name: Auto Update PR
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
schedule:
|
||||
# Run daily at 2 AM UTC to catch stale PRs
|
||||
- cron: '0 2 * * *'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pr_number:
|
||||
description: 'PR number to update (optional, updates all if not specified)'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write # Required for updateBranch API
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
update-prs:
|
||||
runs-on: ubuntu-latest
|
||||
concurrency:
|
||||
group: auto-update-pr-${{ github.event_name }}
|
||||
cancel-in-progress: true
|
||||
steps:
|
||||
- name: Update PRs that are behind main
|
||||
uses: actions/github-script@v9
|
||||
with:
|
||||
script: |
|
||||
const prNumber = context.payload.inputs?.pr_number;
|
||||
|
||||
// Get list of open PRs
|
||||
const prs = prNumber
|
||||
? [(await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: parseInt(prNumber)
|
||||
})).data]
|
||||
: await github.paginate(github.rest.pulls.list, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
state: 'open',
|
||||
sort: 'updated',
|
||||
direction: 'desc'
|
||||
});
|
||||
|
||||
console.log(`Found ${prs.length} open PRs to check`);
|
||||
|
||||
// Constants for comment flood control
|
||||
const UPDATE_COMMENT_COOLDOWN_DAYS = 7;
|
||||
const COOLDOWN_MS = UPDATE_COMMENT_COOLDOWN_DAYS * 24 * 60 * 60 * 1000;
|
||||
|
||||
for (const pr of prs) {
|
||||
// Skip bot PRs and drafts
|
||||
if (pr.user.login.includes('[bot]')) {
|
||||
console.log(`Skipping bot PR #${pr.number} from ${pr.user.login}`);
|
||||
continue;
|
||||
}
|
||||
if (pr.draft) {
|
||||
console.log(`Skipping draft PR #${pr.number}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if PR is behind main (base...head comparison)
|
||||
const { data: comparison } = await github.rest.repos.compareCommits({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
base: pr.base.ref, // main branch
|
||||
head: `${pr.head.repo.owner.login}:${pr.head.ref}` // Fully qualified ref for forks
|
||||
});
|
||||
|
||||
if (comparison.behind_by > 0) {
|
||||
console.log(`PR #${pr.number} is ${comparison.behind_by} commits behind ${pr.base.ref}`);
|
||||
|
||||
// Check if the PR allows maintainer edits
|
||||
if (pr.maintainer_can_modify) {
|
||||
// Try to update the branch
|
||||
try {
|
||||
await github.rest.pulls.updateBranch({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: pr.number
|
||||
});
|
||||
|
||||
console.log(`✅ Updated PR #${pr.number}`);
|
||||
|
||||
// Add a comment
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
body: `🔄 **Branch Updated**\n\nYour branch was ${comparison.behind_by} commits behind \`${pr.base.ref}\` and has been automatically updated. CI checks will re-run shortly.`
|
||||
});
|
||||
} catch (updateError) {
|
||||
console.log(`Could not auto-update PR #${pr.number}: ${updateError.message}`);
|
||||
|
||||
// Determine the reason for failure
|
||||
let failureReason = '';
|
||||
if (updateError.status === 409 || updateError.message.includes('merge conflict')) {
|
||||
failureReason = '\n\n**Note:** Automatic update failed due to merge conflicts. Please resolve them manually.';
|
||||
} else if (updateError.status === 422) {
|
||||
failureReason = '\n\n**Note:** Cannot push to fork. Please update manually.';
|
||||
}
|
||||
|
||||
// Notify the contributor to update manually
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
body: `⚠️ **Branch Update Required**\n\nYour branch is ${comparison.behind_by} commits behind \`${pr.base.ref}\`.${failureReason}\n\nPlease update your branch:\n\n\`\`\`bash\ngit fetch origin ${pr.base.ref}\ngit merge origin/${pr.base.ref}\ngit push\n\`\`\`\n\nOr use GitHub's "Update branch" button if available.`
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Can't modify, just notify
|
||||
console.log(`PR #${pr.number} doesn't allow maintainer edits`);
|
||||
|
||||
// Check if we already commented recently (within last 7 days)
|
||||
const { data: comments } = await github.rest.issues.listComments({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
since: new Date(Date.now() - COOLDOWN_MS).toISOString()
|
||||
});
|
||||
|
||||
const hasRecentUpdateComment = comments.some(c =>
|
||||
c.body?.includes('Branch Update Required') &&
|
||||
c.user?.login === 'github-actions[bot]'
|
||||
);
|
||||
|
||||
if (!hasRecentUpdateComment) {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
body: `⚠️ **Branch Update Required**\n\nYour branch is ${comparison.behind_by} commits behind \`${pr.base.ref}\`. Please update your branch to ensure CI checks run with the latest code:\n\n\`\`\`bash\ngit fetch origin ${pr.base.ref}\ngit merge origin/${pr.base.ref}\ngit push\n\`\`\`\n\nNote: Enable "Allow edits by maintainers" to allow automatic updates.`
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log(`PR #${pr.number} is up to date`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error processing PR #${pr.number}:`, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Log rate limit status
|
||||
const { data: rateLimit } = await github.rest.rateLimit.get();
|
||||
console.log(`API rate limit remaining: ${rateLimit.rate.remaining}/${rateLimit.rate.limit}`);
|
||||
Reference in New Issue
Block a user