🔧 chore: Update i18n actions (#8142)

This commit is contained in:
CanisMinor
2025-06-11 12:33:41 +08:00
committed by GitHub
parent 17431106bb
commit a26499f0bf
2 changed files with 532 additions and 17 deletions
+256
View File
@@ -0,0 +1,256 @@
/**
* Create or update GitHub issue when i18n workflow fails
* Usage: node create-failure-issue.js
*/
module.exports = async ({ github, context, core }) => {
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const timestamp = new Date().toISOString();
const date = timestamp.split('T')[0];
// Get error details from environment variables
const errorDetails = {
validateEnv: process.env.ERROR_VALIDATE_ENV || '',
rebaseAttempt: process.env.ERROR_REBASE_ATTEMPT || '',
createBranch: process.env.ERROR_CREATE_BRANCH || '',
installDeps: process.env.ERROR_INSTALL_DEPS || '',
runI18n: process.env.ERROR_RUN_I18N || '',
commitPush: process.env.ERROR_COMMIT_PUSH || '',
};
// Get step conclusions from environment variables
const stepStatus = {
validateEnv: process.env.STEP_VALIDATE_ENV || 'Not run',
checkBranch: process.env.STEP_CHECK_BRANCH || 'Not run',
rebaseAttempt: process.env.STEP_REBASE_ATTEMPT || 'Not run',
createBranch: process.env.STEP_CREATE_BRANCH || 'Not run',
installDeps: process.env.STEP_INSTALL_DEPS || 'Not run',
runI18n: process.env.STEP_RUN_I18N || 'Not run',
commitPush: process.env.STEP_COMMIT_PUSH || 'Not run',
createPr: process.env.STEP_CREATE_PR || 'Not run',
};
// Find the first non-empty error
const mainError =
Object.values(errorDetails).find((error) => error && error.trim()) || 'Unknown error occurred';
// Determine error category for better troubleshooting
const getErrorCategory = (error) => {
if (error.includes('API') || error.includes('authentication')) return 'API/Authentication';
if (error.includes('network') || error.includes('timeout')) return 'Network/Connectivity';
if (error.includes('dependencies') || error.includes('bun')) return 'Dependencies';
if (error.includes('git') || error.includes('branch') || error.includes('rebase'))
return 'Git Operations';
if (error.includes('permission') || error.includes('token')) return 'Permissions';
return 'General';
};
const errorCategory = getErrorCategory(mainError);
const issueTitle = `🚨 Daily i18n Update Failed - ${date}`;
const issueBody = `## 🚨 Automated i18n Update Failure
**Timestamp:** ${timestamp}
**Workflow Run:** [#${context.runNumber}](${runUrl})
**Repository:** ${context.repo.owner}/${context.repo.repo}
**Branch:** ${context.ref}
**Commit:** ${context.sha}
## ❌ Error Details
**Primary Error:** ${mainError}
**Category:** ${errorCategory}
## 🔍 Step Status
| Step | Status |
|------|--------|
| Environment Validation | ${stepStatus.validateEnv} |
| Branch Check | ${stepStatus.checkBranch} |
| Rebase Attempt | ${stepStatus.rebaseAttempt} |
| Branch Creation | ${stepStatus.createBranch} |
| Dependencies | ${stepStatus.installDeps} |
| i18n Update | ${stepStatus.runI18n} |
| Git Operations | ${stepStatus.commitPush} |
| PR Creation | ${stepStatus.createPr} |
## 🔧 Environment Info
- **Runner OS:** ${process.env.RUNNER_OS || 'Unknown'}
- **Bun Version:** ${process.env.BUN_VERSION || 'Default'}
- **Workflow:** \`${context.workflow}\`
## 📋 Debug Information
Debug logs have been uploaded as artifacts and will be available for 7 days.
${getErrorCategoryHelp(errorCategory)}
## 🛠️ General Troubleshooting Steps
1. Check if all required secrets are properly configured
2. Verify OpenAI API quota and billing status
3. Review the workflow run logs for detailed error messages
4. Check if there are any ongoing GitHub API issues
5. Manually trigger the workflow to retry
## 📊 Workflow Statistics
- **Run Number:** ${context.runNumber}
- **Run ID:** ${context.runId}
- **Event:** ${context.eventName}
---
**Auto-generated by:** [\`${context.workflow}\`](${runUrl})
**Labels:** automated, bug, i18n, workflow-failure, ${errorCategory.toLowerCase().replace(/[^a-z0-9]/g, '-')}`;
try {
// Search for existing open issues with similar title
const existingIssues = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
labels: 'automated,workflow-failure',
state: 'open',
per_page: 50,
});
const todayPrefix = `🚨 Daily i18n Update Failed - ${date}`;
const existingIssue = existingIssues.data.find((issue) => issue.title.startsWith(todayPrefix));
if (existingIssue) {
// Update existing issue with comment
const commentBody = `## 🔄 Additional Failure
**Timestamp:** ${timestamp}
**Workflow Run:** [#${context.runNumber}](${runUrl})
**Error Category:** ${errorCategory}
**Error:** ${mainError}
Same issue occurred again. Please investigate the recurring problem.
### Quick Actions
- [ ] Check API quotas and billing
- [ ] Verify network connectivity
- [ ] Review recent changes that might cause conflicts
- [ ] Consider manual intervention
---
*This is failure #${(await getFailureCount(github, context, existingIssue.number)) + 1} for today.*`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: existingIssue.number,
body: commentBody,
});
// Add priority label if this is a recurring issue
const failureCount = await getFailureCount(github, context, existingIssue.number);
if (failureCount >= 2) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: existingIssue.number,
labels: ['priority-high', 'recurring'],
});
}
core.info(`✅ Updated existing issue #${existingIssue.number}`);
core.setOutput('issue-number', existingIssue.number);
core.setOutput('issue-url', existingIssue.html_url);
core.setOutput('action', 'updated');
} else {
// Create new issue
const labels = [
'automated',
'bug',
'i18n',
'workflow-failure',
errorCategory.toLowerCase().replace(/[^a-z0-9]/g, '-'),
];
const issue = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: issueTitle,
body: issueBody,
labels: labels,
});
core.info(`✅ Created new issue #${issue.data.number}`);
core.setOutput('issue-number', issue.data.number);
core.setOutput('issue-url', issue.data.html_url);
core.setOutput('action', 'created');
}
} catch (error) {
core.setFailed(`Failed to create or update issue: ${error.message}`);
throw error;
}
};
/**
* Get category-specific help text
*/
function getErrorCategoryHelp(category) {
const helpTexts = {
'API/Authentication': `
### 🔑 API/Authentication Issues
- Verify \`OPENAI_API_KEY\` is correctly set and valid
- Check if API key has sufficient quota/credits
- Ensure \`GH_TOKEN\` has necessary permissions
- Test API connectivity manually`,
'Network/Connectivity': `
### 🌐 Network/Connectivity Issues
- Check if OpenAI API is experiencing outages
- Verify proxy settings if using \`OPENAI_PROXY_URL\`
- Retry the workflow as this might be temporary
- Check GitHub Actions service status`,
'Dependencies': `
### 📦 Dependencies Issues
- Verify \`bun\` version compatibility
- Check for package.json changes that might affect dependencies
- Clear cache and retry installation
- Review recent dependency updates`,
'Git Operations': `
### 🔧 Git Operations Issues
- Check for conflicting changes in target branch
- Verify repository permissions
- Review recent commits that might cause conflicts
- Manual branch cleanup might be required`,
'Permissions': `
### 🔐 Permissions Issues
- Verify \`GH_TOKEN\` has \`repo\` and \`issues\` permissions
- Check if token can create/update PRs and branches
- Ensure token hasn't expired
- Review repository settings and branch protection rules`,
'General': `
### 🔍 General Issues
- Review detailed error logs in workflow run
- Check for recent changes in codebase
- Verify all environment variables are set
- Consider running workflow manually with debug enabled`,
};
return helpTexts[category] || helpTexts['General'];
}
/**
* Count how many times this issue has failed today
*/
async function getFailureCount(github, context, issueNumber) {
try {
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
});
const today = new Date().toISOString().split('T')[0];
return comments.data.filter(
(comment) =>
comment.body.includes('Additional Failure') && comment.created_at.startsWith(today),
).length;
} catch (error) {
return 0;
}
}
+276 -17
View File
@@ -8,58 +8,317 @@ on:
jobs:
update-i18n:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GH_TOKEN }}
- name: Configure Git
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
- name: Install bun
uses: oven-sh/setup-bun@v1
with:
bun-version: ${{ secrets.BUN_VERSION }}
- name: Validate environment
id: validate_env
run: |
echo "🔍 Validating environment..."
# Check required secrets
if [ -z "${{ secrets.OPENAI_API_KEY }}" ]; then
echo "❌ OPENAI_API_KEY is missing"
echo "env_valid=false" >> $GITHUB_OUTPUT
echo "ERROR_VALIDATE_ENV=OPENAI_API_KEY secret is not configured" >> $GITHUB_ENV
exit 1
fi
if [ -z "${{ secrets.GH_TOKEN }}" ]; then
echo "❌ GH_TOKEN is missing"
echo "env_valid=false" >> $GITHUB_OUTPUT
echo "ERROR_VALIDATE_ENV=GH_TOKEN secret is not configured" >> $GITHUB_ENV
exit 1
fi
# Test OpenAI API connectivity (optional, with timeout)
echo "🌐 Testing OpenAI API connectivity..."
if timeout 30s curl -s -H "Authorization: Bearer ${{ secrets.OPENAI_API_KEY }}" \
${{ secrets.OPENAI_PROXY_URL || 'https://api.openai.com' }}/v1/models >/dev/null 2>&1; then
echo "✅ OpenAI API accessible"
else
echo "⚠️ OpenAI API test failed (but continuing...)"
fi
echo "env_valid=true" >> $GITHUB_OUTPUT
- name: Check if branch exists
id: check_branch
run: |
git ls-remote --exit-code --heads origin style/auto-i18n
echo "::set-output name=branch_exists::$?"
echo "🔍 Checking for existing branch..."
# Retry mechanism for network issues
for i in {1..3}; do
if git ls-remote --exit-code --heads origin style/auto-i18n >/dev/null 2>&1; then
echo "branch_exists=true" >> $GITHUB_OUTPUT
echo "🔍 Found existing branch: style/auto-i18n"
exit 0
elif [ $i -eq 3 ]; then
echo "branch_exists=false" >> $GITHUB_OUTPUT
echo "️ Branch style/auto-i18n does not exist"
exit 0
else
echo "⚠️ Network issue, retrying... ($i/3)"
sleep 5
fi
done
- name: Handle existing branch with rebase
if: steps.check_branch.outputs.branch_exists == 'true'
id: rebase_attempt
run: |
echo "🔄 Attempting to rebase existing branch..."
# Fetch the existing branch with error handling
if ! git fetch origin style/auto-i18n; then
echo "❌ Failed to fetch existing branch"
echo "rebase_success=false" >> $GITHUB_OUTPUT
echo "ERROR_REBASE_ATTEMPT=Failed to fetch existing branch from origin" >> $GITHUB_ENV
exit 1
fi
if ! git checkout -b style/auto-i18n origin/style/auto-i18n; then
echo "❌ Failed to checkout existing branch"
echo "rebase_success=false" >> $GITHUB_OUTPUT
echo "ERROR_REBASE_ATTEMPT=Failed to checkout existing branch" >> $GITHUB_ENV
exit 1
fi
# Try to rebase onto latest main
if git rebase origin/main; then
echo "✅ Rebase successful"
echo "rebase_success=true" >> $GITHUB_OUTPUT
else
echo "❌ Rebase failed due to conflicts"
echo "rebase_success=false" >> $GITHUB_OUTPUT
# Abort the failed rebase
git rebase --abort || echo "⚠️ Failed to abort rebase cleanly"
# Go back to main and delete the problematic branch
git checkout main
git branch -D style/auto-i18n || echo "⚠️ Failed to delete local branch"
# Try to delete remote branch, handle if it fails
if git push origin --delete style/auto-i18n 2>/dev/null; then
echo "🗑️ Deleted old branch due to rebase conflicts"
else
echo "⚠️ Could not delete remote branch (may not exist or permission issue)"
fi
fi
- name: Create clean branch if needed
if: steps.check_branch.outputs.branch_exists == 'false' || steps.rebase_attempt.outputs.rebase_success == 'false'
id: create_branch
run: |
echo "🌿 Creating fresh branch from main..."
# Ensure we're on main and it's up to date
git checkout main
git pull origin main
# Create new branch
if git checkout -b style/auto-i18n; then
echo "✅ Successfully created new branch"
echo "branch_created=true" >> $GITHUB_OUTPUT
else
echo "❌ Failed to create new branch"
echo "branch_created=false" >> $GITHUB_OUTPUT
echo "ERROR_CREATE_BRANCH=Failed to create new branch style/auto-i18n" >> $GITHUB_ENV
exit 1
fi
- name: Install deps
run: bun i
id: install_deps
run: |
echo "📦 Installing dependencies..."
# Retry mechanism for dependency installation
for i in {1..3}; do
if bun i; then
echo "✅ Dependencies installed successfully"
echo "deps_installed=true" >> $GITHUB_OUTPUT
exit 0
elif [ $i -eq 3 ]; then
echo "❌ Failed to install dependencies after 3 attempts"
echo "deps_installed=false" >> $GITHUB_OUTPUT
echo "ERROR_INSTALL_DEPS=Failed to install dependencies with bun after 3 retries" >> $GITHUB_ENV
exit 1
else
echo "⚠️ Dependency installation failed, retrying... ($i/3)"
sleep 10
fi
done
- name: Run i18n update
if: steps.check_branch.outputs.branch_exists != 0
run: bun run i18n
id: run_i18n
run: |
echo "🌐 Running i18n update..."
# Set timeout and capture output
if timeout 900s bun run i18n 2>&1 | tee i18n_output.log; then
echo "✅ i18n update completed successfully"
echo "i18n_success=true" >> $GITHUB_OUTPUT
else
exit_code=$?
echo "❌ i18n update failed with exit code: $exit_code"
echo "i18n_success=false" >> $GITHUB_OUTPUT
# Capture error details
if [ $exit_code -eq 124 ]; then
echo "ERROR_RUN_I18N=i18n update timed out after 15 minutes" >> $GITHUB_ENV
else
echo "ERROR_RUN_I18N=i18n update failed with exit code $exit_code" >> $GITHUB_ENV
fi
# Save output for debugging
echo "📋 Saving debug output..."
exit 1
fi
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_PROXY_URL: ${{ secrets.OPENAI_PROXY_URL }}
- name: Check for changes
id: git_status
if: steps.run_i18n.outputs.i18n_success == 'true'
run: |
git diff --exit-code || echo "::set-output name=changes_exist::true"
echo "🔍 Checking for changes..."
- name: Create Pull Request
if: steps.check_branch.outputs.branch_exists != 0 && steps.git_status.outputs.changes_exist == 'true'
if git diff --exit-code >/dev/null 2>&1; then
echo "changes_exist=false" >> $GITHUB_OUTPUT
echo "️ No changes detected"
else
echo "changes_exist=true" >> $GITHUB_OUTPUT
echo "✨ Changes detected"
# Show what changed
echo "📝 Changed files:"
git diff --name-only | head -20
fi
- name: Commit and push changes
if: steps.git_status.outputs.changes_exist == 'true'
id: commit_push
run: |
echo "💾 Committing and pushing changes..."
git add .
git commit -m "🤖 style: update i18n
- Auto-generated i18n updates
- Generated at: $(date -u '+%Y-%m-%d %H:%M:%S UTC')
- Workflow run: ${{ github.run_number }}"
# Push with retry mechanism
for i in {1..3}; do
if git push origin style/auto-i18n --force-with-lease; then
echo "✅ Successfully pushed changes"
echo "push_success=true" >> $GITHUB_OUTPUT
exit 0
elif [ $i -eq 3 ]; then
echo "❌ Failed to push changes after 3 attempts"
echo "push_success=false" >> $GITHUB_OUTPUT
echo "ERROR_COMMIT_PUSH=Failed to push changes to remote repository after 3 retries" >> $GITHUB_ENV
exit 1
else
echo "⚠️ Push failed, retrying... ($i/3)"
sleep 5
fi
done
- name: Create or Update Pull Request
if: steps.git_status.outputs.changes_exist == 'true' && steps.commit_push.outputs.push_success == 'true'
id: create_pr
uses: peter-evans/create-pull-request@v4
with:
token: ${{ secrets.GH_TOKEN }}
commit-message: '🤖 style: update i18n'
branch: 'style/auto-i18n'
delete-branch: true
title: '🤖 style: update i18n'
body: 'This PR updates the i18n files.'
body: |
This PR updates the i18n files.
## 🔄 Update Strategy
${{ steps.check_branch.outputs.branch_exists == 'true' && steps.rebase_attempt.outputs.rebase_success == 'true' && '✅ Successfully rebased existing branch onto latest main' || '' }}
${{ steps.check_branch.outputs.branch_exists == 'true' && steps.rebase_attempt.outputs.rebase_success == 'false' && '🔄 Recreated branch due to rebase conflicts' || '' }}
${{ steps.check_branch.outputs.branch_exists == 'false' && '🌿 Created fresh branch from main' || '' }}
## 📝 Changes
- Auto-generated i18n updates
- Generated at: ${{ github.run_number }}
- Timestamp: $(date -u '+%Y-%m-%d %H:%M:%S UTC')
## 🤖 Automation Info
- Workflow: `${{ github.workflow }}`
- Run ID: `${{ github.run_id }}`
- Commit: `${{ github.sha }}`
> This PR is automatically generated by GitHub Actions and kept up-to-date with the latest main branch.
base: main
labels: |
i18n
automated
style
- name: Check Pull Request Status
if: steps.check_branch.outputs.branch_exists != 0 && steps.git_status.outputs.changes_exist == 'true'
if: steps.git_status.outputs.changes_exist == 'true'
run: |
if [ ${{ steps.create_pull_request.outputs.pull-request-number }} ]; then
echo "Pull request created successfully."
if [ "${{ steps.create_pr.outputs.pull-request-number }}" ]; then
echo "Pull request #${{ steps.create_pr.outputs.pull-request-number }} created/updated successfully."
echo "🔗 PR URL: ${{ steps.create_pr.outputs.pull-request-url }}"
else
echo "Failed to create pull request."
echo "Failed to create/update pull request."
exit 1
fi
- name: No changes
if: steps.git_status.outputs.changes_exist != 'true'
run: echo "No changes to commit. Skipping PR creation."
if: steps.git_status.outputs.changes_exist != 'true' && steps.run_i18n.outputs.i18n_success == 'true'
run: echo "No changes to commit. Skipping PR creation."
# Set step status for issue creation
- name: Set step conclusions
if: always()
run: |
echo "STEP_VALIDATE_ENV=${{ steps.validate_env.conclusion || 'Not run' }}" >> $GITHUB_ENV
echo "STEP_CHECK_BRANCH=${{ steps.check_branch.conclusion || 'Not run' }}" >> $GITHUB_ENV
echo "STEP_REBASE_ATTEMPT=${{ steps.rebase_attempt.conclusion || 'Not run' }}" >> $GITHUB_ENV
echo "STEP_CREATE_BRANCH=${{ steps.create_branch.conclusion || 'Not run' }}" >> $GITHUB_ENV
echo "STEP_INSTALL_DEPS=${{ steps.install_deps.conclusion || 'Not run' }}" >> $GITHUB_ENV
echo "STEP_RUN_I18N=${{ steps.run_i18n.conclusion || 'Not run' }}" >> $GITHUB_ENV
echo "STEP_COMMIT_PUSH=${{ steps.commit_push.conclusion || 'Not run' }}" >> $GITHUB_ENV
echo "STEP_CREATE_PR=${{ steps.create_pr.conclusion || 'Not run' }}" >> $GITHUB_ENV
# Error handling and issue creation
- name: Upload debug artifacts
if: failure()
uses: actions/upload-artifact@v3
with:
name: debug-logs-${{ github.run_number }}
path: |
i18n_output.log
/tmp/*.log
retention-days: 7
- name: Create issue on failure
if: failure()
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GH_TOKEN }}
script: |
const createFailureIssue = require('./.github/scripts/create-failure-issue.js');
return await createFailureIssue({ github, context, core });