Skip to content

auto - [zh](新的关系数据库认证) #389

auto - [zh](新的关系数据库认证)

auto - [zh](新的关系数据库认证) #389

name: Articles Auto Translate
run-name: auto - ${{ github.event.issue.title }}
on:
issues:
types: [labeled]
env:
# Git helper functions for push retry with exponential backoff
PUSH_RETRY_SCRIPT: |
push_with_retry() {
local branch=${1:-main}
local max_retries=${2:-4}
for i in $(seq 1 $max_retries); do
if git push origin "$branch"; then
echo "Push to $branch successful"
return 0
else
wait_time=$((2 ** i))
echo "Push failed, attempt $i/$max_retries. Waiting ${wait_time}s..."
if [ $i -lt $max_retries ]; then
sleep $wait_time
git fetch origin "$branch" || true
git pull --rebase origin "$branch" || true
fi
fi
done
echo "Push failed after $max_retries attempts"
return 1
}
jobs:
# First job: Validate the trigger and extract information
validate:
name: Validate Auto-Translate Trigger
runs-on: ubuntu-latest
# Only run if the label added is "auto"
if: github.event.label.name == 'auto'
outputs:
lang_code: ${{ steps.extract.outputs.lang_code }}
lang_label: ${{ steps.extract.outputs.lang_label }}
is_valid: ${{ steps.extract.outputs.is_valid }}
steps:
- name: Validate issue and extract language
id: extract
run: |
# Extract language code from issue title (e.g., "[zh] Article Title" -> "zh")
title="${{ github.event.issue.title }}"
LANG_CODE=$(echo "$title" | sed -E 's/^\[([a-zA-Z]+)\].*/\1/' | tr '[:upper:]' '[:lower:]')
# Map language codes to language label names
declare -A LANG_MAP=(
["zh"]="chinese"
["es"]="spanish"
["pt"]="portuguese"
["it"]="italian"
["ja"]="japanese"
["ko"]="korean"
["uk"]="ukrainian"
)
LANG_LABEL="${LANG_MAP[$LANG_CODE]:-}"
# Validate
if [ -z "$LANG_CODE" ] || [ -z "$LANG_LABEL" ]; then
echo "is_valid=false" >> $GITHUB_OUTPUT
echo "::error::Could not extract valid language from title: $title"
echo "::error::Expected format: [lang] Title (e.g., [zh] Article Title)"
exit 1
fi
# Validate issue body is not empty
if [ -z "${{ github.event.issue.body }}" ]; then
echo "is_valid=false" >> $GITHUB_OUTPUT
echo "::error::Issue body is empty. Please provide article URL."
exit 1
fi
echo "lang_code=$LANG_CODE" >> $GITHUB_OUTPUT
echo "lang_label=$LANG_LABEL" >> $GITHUB_OUTPUT
echo "is_valid=true" >> $GITHUB_OUTPUT
echo "Language code: $LANG_CODE, Language label: $LANG_LABEL"
auto-translate:
name: Auto Translate Article
needs: validate
if: needs.validate.outputs.is_valid == 'true'
runs-on: ubuntu-latest
permissions:
issues: write
contents: write
# Use language-specific concurrency group so different languages can run in parallel
# but same-language translations are queued
concurrency:
group: auto-translate-${{ needs.validate.outputs.lang_code }}
cancel-in-progress: false
env:
LANG_CODE: ${{ needs.validate.outputs.lang_code }}
LANG_LABEL: ${{ needs.validate.outputs.lang_label }}
steps:
### Queue lock: additional protection for same-language concurrent runs
- uses: softprops/turnstyle@v1
with:
poll-interval-seconds: 15
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Add processing comment
uses: actions/github-script@v7
with:
script: |
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'Auto-translation workflow started for language: **${{ env.LANG_CODE }}**. This may take a few minutes...'
});
### Checkout repository
- uses: actions/checkout@v5
with:
fetch-depth: 0
### Configure Git
- name: Setup Git
run: |
git config user.email "github-actions[bot]@users.noreply.github.com"
git config user.name "github-actions[bot]"
git config pull.rebase true
### Fetch article and generate Markdown
- name: Fetch article and convert to Markdown
id: fetch
uses: freecodecamp/article-webpage-to-markdown-action@dev
with:
newsLink: "${{ github.event.issue.body }}"
includeSelector: 'span.author-card-name,section.post-content'
ignoreSelector: '.ad-wrapper'
skipSameArticleCheck: true
skipIssueComment: true
markDownFilePath: './articles/_tmp/'
githubToken: "${{ github.token }}"
### Backup fetched Markdown to external secure path (keep original filename)
- name: Backup fetched Markdown to /tmp
id: backup-md
run: |
original_file="${{ steps.fetch.outputs.markdown_file_path }}"
filename=$(basename "$original_file")
# Sanitize filename
safe_filename=$(echo "$filename" | sed 's/[^a-zA-Z0-9._-]/-/g')
BACKUP_PATH="/tmp/$safe_filename"
cp "$original_file" "$BACKUP_PATH"
echo "path=$BACKUP_PATH" >> $GITHUB_OUTPUT
echo "filename=$safe_filename" >> $GITHUB_OUTPUT
echo "BACKUP_PATH=$BACKUP_PATH" >> $GITHUB_ENV
echo "SAFE_FILENAME=$safe_filename" >> $GITHUB_ENV
echo "Markdown backed up to $BACKUP_PATH"
### Save English raw text ONLY to _raw folder on main branch
### Do NOT copy to language folder yet - that happens after translation
- name: Commit raw article to main
run: |
file="${{ steps.fetch.outputs.markdown_file_path }}"
base="${{ env.SAFE_FILENAME }}"
mkdir -p "./articles/_raw/"
cp "$file" "./articles/_raw/$base"
git add -f "./articles/_raw/$base" || true
git commit -m "Add raw article: $base" || echo "Nothing to commit."
git fetch origin main
git stash push -u -m "Auto-stash before rebase" || true
git pull --rebase origin main || true
git stash pop || true
# Use push retry function
eval "$PUSH_RETRY_SCRIPT"
push_with_retry main
### Switch to auto-translate branch (resolve conflicts & clean up temp files)
- name: Checkout auto-translate branch
run: |
# Check merge pending status
if [ -f ".git/MERGE_HEAD" ]; then
echo "Unfinished merge detected. Aborting..."
git merge --abort || git reset --merge
fi
# Clean up temp files to avoid branch contamination
rm -rf ./articles/_tmp/
git fetch origin
# Create or checkout auto-translate branch
if git show-ref --verify --quiet refs/remotes/origin/auto-translate; then
git checkout -B auto-translate origin/auto-translate
else
git checkout -b auto-translate
fi
# Merge main to get the raw article
git merge --strategy=recursive --strategy-option=theirs main || true
### Ensure language directory exists
- name: Prepare language directory
run: |
lang="${{ env.LANG_CODE }}"
mkdir -p "./articles/$lang/"
### Auto-translate article (use secure path)
- name: Translate article
uses: freeCodeCamp/articles-auto-translate-action@main
with:
with_issue_title: "${{ github.event.issue.title }}"
with_issue_body: "${{ github.event.issue.body }}"
with_label_name: "${{ env.LANG_LABEL }}"
with_github_token: "${{ github.token }}"
with_original_markdown_file_path: "${{ env.BACKUP_PATH }}"
with_task_fetch_to_save_path: "./articles/_raw/"
with_task_translate_openai_api_key: "${{ secrets.OPENAI_API_KEY }}"
with_task_translate_to_save_path: "./articles/{lang}/"
### Verify translation was created and commit
- name: Commit translated article
id: commit-translation
run: |
base="${{ env.SAFE_FILENAME }}"
lang="${{ env.LANG_CODE }}"
translated="./articles/$lang/$base"
echo "Checking for translated file: $translated"
if [ ! -f "$translated" ]; then
echo "::error::Translated file not found at: $translated"
echo "Listing articles directory contents:"
find ./articles -type f -name "*.md" | head -20
exit 1
fi
# Verify translation actually happened (file should differ from original)
original="./articles/_raw/$base"
if [ -f "$original" ]; then
if diff -q "$original" "$translated" > /dev/null 2>&1; then
echo "::warning::Translated file is identical to original - translation may have failed"
else
echo "Translation verified: files differ from original"
fi
fi
git add "$translated"
git commit -m "Add translated article ($lang): $base" || echo "Nothing to commit."
git fetch origin auto-translate || true
# Safe rebase, resolve conflicts
git stash push -u -m "Auto-stash before rebase" || true
if [ -f ".git/MERGE_HEAD" ]; then
echo "Unfinished merge detected. Aborting..."
git merge --abort || git reset --merge
fi
git pull --rebase origin auto-translate || true
git stash pop || true
# Use push retry function
eval "$PUSH_RETRY_SCRIPT"
push_with_retry auto-translate
### Clean up temp directory on main
- name: Cleanup temp directory
run: |
git checkout main
rm -rf ./articles/_tmp/
git add -u ./articles/_tmp/ || true
git commit -m "Cleanup _tmp directory" || echo "Nothing to commit."
git fetch origin main
git stash push -u -m "Auto-stash before rebase" || true
git pull --rebase origin main || true
git stash pop || true
# Use push retry function for final cleanup
eval "$PUSH_RETRY_SCRIPT"
push_with_retry main
### Add success comment
- name: Add success comment
if: success()
uses: actions/github-script@v7
with:
script: |
const langCode = '${{ env.LANG_CODE }}';
const filename = '${{ env.SAFE_FILENAME }}';
const message = `Auto-translation completed successfully!
**Files created:**
- Raw article: \`articles/_raw/${filename}\`
- Translated article (auto-translate branch): \`articles/${langCode}/${filename}\`
**Next steps:**
1. Contributors can proofread the translation on the \`auto-translate\` branch
2. Use \`/postedit\` command to claim this article for post-editing
3. When ready, create a PR from \`auto-translate\` to \`main\`
[View translated file](https://github.com/${{ github.repository }}/blob/auto-translate/articles/${langCode}/${filename})
[Edit in github.dev](https://github.dev/${{ github.repository }}/blob/auto-translate/articles/${langCode}/${filename})`;
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: message
});
### Add failure comment
- name: Add failure comment
if: failure()
uses: actions/github-script@v7
with:
script: |
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'Auto-translation workflow failed. Please check the [workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.'
});