mirror of
https://github.com/langgenius/dify-docs.git
synced 2026-03-27 13:28:32 +07:00
Changes: - Use github.run_id in analyze workflow artifact name - Use github.event.workflow_run.id in update workflow download - This fixes the issue where PR number is not accessible in workflow_run context 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
371 lines
16 KiB
YAML
371 lines
16 KiB
YAML
# Workflow for updating translation PRs on sync events
|
||
# Triggered by Analyze workflow for security validation
|
||
name: Update Translation PR
|
||
|
||
on:
|
||
workflow_run:
|
||
workflows: ["Analyze Documentation Changes"]
|
||
types: [completed]
|
||
branches-ignore:
|
||
- 'docs-sync-pr-*'
|
||
|
||
permissions:
|
||
contents: write
|
||
pull-requests: write
|
||
actions: read
|
||
|
||
jobs:
|
||
update-translation:
|
||
runs-on: ubuntu-latest
|
||
# Only run if analyze workflow succeeded
|
||
if: github.event.workflow_run.conclusion == 'success'
|
||
steps:
|
||
- name: Download analysis artifacts
|
||
uses: actions/download-artifact@v4
|
||
with:
|
||
name: docs-sync-analysis-${{ github.event.workflow_run.id }}
|
||
path: /tmp/analysis
|
||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||
run-id: ${{ github.event.workflow_run.id }}
|
||
|
||
- name: Load and validate analysis
|
||
id: load-analysis
|
||
run: |
|
||
echo "Loading validated analysis from secure workflow..."
|
||
|
||
# Check if sync_plan.json exists (created by analyze workflow)
|
||
if [ ! -f "/tmp/analysis/sync_plan.json" ]; then
|
||
echo "❌ No sync plan found - analyze workflow may have skipped this PR"
|
||
echo "should_proceed=false" >> $GITHUB_OUTPUT
|
||
exit 0
|
||
fi
|
||
|
||
# Load analysis metadata
|
||
PR_NUMBER=$(jq -r '.metadata.pr_number' /tmp/analysis/sync_plan.json)
|
||
PR_TYPE=$(jq -r '.metadata.pr_type' /tmp/analysis/sync_plan.json)
|
||
IS_INCREMENTAL=$(jq -r '.metadata.is_incremental' /tmp/analysis/sync_plan.json)
|
||
BASE_SHA=$(jq -r '.metadata.base_sha' /tmp/analysis/sync_plan.json)
|
||
HEAD_SHA=$(jq -r '.metadata.head_sha' /tmp/analysis/sync_plan.json)
|
||
|
||
# Verify this is an English-only PR (already validated by analyze workflow)
|
||
if [ "$PR_TYPE" != "english" ]; then
|
||
echo "ℹ️ Not an English-only PR (type: $PR_TYPE) - skipping translation update"
|
||
echo "should_proceed=false" >> $GITHUB_OUTPUT
|
||
exit 0
|
||
fi
|
||
|
||
echo "✅ Validated analysis loaded from secure workflow"
|
||
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
|
||
echo "is_incremental=$IS_INCREMENTAL" >> $GITHUB_OUTPUT
|
||
echo "base_sha=$BASE_SHA" >> $GITHUB_OUTPUT
|
||
echo "head_sha=$HEAD_SHA" >> $GITHUB_OUTPUT
|
||
echo "should_proceed=true" >> $GITHUB_OUTPUT
|
||
|
||
# Display summary
|
||
FILE_COUNT=$(jq -r '.metadata.file_count // 0' /tmp/analysis/sync_plan.json)
|
||
echo "📊 Analysis Summary:"
|
||
echo " - PR: #$PR_NUMBER"
|
||
echo " - Type: $PR_TYPE"
|
||
echo " - Files: $FILE_COUNT"
|
||
echo " - Incremental: $IS_INCREMENTAL"
|
||
echo " - Range: ${BASE_SHA:0:8}...${HEAD_SHA:0:8}"
|
||
|
||
- name: Checkout PR
|
||
if: steps.load-analysis.outputs.should_proceed == 'true'
|
||
uses: actions/checkout@v4
|
||
with:
|
||
ref: ${{ steps.load-analysis.outputs.head_sha }}
|
||
fetch-depth: 0
|
||
token: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
- name: Set up Python
|
||
if: steps.load-analysis.outputs.should_proceed == 'true'
|
||
uses: actions/setup-python@v4
|
||
with:
|
||
python-version: '3.9'
|
||
|
||
- name: Find associated translation PR
|
||
if: steps.load-analysis.outputs.should_proceed == 'true'
|
||
id: find-translation-pr
|
||
env:
|
||
GH_TOKEN: ${{ github.token }}
|
||
run: |
|
||
PR_NUMBER="${{ steps.load-analysis.outputs.pr_number }}"
|
||
echo "Looking for translation PR associated with PR #${PR_NUMBER}..."
|
||
|
||
# Search for translation PR by branch name pattern
|
||
TRANSLATION_PR_DATA=$(gh pr list \
|
||
--search "head:docs-sync-pr-${PR_NUMBER}" \
|
||
--json number,title,url,state \
|
||
--jq '.[0] // empty' 2>/dev/null || echo "")
|
||
|
||
if [ -n "$TRANSLATION_PR_DATA" ] && [ "$TRANSLATION_PR_DATA" != "null" ]; then
|
||
TRANSLATION_PR_NUMBER=$(echo "$TRANSLATION_PR_DATA" | jq -r '.number')
|
||
TRANSLATION_PR_STATE=$(echo "$TRANSLATION_PR_DATA" | jq -r '.state')
|
||
TRANSLATION_PR_URL=$(echo "$TRANSLATION_PR_DATA" | jq -r '.url')
|
||
|
||
if [ "$TRANSLATION_PR_STATE" = "OPEN" ]; then
|
||
echo "✅ Found active translation PR #${TRANSLATION_PR_NUMBER}"
|
||
echo "translation_pr_number=$TRANSLATION_PR_NUMBER" >> $GITHUB_OUTPUT
|
||
echo "translation_pr_url=$TRANSLATION_PR_URL" >> $GITHUB_OUTPUT
|
||
echo "found_translation_pr=true" >> $GITHUB_OUTPUT
|
||
else
|
||
echo "ℹ️ Found translation PR #${TRANSLATION_PR_NUMBER} but it's ${TRANSLATION_PR_STATE} - skipping update"
|
||
echo "found_translation_pr=false" >> $GITHUB_OUTPUT
|
||
fi
|
||
else
|
||
echo "ℹ️ No translation PR found for PR #${PR_NUMBER} - this might be the first update"
|
||
echo "found_translation_pr=false" >> $GITHUB_OUTPUT
|
||
fi
|
||
|
||
- name: Determine update range
|
||
if: steps.find-translation-pr.outputs.found_translation_pr == 'true'
|
||
id: update-range
|
||
env:
|
||
GH_TOKEN: ${{ github.token }}
|
||
run: |
|
||
PR_NUMBER="${{ steps.load-analysis.outputs.pr_number }}"
|
||
HEAD_SHA="${{ steps.load-analysis.outputs.head_sha }}"
|
||
BASE_SHA="${{ steps.load-analysis.outputs.base_sha }}"
|
||
|
||
echo "Determining incremental update range..."
|
||
|
||
# Get last processed commit from translation branch commit messages
|
||
SYNC_BRANCH="docs-sync-pr-${PR_NUMBER}"
|
||
git fetch origin "$SYNC_BRANCH" 2>/dev/null || true
|
||
|
||
LAST_PROCESSED=$(git log "origin/$SYNC_BRANCH" --format=%B -1 \
|
||
| grep -oP 'Last-Processed-Commit: \K[a-f0-9]+' \
|
||
| head -1 || echo "")
|
||
|
||
if [ -n "$LAST_PROCESSED" ]; then
|
||
echo "✅ Found last processed commit: $LAST_PROCESSED"
|
||
COMPARE_BASE="$LAST_PROCESSED"
|
||
else
|
||
echo "⚠️ No last processed commit found, using analysis base SHA"
|
||
COMPARE_BASE="$BASE_SHA"
|
||
fi
|
||
|
||
COMPARE_HEAD="$HEAD_SHA"
|
||
|
||
echo "compare_base=$COMPARE_BASE" >> $GITHUB_OUTPUT
|
||
echo "compare_head=$COMPARE_HEAD" >> $GITHUB_OUTPUT
|
||
|
||
echo "📊 Incremental update range: $COMPARE_BASE...$COMPARE_HEAD"
|
||
|
||
- name: Install dependencies
|
||
if: steps.find-translation-pr.outputs.found_translation_pr == 'true'
|
||
run: |
|
||
cd tools/translate
|
||
pip install httpx aiofiles python-dotenv
|
||
|
||
- name: Run translation and commit
|
||
if: steps.find-translation-pr.outputs.found_translation_pr == 'true'
|
||
id: update-translations
|
||
env:
|
||
DIFY_API_KEY: ${{ secrets.DIFY_API_KEY }}
|
||
GH_TOKEN: ${{ github.token }}
|
||
run: |
|
||
echo "Running incremental translation update with validated inputs..."
|
||
|
||
PR_NUMBER="${{ steps.load-analysis.outputs.pr_number }}"
|
||
HEAD_SHA="${{ steps.update-range.outputs.compare_head }}"
|
||
BASE_SHA="${{ steps.update-range.outputs.compare_base }}"
|
||
|
||
# Get PR title from workflow run event
|
||
PR_TITLE="${{ github.event.workflow_run.pull_requests[0].title }}"
|
||
|
||
echo "PR: #${PR_NUMBER}"
|
||
echo "Comparison: ${BASE_SHA:0:8}...${HEAD_SHA:0:8}"
|
||
echo "Using validated sync plan from analyze workflow"
|
||
|
||
# Call the Python script for incremental translation
|
||
cd tools/translate
|
||
python translate_pr.py \
|
||
--pr-number "$PR_NUMBER" \
|
||
--head-sha "$HEAD_SHA" \
|
||
--base-sha "$BASE_SHA" \
|
||
--pr-title "$PR_TITLE" \
|
||
--is-incremental \
|
||
2>&1 | tee /tmp/translation_output.log
|
||
|
||
SCRIPT_EXIT_CODE=${PIPESTATUS[0]}
|
||
|
||
# Extract JSON result
|
||
RESULT_JSON=$(grep -A 1000 "RESULT_JSON:" /tmp/translation_output.log | tail -n +2 | grep -B 1000 "^========" | head -n -1)
|
||
|
||
if [ -n "$RESULT_JSON" ]; then
|
||
echo "$RESULT_JSON" > /tmp/translation_result.json
|
||
|
||
# Parse outputs
|
||
SUCCESS=$(echo "$RESULT_JSON" | jq -r '.success')
|
||
HAS_CHANGES=$(echo "$RESULT_JSON" | jq -r '.has_changes // false')
|
||
|
||
echo "has_changes=$HAS_CHANGES" >> $GITHUB_OUTPUT
|
||
echo "commit_successful=$([ "$SUCCESS" = "true" ] && echo true || echo false)" >> $GITHUB_OUTPUT
|
||
|
||
# Extract translation results
|
||
echo "$RESULT_JSON" | jq -r '.translation_results' > /tmp/update_results.json 2>/dev/null || echo '{"translated":[],"failed":[],"skipped":[]}' > /tmp/update_results.json
|
||
|
||
echo "✅ Translation update completed"
|
||
else
|
||
echo "❌ Could not parse result JSON"
|
||
echo "has_changes=false" >> $GITHUB_OUTPUT
|
||
echo "commit_successful=false" >> $GITHUB_OUTPUT
|
||
exit 1
|
||
fi
|
||
|
||
exit $SCRIPT_EXIT_CODE
|
||
|
||
- name: Comment on original PR about update
|
||
if: steps.update-translations.outputs.has_changes == 'true' && steps.update-translations.outputs.commit_successful == 'true'
|
||
uses: actions/github-script@v7
|
||
continue-on-error: true
|
||
with:
|
||
script: |
|
||
const fs = require('fs');
|
||
const prNumber = ${{ steps.load-analysis.outputs.pr_number }};
|
||
const translationPrNumber = '${{ steps.find-translation-pr.outputs.translation_pr_number }}';
|
||
const translationPrUrl = '${{ steps.find-translation-pr.outputs.translation_pr_url }}';
|
||
|
||
// Load update results
|
||
let results = { translated: [], failed: [], skipped: [] };
|
||
try {
|
||
results = JSON.parse(fs.readFileSync('/tmp/update_results.json', 'utf8'));
|
||
} catch (e) {
|
||
console.log('Could not load update results');
|
||
}
|
||
|
||
let comment = `## 🔄 Translation PR Updated\n\n`
|
||
comment += `Your English documentation changes have been automatically translated and the translation PR has been updated.\n\n`
|
||
|
||
comment += `### 📝 Original Changes\n\n`;
|
||
comment += `- **Original PR**: #${prNumber}\n`;
|
||
comment += `- **Type**: English documentation updates\n`;
|
||
|
||
comment += `### 🔄 Synchronization\n\n`;
|
||
comment += `- **Automatic Updates**: This PR will be automatically updated if the original PR changes\n`;
|
||
comment += `- **Independent Review**: This translation PR can be reviewed and merged independently\n`;
|
||
|
||
if (results.translated && results.translated.length > 0) {
|
||
comment += `### ✅ Updated Translations (${results.translated.length} files):\n`;
|
||
results.translated.slice(0, 6).forEach(file => {
|
||
comment += `- \`${file}\`\n`;
|
||
});
|
||
if (results.translated.length > 6) {
|
||
comment += `- ... and ${results.translated.length - 6} more files\n`;
|
||
}
|
||
comment += '\n';
|
||
}
|
||
|
||
if (results.failed && results.failed.length > 0) {
|
||
comment += `### ⚠️ Update Issues (${results.failed.length}):\n`;
|
||
results.failed.slice(0, 3).forEach(file => {
|
||
comment += `- \`${file}\`\n`;
|
||
});
|
||
comment += '\n';
|
||
}
|
||
|
||
comment += `### 🔄 What's Updated:
|
||
- **Translation Files**: All corresponding cn and jp files
|
||
- **Navigation Structure**: Updated docs.json if needed
|
||
- **Automatic**: This update happened automatically when you updated your PR
|
||
|
||
---
|
||
🤖 _Automatic update from the translation workflow._`;
|
||
|
||
try {
|
||
await github.rest.issues.createComment({
|
||
owner: context.repo.owner,
|
||
repo: context.repo.repo,
|
||
issue_number: prNumber,
|
||
body: comment
|
||
});
|
||
} catch (error) {
|
||
console.log('Could not comment on original PR:', error.message);
|
||
}
|
||
|
||
- name: Comment on translation PR about update
|
||
if: steps.update-translations.outputs.has_changes == 'true' && steps.update-translations.outputs.commit_successful == 'true'
|
||
uses: actions/github-script@v7
|
||
continue-on-error: true
|
||
with:
|
||
script: |
|
||
const fs = require('fs');
|
||
const prNumber = ${{ steps.load-analysis.outputs.pr_number }};
|
||
const translationPrNumber = '${{ steps.find-translation-pr.outputs.translation_pr_number }}';
|
||
|
||
// Load update results
|
||
let results = { translated: [], failed: [], skipped: [] };
|
||
try {
|
||
results = JSON.parse(fs.readFileSync('/tmp/update_results.json', 'utf8'));
|
||
} catch (e) {
|
||
console.log('Could not load update results');
|
||
}
|
||
|
||
const updateComment = `## 🔄 Automatic Translation Update
|
||
|
||
This translation PR has been automatically updated following changes in the original PR #${prNumber}.
|
||
|
||
### 📝 What Was Updated:
|
||
- **Source**: Changes from PR #${prNumber}
|
||
- **Updated Files**: ${results.translated ? results.translated.length : 0} translation files
|
||
- **Languages**: Chinese (cn) and Japanese (jp)
|
||
|
||
### ✅ Translation Status:
|
||
${results.translated && results.translated.length > 0 ?
|
||
`**Successfully Updated (${results.translated.length} files):**\n` +
|
||
results.translated.slice(0, 5).map(f => `- \`${f}\``).join('\n') +
|
||
(results.translated.length > 5 ? `\n- ... and ${results.translated.length - 5} more` : '') :
|
||
'- All translations are up to date'}
|
||
|
||
${results.failed && results.failed.length > 0 ?
|
||
`\n### ⚠️ Update Issues:\n${results.failed.slice(0, 3).map(f => `- \`${f}\``).join('\n')}` : ''}
|
||
|
||
### 🔄 Review Process:
|
||
1. **Automatic Update**: This PR was updated automatically
|
||
2. **Review Needed**: Please review the updated translations
|
||
3. **Independent Merge**: This PR can still be merged independently
|
||
|
||
---
|
||
🤖 _This update was triggered automatically by changes to PR #${prNumber}._`;
|
||
|
||
try {
|
||
await github.rest.issues.createComment({
|
||
owner: context.repo.owner,
|
||
repo: context.repo.repo,
|
||
issue_number: translationPrNumber,
|
||
body: updateComment
|
||
});
|
||
} catch (error) {
|
||
console.log('Could not comment on translation PR:', error.message);
|
||
}
|
||
|
||
- name: Handle no updates needed
|
||
if: steps.find-translation-pr.outputs.found_translation_pr == 'true' && steps.update-translations.outputs.has_changes != 'true'
|
||
uses: actions/github-script@v7
|
||
continue-on-error: true
|
||
with:
|
||
script: |
|
||
const prNumber = ${{ steps.load-analysis.outputs.pr_number }};
|
||
const translationPrNumber = '${{ steps.find-translation-pr.outputs.translation_pr_number }}';
|
||
|
||
const comment = `## ✅ Translation PR Already Up to Date
|
||
|
||
Your changes to PR #${prNumber} did not require translation updates.
|
||
|
||
The translation PR [#${translationPrNumber}](https://github.com/${{ github.repository }}/pull/${translationPrNumber}) remains current.
|
||
|
||
🤖 _Automatic check from the translation workflow._`;
|
||
|
||
try {
|
||
await github.rest.issues.createComment({
|
||
owner: context.repo.owner,
|
||
repo: context.repo.repo,
|
||
issue_number: prNumber,
|
||
body: comment
|
||
});
|
||
} catch (error) {
|
||
console.log('Could not comment on original PR:', error.message);
|
||
}
|