From b56a9b960a2f020fb1cff5fba181e62b96d62536 Mon Sep 17 00:00:00 2001 From: Aolin Date: Tue, 26 May 2026 16:13:57 +0800 Subject: [PATCH] This is an automated cherry-pick of #22936 Signed-off-by: ti-chi-bot --- .github/workflows/ci.yaml | 51 +++ .github/workflows/doc_review.yml | 77 +++++ .../workflows/ja-full-translation-google.yaml | 97 ++++++ .github/workflows/link.yaml | 11 + .github/workflows/media.yml | 8 +- .github/workflows/prevent-deletion.yaml | 2 +- .github/workflows/rebase.yml | 4 + .github/workflows/sync-cloud-zh-toc.yml | 120 +++++++ .github/workflows/sync-doc-pr-zh-to-en.yml | 317 ++++++++++++++++++ .github/workflows/translation-cron.yml | 103 ++++++ .github/workflows/translation-zh-switch.yaml | 177 ++++++++++ .github/workflows/translation-zh.yaml | 244 ++++++++++++++ 12 files changed, 1208 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/doc_review.yml create mode 100644 .github/workflows/ja-full-translation-google.yaml create mode 100644 .github/workflows/sync-cloud-zh-toc.yml create mode 100644 .github/workflows/sync-doc-pr-zh-to-en.yml create mode 100644 .github/workflows/translation-cron.yml create mode 100644 .github/workflows/translation-zh-switch.yaml create mode 100644 .github/workflows/translation-zh.yaml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1a93b303192fd..edcba8ed207d9 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,10 +11,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out +<<<<<<< HEAD uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: "18" +======= + uses: actions/checkout@v6 +>>>>>>> 0f2e3b14b5 (ci: update actions (#22936)) - name: Verify duplicated file names run: ./scripts/verify-duplicated-file-name.sh - name: Verify internal links and anchors - tidb only @@ -32,6 +36,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out +<<<<<<< HEAD uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: @@ -52,12 +57,58 @@ jobs: cd ./tmp ./scripts/verify-links.sh ./scripts/verify-link-anchors.sh +======= + uses: actions/checkout@v6 + - uses: actions/setup-node@v6 + with: + node-version: "18" + cache: npm + cache-dependency-path: package-lock.json + - name: Install Node dependencies + run: npm ci + - name: Verify internal links (full repo) - files + run: ./scripts/verify-links.sh + + internal-links-anchors: + runs-on: ubuntu-latest + steps: + - name: Check out + uses: actions/checkout@v6 + - uses: actions/setup-node@v6 + with: + node-version: "18" + cache: npm + cache-dependency-path: package-lock.json + - name: Install Node dependencies + run: npm ci + - name: Verify internal links (full repo) - anchors + run: ./scripts/verify-link-anchors.sh + + internal-links-toc: + runs-on: ubuntu-latest + steps: + - name: Check out + uses: actions/checkout@v6 + - uses: actions/setup-node@v6 + with: + node-version: "18" + cache: npm + cache-dependency-path: package-lock.json + - name: Install Node dependencies + run: npm ci + - name: Verify internal links (full repo) - TOC membership + run: node ./scripts/verify-internal-links-in-toc.js +>>>>>>> 0f2e3b14b5 (ci: update actions (#22936)) vale: runs-on: ubuntu-latest steps: - name: Checkout +<<<<<<< HEAD uses: actions/checkout@v3 +======= + uses: actions/checkout@v6 +>>>>>>> 0f2e3b14b5 (ci: update actions (#22936)) - name: Vale Linter uses: errata-ai/vale-action@v2.0.1 with: diff --git a/.github/workflows/doc_review.yml b/.github/workflows/doc_review.yml new file mode 100644 index 0000000000000..3aafd670582e7 --- /dev/null +++ b/.github/workflows/doc_review.yml @@ -0,0 +1,77 @@ +name: AI Doc Review + +on: + workflow_dispatch: + + issue_comment: + types: + - created + +permissions: + contents: read + pull-requests: write + issues: write + +jobs: + review: + runs-on: ubuntu-latest + if: > + github.event_name == 'workflow_dispatch' || + ( + github.event_name == 'issue_comment' && + contains(github.event.comment.body, '/bot-review') && + (github.event.comment.user.login == 'hfxsd' || github.event.comment.user.login == 'likidu' || github.event.comment.user.login == 'lilin90' || github.event.comment.user.login == 'Oreoxmt' || github.event.comment.user.login == 'qiancai') + ) + steps: + - name: Checkout Repo + uses: actions/checkout@v6 + with: + fetch-depth: 0 # Fetch all history for all branches and tags + + - name: Extract review parameters + id: extract + if: github.event_name == 'issue_comment' + run: | + COMMENT="${{ github.event.comment.body }}" + + # Match commit range + if [[ "$COMMENT" =~ \/bot-review:[[:space:]]*([a-f0-9]{7,40})[[:space:]]*\.\.[[:space:]]*([a-f0-9]{7,40}) ]]; then + echo "BASE_SHA=${BASH_REMATCH[1]}" >> $GITHUB_OUTPUT + echo "HEAD_SHA=${BASH_REMATCH[2]}" >> $GITHUB_OUTPUT + echo "REVIEW_MODE=commit_range" >> $GITHUB_OUTPUT + printf "Detected commit range with regex: %s..%s\\n" "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" + + # Match a single commit + elif [[ "$COMMENT" =~ \/bot-review:[[:space:]]+([a-f0-9]{7,40}) ]]; then + echo "COMMIT_SHA=${BASH_REMATCH[1]}" >> $GITHUB_OUTPUT + echo "REVIEW_MODE=single_commit" >> $GITHUB_OUTPUT + printf "Detected single commit: %s\\n" "${BASH_REMATCH[1]}" + + # Match "/bot-review" or "/bot-review " + elif [[ "$COMMENT" =~ ^\/bot-review[[:space:]]*$ ]]; then + echo "REVIEW_MODE=latest" >> $GITHUB_OUTPUT + echo "Detected default review mode" + + # Invalid format + else + echo "REVIEW_MODE=invalid" >> $GITHUB_OUTPUT + echo "Invalid bot-review command format" + fi + + echo "Parameters output:" + cat $GITHUB_OUTPUT + + - name: AI Doc Reviewer + uses: qiancai/ai-doc-reviewer@main + continue-on-error: false # Ensure workflow fails if the action fails + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + API_PROVIDER: "openai" # or "openai" if you want to use OpenAI + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + OPENAI_API_MODEL: "gpt-4o" + exclude: "**/*.json" # Optional: exclude patterns separated by commas + REVIEW_MODE: ${{ steps.extract.outputs.REVIEW_MODE || 'default' }} + COMMIT_SHA: ${{ steps.extract.outputs.COMMIT_SHA || '' }} + BASE_SHA: ${{ steps.extract.outputs.BASE_SHA || '' }} + HEAD_SHA: ${{ steps.extract.outputs.HEAD_SHA || '' }} + PROMPT_PATH: "doc-review-prompt.txt" diff --git a/.github/workflows/ja-full-translation-google.yaml b/.github/workflows/ja-full-translation-google.yaml new file mode 100644 index 0000000000000..217c8dca89d06 --- /dev/null +++ b/.github/workflows/ja-full-translation-google.yaml @@ -0,0 +1,97 @@ +name: JA Full Translation (Google version) + +on: + workflow_dispatch: + inputs: + from: + description: "The EN source branch. e.g. release-8.5" + required: true + default: "release-8.5" + to: + description: "The JA target branch. e.g. i18n-ja-release-8.5" + required: true + default: "i18n-ja-release-8.5" + +jobs: + ja-translation: + if: github.repository == 'pingcap/docs' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + name: Download translator repo + with: + repository: "pingcap/docs-toolkit" + ref: "main" + path: "docs-toolkit" + - uses: actions/checkout@v6 + name: Download specified branch of docs repo + with: + ref: ${{ github.event.inputs.from }} + path: "docs" + - uses: actions/setup-node@v6 + name: Setup node + with: + node-version: 20 + + - run: | + sudo apt install tree -y + + - name: Copy doc files to translator folder + run: | + cp -r docs docs-toolkit/markdown-translator/markdowns + rm -rf docs-toolkit/markdown-translator/markdowns/.github + rm -rf docs-toolkit/markdown-translator/markdowns/scripts + rm -rf docs-toolkit/markdown-translator/markdowns/media + + - name: Config and translate + run: | + cd docs-toolkit/markdown-translator + echo ${{secrets.GCP_KEY}} | base64 --decode >> key.json + export GOOGLE_APPLICATION_CREDENTIALS=key.json + export PROJECT_ID=${{ secrets.GCP_PROJECT_ID }} + export GLOSSARY_ID=${{ secrets.GCP_GLOSSARY_ID }} + yarn + node src/index_ja.js + cd .. + - name: Copy translated files to docs repo + run: | + cd docs + git checkout -b ${{ github.event.inputs.to }} + cd .. + cp -r docs-toolkit/markdown-translator/output/markdowns/* docs/ + + - name: Update latest translation commit info + run: | + cd docs + SOURCE_SHA=$(git rev-parse origin/${{ github.event.inputs.from }}) + echo '{"target":"${{ github.event.inputs.from }}","sha":"'$SOURCE_SHA'"}' > latest_translation_commit.json + + - name: Git commit and push + run: | + cd docs + git config user.name github-actions + git config user.email github-actions@github.com + git add . + if git status | grep -q "Changes to be committed" + then + git commit -m "Update full translated files for JA" + else + echo "No changes detected, skipped" + fi + git push -f --set-upstream origin ${{ github.event.inputs.to }} + + dispatch: + if: github.repository == 'pingcap/docs' + runs-on: ubuntu-latest + needs: [ja-translation] + + steps: + - name: trigger docs-staging workflow + run: | + curl \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: token ${{ secrets.DOCS_STAGING }}" \ + https://api.github.com/repos/pingcap/docs-staging/actions/workflows/update.yml/dispatches \ + -d '{"ref":"main","inputs":{"full": "false", "repo":"${{ github.repository }}","branch":"${{ github.event.inputs.to }}"}}' diff --git a/.github/workflows/link.yaml b/.github/workflows/link.yaml index 4536d939fe79d..1aa024ca5f147 100644 --- a/.github/workflows/link.yaml +++ b/.github/workflows/link.yaml @@ -14,7 +14,18 @@ jobs: - name: Download Exclude Path run: | +<<<<<<< HEAD curl https://raw.githubusercontent.com/pingcap/docs/master/.lycheeignore --output .lycheeignore +======= + curl -fsSL https://raw.githubusercontent.com/pingcap/docs/master/.lycheeignore --output .lycheeignore + + - name: Restore lychee cache + uses: actions/cache@v5 + with: + path: .lycheecache + key: cache-lychee-${{ github.sha }} + restore-keys: cache-lychee- +>>>>>>> 0f2e3b14b5 (ci: update actions (#22936)) - name: Check Links uses: lycheeverse/lychee-action@v1.6.1 diff --git a/.github/workflows/media.yml b/.github/workflows/media.yml index 378650241a136..8256946845be4 100644 --- a/.github/workflows/media.yml +++ b/.github/workflows/media.yml @@ -11,7 +11,11 @@ jobs: name: Upload media files runs-on: ubuntu-latest steps: +<<<<<<< HEAD - uses: actions/checkout@v3 +======= + - uses: actions/checkout@v6 +>>>>>>> 0f2e3b14b5 (ci: update actions (#22936)) with: # Must use at least depth 2! fetch-depth: 2 @@ -60,10 +64,10 @@ jobs: TENCENTCLOUD_SECRET_KEY: ${{ secrets.TENCENTCLOUD_SECRET_KEY }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Python environment - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.12" architecture: "x64" diff --git a/.github/workflows/prevent-deletion.yaml b/.github/workflows/prevent-deletion.yaml index e1961dfc500a6..9d08804908a40 100644 --- a/.github/workflows/prevent-deletion.yaml +++ b/.github/workflows/prevent-deletion.yaml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout base - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 - name: Fetch head diff --git a/.github/workflows/rebase.yml b/.github/workflows/rebase.yml index 73cce3c0fa894..85c08f1147762 100644 --- a/.github/workflows/rebase.yml +++ b/.github/workflows/rebase.yml @@ -9,7 +9,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the latest code +<<<<<<< HEAD uses: actions/checkout@v3 +======= + uses: actions/checkout@v6 +>>>>>>> 0f2e3b14b5 (ci: update actions (#22936)) with: token: ${{ secrets.REBASE_SECRET_KEY }} fetch-depth: 0 # otherwise, you will fail to push refs to dest repo diff --git a/.github/workflows/sync-cloud-zh-toc.yml b/.github/workflows/sync-cloud-zh-toc.yml new file mode 100644 index 0000000000000..d30cd15069bdf --- /dev/null +++ b/.github/workflows/sync-cloud-zh-toc.yml @@ -0,0 +1,120 @@ +name: Sync Cloud ZH TOC Files + +on: + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +env: + EN_BRANCH: release-8.5 + ZH_BRANCH: i18n-zh-release-8.5 + +jobs: + sync-toc: + if: github.repository == 'pingcap/docs' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + name: Checkout ZH branch + with: + ref: "${{ env.ZH_BRANCH }}" + path: "docs" + token: ${{ github.token }} + + - name: Copy script from main branch (temporary) + run: | + mkdir -p temp_scripts + curl -H "Authorization: Bearer ${{ github.token }}" \ + -H "Accept: application/vnd.github.v3.raw" \ + -L "https://api.github.com/repos/${{ github.repository }}/contents/scripts/sync-en-cloud-toc-changes-to-zh.py" \ + -o temp_scripts/sync-en-cloud-toc-changes-to-zh.py + + - uses: actions/setup-python@v6 + name: Setup Python 3.11 + with: + python-version: '3.11' + + - name: Install Python dependencies + run: | + pip install "google-genai>=0.3,<1" + + - name: Configure Git + run: | + cd docs + git config user.name github-actions + git config user.email github-actions@github.com + + - name: Run TOC sync script + env: + GEMINI_API_TOKEN: ${{ secrets.GEMINI_API_TOKEN }} + GITHUB_TOKEN: ${{ github.token }} + run: | + cp temp_scripts/sync-en-cloud-toc-changes-to-zh.py docs/ + cd docs + python sync-en-cloud-toc-changes-to-zh.py + rm sync-en-cloud-toc-changes-to-zh.py # Remove the script file so it won't be included in PR + + - name: Clean up temporary files + run: | + rm -rf temp_scripts + + - name: Check for changes + id: check_changes + run: | + cd docs + if git diff --quiet; then + echo "changes=false" >> $GITHUB_OUTPUT + echo "No changes detected" + else + echo "changes=true" >> $GITHUB_OUTPUT + echo "Changes detected" + fi + + - name: Set build ID + id: build_id + if: steps.check_changes.outputs.changes == 'true' + run: echo "id=$(date +'%Y%m%d')-$(date +%s)" >> $GITHUB_OUTPUT + + - name: Create PR + if: steps.check_changes.outputs.changes == 'true' + uses: peter-evans/create-pull-request@v8 + with: + path: "docs" + token: ${{ github.token }} + branch: sync-zh-toc-${{ steps.build_id.outputs.id }} + base: ${{ env.ZH_BRANCH }} + title: "i18n-zh-release-8.5: sync ZH TOC changes ${{ steps.build_id.outputs.id }}" + body: | + ### What is changed, added or deleted? (Required) + + Sync Chinese Cloud TOC files based on English TOC updates from ${{ env.EN_BRANCH }} branch. + + ### Which TiDB version(s) do your changes apply to? (Required) + + + + **Tips for choosing the affected version(s):** + + By default, **CHOOSE MASTER ONLY** so your changes will be applied to the next TiDB major or minor releases. If your PR involves a product feature behavior change or a compatibility change, **CHOOSE THE AFFECTED RELEASE BRANCH(ES) AND MASTER**. + + For details, see [tips for choosing the affected versions](https://github.com/pingcap/docs/blob/master/CONTRIBUTING.md#guideline-for-choosing-the-affected-versions). + + - [x] ${{ env.ZH_BRANCH }} + + ### What is the related PR or file link(s)? + + + + - This PR syncs TOC changes from: ${{ env.EN_BRANCH }} + - Other reference link(s): + + ### Do your changes match any of the following descriptions? + + - [ ] Delete files + - [ ] Change aliases + - [ ] Need modification after applied to another branch + - [ ] Might cause conflicts after applied to another branch + delete-branch: true diff --git a/.github/workflows/sync-doc-pr-zh-to-en.yml b/.github/workflows/sync-doc-pr-zh-to-en.yml new file mode 100644 index 0000000000000..7c08d1391bc48 --- /dev/null +++ b/.github/workflows/sync-doc-pr-zh-to-en.yml @@ -0,0 +1,317 @@ +name: Sync Docs Changes from ZH PR to EN PR + +on: + workflow_dispatch: + inputs: + source_pr_url: + description: 'Source PR URL (Chinese docs repository)' + required: true + type: string + default: '' + target_pr_url: + description: 'Target PR URL (English docs repository)' + required: true + type: string + default: '' + ai_provider: + description: 'AI Provider to use for translation' + required: false + type: choice + options: + - deepseek + - gemini + - azure + default: 'azure' + +permissions: + contents: write + pull-requests: write + +jobs: + sync-docs: + runs-on: ubuntu-latest + if: contains(fromJson('["hfxsd","likidu","lilin90","Oreoxmt","qiancai"]'), github.actor) + + steps: + - name: Checkout current repository + uses: actions/checkout@v6 + with: + token: ${{ secrets.GITHUB_TOKEN }} + persist-credentials: false + fetch-depth: 0 + + - name: Checkout ai-pr-translator repository + uses: actions/checkout@v6 + with: + repository: "qiancai/ai-pr-translator" + ref: "main" + path: "ai-pr-translator" + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.9' + + - name: Install dependencies + run: pip install -r ai-pr-translator/scripts/requirements.txt + + - name: Extract PR information + id: extract_info + env: + SOURCE_URL: ${{ github.event.inputs.source_pr_url }} + TARGET_URL: ${{ github.event.inputs.target_pr_url }} + run: | + if [[ ! "$SOURCE_URL" =~ ^https://github\.com/[^/]+/[^/]+/pull/[0-9]+$ ]]; then + echo "❌ Invalid source PR URL format"; exit 1 + fi + if [[ ! "$TARGET_URL" =~ ^https://github\.com/[^/]+/[^/]+/pull/[0-9]+$ ]]; then + echo "❌ Invalid target PR URL format"; exit 1 + fi + + SOURCE_OWNER=$(echo "$SOURCE_URL" | cut -d'/' -f4) + SOURCE_REPO=$(echo "$SOURCE_URL" | cut -d'/' -f5) + SOURCE_PR=$(echo "$SOURCE_URL" | cut -d'/' -f7) + TARGET_OWNER=$(echo "$TARGET_URL" | cut -d'/' -f4) + TARGET_REPO=$(echo "$TARGET_URL" | cut -d'/' -f5) + TARGET_PR=$(echo "$TARGET_URL" | cut -d'/' -f7) + + if [[ "$SOURCE_OWNER/$SOURCE_REPO" != "pingcap/docs-cn" ]]; then + echo "❌ Unsupported source repository: only pingcap/docs-cn is supported"; exit 1 + fi + if [[ "$TARGET_OWNER/$TARGET_REPO" != "pingcap/docs" ]]; then + echo "❌ Unsupported target repository: only pingcap/docs is supported"; exit 1 + fi + + { + echo "source_owner<> $GITHUB_OUTPUT + + echo "Source: ${SOURCE_OWNER}/${SOURCE_REPO}#${SOURCE_PR}" + echo "Target: ${TARGET_OWNER}/${TARGET_REPO}#${TARGET_PR}" + + - name: Get target PR branch info + id: target_branch + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TARGET_OWNER: ${{ steps.extract_info.outputs.target_owner }} + TARGET_REPO: ${{ steps.extract_info.outputs.target_repo }} + TARGET_PR: ${{ steps.extract_info.outputs.target_pr }} + run: | + PR_INFO=$(gh api "repos/${TARGET_OWNER}/${TARGET_REPO}/pulls/${TARGET_PR}") + TARGET_BRANCH=$(echo "$PR_INFO" | jq -r '.head.ref') + HEAD_REPO=$(echo "$PR_INFO" | jq -r '.head.repo.full_name') + BASE_BRANCH=$(echo "$PR_INFO" | jq -r '.base.ref') + MAINTAINER_CAN_MODIFY=$(echo "$PR_INFO" | jq -r '.maintainer_can_modify // false') + + if [[ -z "$TARGET_BRANCH" || "$TARGET_BRANCH" == "null" || -z "$HEAD_REPO" || "$HEAD_REPO" == "null" || -z "$BASE_BRANCH" || "$BASE_BRANCH" == "null" ]]; then + echo "❌ Failed to extract target PR branch metadata from the GitHub API response." + exit 1 + fi + + echo "target_branch=${TARGET_BRANCH}" >> $GITHUB_OUTPUT + echo "head_repo=${HEAD_REPO}" >> $GITHUB_OUTPUT + echo "base_branch=${BASE_BRANCH}" >> $GITHUB_OUTPUT + echo "maintainer_can_modify=${MAINTAINER_CAN_MODIFY}" >> $GITHUB_OUTPUT + echo "Target branch: ${TARGET_BRANCH}, Head repo: ${HEAD_REPO}, Base branch: ${BASE_BRANCH}, Maintainer can modify: ${MAINTAINER_CAN_MODIFY}" + + - name: Verify target PR branch is pushable + env: + TARGET_OWNER: ${{ steps.extract_info.outputs.target_owner }} + TARGET_REPO: ${{ steps.extract_info.outputs.target_repo }} + HEAD_REPO: ${{ steps.target_branch.outputs.head_repo }} + MAINTAINER_CAN_MODIFY: ${{ steps.target_branch.outputs.maintainer_can_modify }} + run: | + if [[ "$HEAD_REPO" != "${TARGET_OWNER}/${TARGET_REPO}" && "$MAINTAINER_CAN_MODIFY" != "true" ]]; then + echo "Fork PR head repo ${HEAD_REPO} does not allow maintainer edits, so translated changes cannot be pushed back automatically." + exit 1 + fi + + echo "Push preflight passed for ${HEAD_REPO}." + + - name: Clone target repository + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + HEAD_REPO: ${{ steps.target_branch.outputs.head_repo }} + TARGET_BRANCH: ${{ steps.target_branch.outputs.target_branch }} + run: | + ASKPASS_SCRIPT="$RUNNER_TEMP/git-askpass-clone.sh" + cat >"$ASKPASS_SCRIPT" <<'EOF' + #!/bin/sh + case "$1" in + *Username*) printf '%s\n' "x-access-token" ;; + *Password*) printf '%s\n' "$GITHUB_TOKEN" ;; + *) printf '\n' ;; + esac + EOF + chmod 700 "$ASKPASS_SCRIPT" + export GIT_ASKPASS="$ASKPASS_SCRIPT" + export GIT_TERMINAL_PROMPT=0 + trap 'rm -f "$ASKPASS_SCRIPT"' EXIT + + git clone "https://github.com/${HEAD_REPO}.git" target_repo + cd target_repo && git checkout "$TARGET_BRANCH" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Run sync script + id: sync_script + continue-on-error: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DEEPSEEK_API_TOKEN: ${{ secrets.DEEPSEEK_API_TOKEN }} + GEMINI_API_TOKEN: ${{ secrets.GEMINI_API_TOKEN }} + AZURE_OPENAI_KEY: ${{ secrets.AZURE_OPENAI_KEY }} + OPENAI_BASE_URL: ${{ secrets.AZURE_OPENAI_BASE_URL }} + SOURCE_PR_URL: ${{ github.event.inputs.source_pr_url }} + TARGET_PR_URL: ${{ github.event.inputs.target_pr_url }} + AI_PROVIDER: ${{ github.event.inputs.ai_provider }} + TARGET_REPO_PATH: ${{ github.workspace }}/target_repo + TERMS_PATH: ${{ github.workspace }}/target_repo/resources/terms.md + run: | + cd ai-pr-translator/scripts + if python main_workflow.py; then + echo "sync_success=true" >> $GITHUB_OUTPUT + echo "✅ Sync script completed successfully" + else + echo "sync_success=false" >> $GITHUB_OUTPUT + echo "❌ Sync script failed" + exit 1 + fi + + - name: Commit and push changes + id: commit_push + if: steps.sync_script.outputs.sync_success == 'true' + continue-on-error: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SOURCE_PR_URL: ${{ github.event.inputs.source_pr_url }} + TARGET_PR_URL: ${{ github.event.inputs.target_pr_url }} + AI_PROVIDER: ${{ github.event.inputs.ai_provider }} + TARGET_BRANCH: ${{ steps.target_branch.outputs.target_branch }} + TARGET_BASE_BRANCH: ${{ steps.target_branch.outputs.base_branch }} + run: | + ASKPASS_SCRIPT="$RUNNER_TEMP/git-askpass-push.sh" + cat >"$ASKPASS_SCRIPT" <<'EOF' + #!/bin/sh + case "$1" in + *Username*) printf '%s\n' "x-access-token" ;; + *Password*) printf '%s\n' "$GITHUB_TOKEN" ;; + *) printf '\n' ;; + esac + EOF + chmod 700 "$ASKPASS_SCRIPT" + export GIT_ASKPASS="$ASKPASS_SCRIPT" + export GIT_TERMINAL_PROMPT=0 + trap 'rm -f "$ASKPASS_SCRIPT"' EXIT + + cd target_repo && git add . + if git diff --staged --quiet; then + echo "push_success=false" >> $GITHUB_OUTPUT + echo "No translated changes were generated, so nothing was pushed." + exit 1 + fi + + REWRITE_PLACEHOLDER_COMMITS=false + BASE_REF="origin/${TARGET_BASE_BRANCH}" + + if git rev-parse --verify "$BASE_REF" >/dev/null 2>&1; then + if MERGE_BASE=$(git merge-base HEAD "$BASE_REF"); then + readarray -t BRANCH_COMMITS < <(git rev-list --reverse "${MERGE_BASE}..HEAD") + + if [[ ${#BRANCH_COMMITS[@]} -eq 2 ]]; then + FIRST_MSG=$(git log -1 --format=%s "${BRANCH_COMMITS[0]}") + SECOND_MSG=$(git log -1 --format=%s "${BRANCH_COMMITS[1]}") + + if [[ "$FIRST_MSG" == "Add temp.md" && "$SECOND_MSG" == "Delete temp.md" ]]; then + echo "Detected placeholder commits. Resetting branch to ${MERGE_BASE} before creating the first real sync commit." + git reset --soft "${MERGE_BASE}" + REWRITE_PLACEHOLDER_COMMITS=true + fi + fi + else + echo "Failed to find a merge-base with ${BASE_REF}. Skipping placeholder cleanup." + fi + else + echo "Base ref ${BASE_REF} not found in cloned fork. Skipping placeholder cleanup." + fi + + if ! printf "Auto-sync: Update English docs from Chinese PR\n\nSynced from: %s\nTarget PR: %s\nAI Provider: %s\n\nCo-authored-by: github-actions[bot] " \ + "$SOURCE_PR_URL" "$TARGET_PR_URL" "$AI_PROVIDER" | git commit -F -; then + echo "push_success=false" >> $GITHUB_OUTPUT + echo "Failed to create a commit for the translated changes." + exit 1 + fi + + if [[ "$REWRITE_PLACEHOLDER_COMMITS" == "true" ]]; then + if git push --force-with-lease origin "$TARGET_BRANCH"; then + echo "push_success=true" >> $GITHUB_OUTPUT + else + echo "push_success=false" >> $GITHUB_OUTPUT + echo "Failed to force-push translated changes to $TARGET_BRANCH." + exit 1 + fi + else + if git push origin "$TARGET_BRANCH"; then + echo "push_success=true" >> $GITHUB_OUTPUT + else + echo "push_success=false" >> $GITHUB_OUTPUT + echo "Failed to push translated changes to $TARGET_BRANCH." + exit 1 + fi + fi + + echo "Changes pushed to $TARGET_BRANCH" + + - name: Add success comment to target PR + if: steps.commit_push.outputs.push_success == 'true' + continue-on-error: true + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SOURCE_PR_URL: ${{ github.event.inputs.source_pr_url }} + TARGET_PR_URL: ${{ github.event.inputs.target_pr_url }} + TARGET_OWNER: ${{ steps.extract_info.outputs.target_owner }} + TARGET_REPO: ${{ steps.extract_info.outputs.target_repo }} + TARGET_PR: ${{ steps.extract_info.outputs.target_pr }} + run: | + BODY=$(printf '%s\n\n%s\n%s\n\n%s' \ + "**Auto-sync completed successfully**" \ + "**Source PR**: ${SOURCE_PR_URL}" \ + "**Target PR**: ${TARGET_PR_URL}" \ + "English documentation has been updated based on Chinese documentation changes.") + PAYLOAD=$(jq -n --arg body "$BODY" '{body: $body}') + printf '%s' "$PAYLOAD" | gh api --method POST \ + "repos/${TARGET_OWNER}/${TARGET_REPO}/issues/${TARGET_PR}/comments" \ + --input - + + - name: Add failure comment to target PR + if: always() && steps.extract_info.outputs.target_owner != '' && steps.commit_push.outputs.push_success != 'true' + continue-on-error: true + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SOURCE_PR_URL: ${{ github.event.inputs.source_pr_url }} + TARGET_PR_URL: ${{ github.event.inputs.target_pr_url }} + TARGET_OWNER: ${{ steps.extract_info.outputs.target_owner }} + TARGET_REPO: ${{ steps.extract_info.outputs.target_repo }} + TARGET_PR: ${{ steps.extract_info.outputs.target_pr }} + run: | + BODY=$(printf '%s\n\n%s\n%s\n\n%s' \ + "**Auto-sync failed**" \ + "**Source PR**: ${SOURCE_PR_URL}" \ + "**Target PR**: ${TARGET_PR_URL}" \ + "Translated changes were not pushed to the target branch. Please check the workflow logs for details.") + PAYLOAD=$(jq -n --arg body "$BODY" '{body: $body}') + printf '%s' "$PAYLOAD" | gh api --method POST \ + "repos/${TARGET_OWNER}/${TARGET_REPO}/issues/${TARGET_PR}/comments" \ + --input - + + - name: Fail workflow if translated changes were not pushed + if: always() && steps.commit_push.outputs.push_success != 'true' + run: | + echo "Workflow failed because translated changes were not pushed to the target branch." + exit 1 diff --git a/.github/workflows/translation-cron.yml b/.github/workflows/translation-cron.yml new file mode 100644 index 0000000000000..20af70295edb4 --- /dev/null +++ b/.github/workflows/translation-cron.yml @@ -0,0 +1,103 @@ +name: Translation Cron JA + +on: + schedule: + # Runs JA translation at 19:00 every Wednesday (Beijing time, UTC+8) + - cron: "0 11 * * 3" + workflow_dispatch: + inputs: + file_names: + description: 'Specify file names to translate (comma-separated list)' + required: false + type: string + default: '' + +env: + LTS_BRANCH: i18n-ja-release-8.5 + CLOUD_BRANCH: i18n-ja-release-8.5 + +jobs: + # Build a matrix of JA branches to translate, including LTS and Cloud. + build-matrix: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - id: set-matrix + run: echo "matrix={\"include\":[{\"name\":\"LTS\",\"value\":\"${{ env.LTS_BRANCH }}\"},{\"name\":\"Cloud\",\"value\":\"${{ env.CLOUD_BRANCH }}\"}]}" >> $GITHUB_OUTPUT + + translate-ja: + if: github.repository == 'pingcap/docs' + needs: build-matrix + runs-on: ubuntu-latest + strategy: + matrix: ${{ fromJson(needs.build-matrix.outputs.matrix) }} + continue-on-error: true + + steps: + # skip the duplicate matrix job once if the LTS and Cloud branches are the same + - name: Skip duplicate branch + if: ${{ matrix.name == 'LTS' && env.LTS_BRANCH == env.CLOUD_BRANCH }} + run: | + echo "Skipping duplicate branch ${{ matrix.value }}" + exit 1 + + - uses: actions/checkout@v6 + name: Download translator repo + with: + repository: "pingcap/docs-toolkit" + ref: "main" + path: "docs-toolkit" + - uses: actions/checkout@v6 + name: Download docs repo and specified branch + with: + ref: "${{ matrix.value }}" + path: "docs" + - uses: actions/setup-node@v6 + name: Setup node + with: + node-version: 20 + + - run: | + sudo apt install tree -y + + - name: Download files by comparing commits + uses: pingcap/docs-toolkit/actions/file-diff-update@main + with: + config_file: latest_translation_commit.json + working_directory: docs + files: ${{ inputs.file_names || '' }} + + - name: Show tmp directory structure + run: | + cd docs + tree tmp || find tmp -type f | head -20 + - name: Config and translate + run: | + cd docs-toolkit/markdown-translator + yarn + cd ../.. + echo ${{secrets.GCP_KEY}} | base64 --decode >> key.json + export GOOGLE_APPLICATION_CREDENTIALS=key.json + export PROJECT_ID=${{ secrets.GCP_PROJECT_ID }} + export GLOSSARY_ID=${{ secrets.GCP_GLOSSARY_ID }} + node docs-toolkit/markdown-translator/src/index_ja.js --input-dir docs/tmp --output-dir docs/ + + - name: Git commit and push + run: | + cd docs + git status + git config user.name github-actions + git config user.email github-actions@github.com + git add . + git commit -m "update translated files" + git push + + - name: trigger docs-staging workflow + run: | + curl \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: token ${{ secrets.DOCS_STAGING }}" \ + https://api.github.com/repos/pingcap/docs-staging/actions/workflows/update.yml/dispatches \ + -d '{"ref":"main","inputs":{"full": "false", "repo":"${{ github.repository }}","branch":"${{ matrix.value }}"}}' diff --git a/.github/workflows/translation-zh-switch.yaml b/.github/workflows/translation-zh-switch.yaml new file mode 100644 index 0000000000000..1518c6fcd4699 --- /dev/null +++ b/.github/workflows/translation-zh-switch.yaml @@ -0,0 +1,177 @@ +name: ZH cloud translation switch + +on: + workflow_dispatch: + inputs: + from: + description: "The last zh source branch. e.g. i18n-zh-release-8.1" + required: true + to: + description: "The target zh source branch. e.g. i18n-zh-release-8.5" + required: true + to_base: + description: "The base branch. e.g. release-8.5" + required: true + +jobs: + zh-translation: + if: github.repository == 'pingcap/docs' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + name: Download translator repo + with: + repository: "pingcap/docs-toolkit" + ref: "main" + path: "docs-toolkit" + + - uses: actions/checkout@v6 + name: Checkout from branch and create target branch + with: + ref: "${{ github.event.inputs.from }}" + path: "docs" + + - name: Create target branch + run: | + cd docs + git checkout -b "${{ github.event.inputs.to }}" + git push origin "${{ github.event.inputs.to }}" + cd .. + + - name: Force merge to_base branch excluding tidb-cloud folder + run: | + cd docs + git config user.name github-actions + git config user.email github-actions@github.com + + # Fetch the to_base branch + git fetch origin "${{ github.event.inputs.to_base }}" + + # Simple and reliable approach: merge everything first, then restore tidb-cloud + + # Store the current target branch state before merge + TARGET_BRANCH_HEAD=$(git rev-parse HEAD) + + # Create a temporary branch from to_base + git checkout -b temp-merge-branch "origin/${{ github.event.inputs.to_base }}" + + # Switch back to target branch + git checkout "${{ github.event.inputs.to }}" + + # Merge the temporary branch with allow-unrelated-histories + git merge temp-merge-branch --no-edit --allow-unrelated-histories -X theirs + + # After merge, restore tidb-cloud folder from the original target branch state + # Use the stored commit hash to restore the original tidb-cloud folder + git checkout $TARGET_BRANCH_HEAD -- tidb-cloud/ || true + + # If there are any conflicts in tidb-cloud, resolve them by keeping the target branch version + git add tidb-cloud/ || true + + # Clean up temporary branch + git branch -D temp-merge-branch + + # Get the latest filterCloudInitFiles.js from master branch + git fetch origin master + git checkout origin/master -- scripts/filterCloudInitFiles.js || true + + # Push the changes + git push origin "${{ github.event.inputs.to }}" + cd .. + + - name: Update latest_translation_commit.json + run: | + cd docs + # Get the latest commit SHA from to_base branch + TO_BASE_SHA=$(git rev-parse origin/${{ github.event.inputs.to_base }}) + echo '{"target":"${{ github.event.inputs.to_base }}","sha":"'$TO_BASE_SHA'"}' > latest_translation_commit.json + git config user.name github-actions + git config user.email github-actions@github.com + git add latest_translation_commit.json + git commit -m "ci: update latest_translation_commit.json for ${{ github.event.inputs.to_base }}" + git push origin "${{ github.event.inputs.to }}" + cd .. + + - uses: actions/setup-node@v6 + name: Setup node + with: + node-version: 20 + + - run: | + sudo apt install tree -y + + - name: Download files by comparing commits + run: | + export GH_TOKEN=${{github.token}} + cd docs + npm i + node scripts/filterCloudInitFiles.js + tree tmp + cd .. + + - name: Copy new files to translator folder + run: | + cp -r docs/tmp docs-toolkit/markdown-translator/markdowns + + - name: Copy variables.json to translator folder + run: | + cp docs/tmp/variables.json docs/variables.json || true + + - name: Config and translate + run: | + cd docs-toolkit/markdown-translator + export LANGLINK_ACCESS_KEY=${{ secrets.LANGLINK_ACCESS_KEY }} + export LANGLINK_ACCESS_SECRET=${{ secrets.LANGLINK_ACCESS_SECRET }} + export LANGLINK_USER=${{ secrets.LANGLINK_USER }} + yarn + node src/index.js + cd .. + + - name: Copy translated files to docs repo + run: | + cp -r docs-toolkit/markdown-translator/output/markdowns/* docs/ + + - name: Set build ID + id: build_id + run: echo "::set-output name=id::$(date +%s)" + + - name: Create PR + uses: peter-evans/create-pull-request@v8 + with: + path: "docs" + token: ${{ github.token }} + branch: zh-translation/${{ steps.build_id.outputs.id }} + base: "${{ github.event.inputs.to }}" + title: "ci: ZH translation ${{ steps.build_id.outputs.id }}" + body: | + ### What is changed, added or deleted? (Required) + + Translate docs to Chinese. + + ### Which TiDB version(s) do your changes apply to? (Required) + + + + **Tips for choosing the affected version(s):** + + By default, **CHOOSE MASTER ONLY** so your changes will be applied to the next TiDB major or minor releases. If your PR involves a product feature behavior change or a compatibility change, **CHOOSE THE AFFECTED RELEASE BRANCH(ES) AND MASTER**. + + For details, see [tips for choosing the affected versions](https://github.com/pingcap/docs/blob/master/CONTRIBUTING.md#guideline-for-choosing-the-affected-versions). + + - [x] ${{ github.event.inputs.to }} + + ### What is the related PR or file link(s)? + + + + - This PR is translated from: en + - Other reference link(s): + + ### Do your changes match any of the following descriptions? + + - [ ] Delete files + - [ ] Change aliases + - [ ] Need modification after applied to another branch + - [ ] Might cause conflicts after applied to another branch + delete-branch: true diff --git a/.github/workflows/translation-zh.yaml b/.github/workflows/translation-zh.yaml new file mode 100644 index 0000000000000..b2014fb252cfd --- /dev/null +++ b/.github/workflows/translation-zh.yaml @@ -0,0 +1,244 @@ +name: Sync TiDB Cloud Docs from EN to ZH + +concurrency: + group: translation-zh-cloud-${{ github.event_name }} + cancel-in-progress: true + +on: + schedule: + - cron: "0 9 * * 3" # Runs at 17:00 every Wednesday (Beijing time, UTC+8) + workflow_dispatch: + inputs: + file_names: + description: "Specify Cloud files to translate (comma-separated list)" + required: true + type: string + source_files_translation_mode: + description: "Translate specified files incrementally or as full files" + required: true + type: choice + default: incremental + options: + - incremental + - full + +env: + SOURCE_REPO: pingcap/docs + SOURCE_BRANCH: release-8.5 + CN_CLOUD_BRANCH: i18n-zh-release-8.5 + CLOUD_TOC_FILES: TOC-tidb-cloud.md,TOC-tidb-cloud-starter.md,TOC-tidb-cloud-essential.md,TOC-tidb-cloud-premium.md,TOC-tidb-cloud-releases.md + CLOUD_INDEX_FILES: tidb-cloud/dedicated/_index.md,tidb-cloud/essential/_index.md,tidb-cloud/premium/_index.md,tidb-cloud/releases/_index.md,tidb-cloud/starter/_index.md + AI_TRANSLATOR_REPO: qiancai/ai-pr-translator + AI_TRANSLATOR_REF: main + +jobs: + translate: + if: github.repository == 'pingcap/docs' + runs-on: ubuntu-latest + + permissions: + contents: write + pull-requests: write + + steps: + - uses: actions/checkout@v6 + name: Checkout docs target branch + with: + ref: ${{ env.CN_CLOUD_BRANCH }} + path: docs + + - uses: actions/checkout@v6 + name: Checkout docs source branch + with: + repository: ${{ env.SOURCE_REPO }} + ref: ${{ env.SOURCE_BRANCH }} + path: docs-source + fetch-depth: 0 + persist-credentials: false + + - uses: actions/checkout@v6 + name: Checkout ai-pr-translator + with: + repository: ${{ env.AI_TRANSLATOR_REPO }} + ref: ${{ env.AI_TRANSLATOR_REF }} + path: ai-pr-translator + persist-credentials: false + + - uses: actions/setup-python@v6 + name: Setup Python + with: + python-version: "3.9" + cache: pip + cache-dependency-path: ai-pr-translator/scripts/requirements.txt + + - name: Install Python dependencies + shell: bash + run: | + set -euo pipefail + python -m pip install --upgrade pip + pip install -r ai-pr-translator/scripts/requirements.txt + + - name: Resolve commit range + id: commits + shell: bash + working-directory: docs + run: | + set -euo pipefail + + readarray -t cursor_values < <(python - <<'PY' + import json + from pathlib import Path + + data = json.loads(Path("latest_translation_commit.json").read_text(encoding="utf-8")) + print((data.get("target") or "").strip()) + print((data.get("sha") or "").strip()) + PY + ) + + cursor_target="${cursor_values[0]:-}" + base_ref="${cursor_values[1]:-}" + head_ref="$(git -C "${GITHUB_WORKSPACE}/docs-source" rev-parse HEAD)" + + if [ -z "${base_ref}" ]; then + echo "latest_translation_commit.json does not contain a source sha" >&2 + exit 1 + fi + + if [ -n "${cursor_target}" ] && [ "${cursor_target}" != "${SOURCE_BRANCH}" ]; then + echo "latest_translation_commit.json target is ${cursor_target}, expected ${SOURCE_BRANCH}" >&2 + exit 1 + fi + + echo "base_ref=${base_ref}" >> "${GITHUB_OUTPUT}" + echo "head_ref=${head_ref}" >> "${GITHUB_OUTPUT}" + + - name: Resolve Cloud source file filter + id: source_files + shell: bash + env: + INPUT_FILE_NAMES: ${{ inputs.file_names || '' }} + BASE_REF: ${{ steps.commits.outputs.base_ref }} + HEAD_REF: ${{ steps.commits.outputs.head_ref }} + DOCS_SOURCE_PATH: ${{ github.workspace }}/docs-source + CLOUD_TOC_FILES: ${{ env.CLOUD_TOC_FILES }} + CLOUD_INDEX_FILES: ${{ env.CLOUD_INDEX_FILES }} + run: | + set -euo pipefail + python ai-pr-translator/scripts/resolve_cloud_source_files.py + + - name: Run commit sync workflow + id: sync + if: steps.source_files.outputs.has_source_changes == 'true' + continue-on-error: true + shell: bash + env: + GITHUB_TOKEN: ${{ github.token }} + AZURE_OPENAI_KEY: ${{ secrets.AZURE_OPENAI_KEY }} + OPENAI_BASE_URL: ${{ secrets.AZURE_OPENAI_BASE_URL }} + SOURCE_REPO: ${{ env.SOURCE_REPO }} + TARGET_REPO: ${{ env.SOURCE_REPO }} + SOURCE_BRANCH: ${{ env.SOURCE_BRANCH }} + SOURCE_BASE_REF: ${{ steps.commits.outputs.base_ref }} + SOURCE_HEAD_REF: ${{ steps.commits.outputs.head_ref }} + SOURCE_FOLDER: "" + SOURCE_FILES: ${{ steps.source_files.outputs.files }} + SOURCE_FILES_TRANSLATION_MODE: ${{ inputs.source_files_translation_mode || 'incremental' }} + IGNORE_RESOURCE_CARD_SECTION: "Yes" + SOURCE_REPO_PATH: ${{ github.workspace }}/docs-source + TARGET_REF: ${{ env.CN_CLOUD_BRANCH }} + PREFER_LOCAL_TARGET_FOR_READ: "true" + TARGET_REPO_PATH: ${{ github.workspace }}/docs + AI_PROVIDER: azure + TERMS_PATH: ${{ github.workspace }}/docs-source/resources/terms.md + FAIL_ON_TRANSLATION_ERROR: "true" + SKIP_TRANSLATING_CLOUD_DOCS_TO_ZH: "false" + SKIP_TRANSLATING_AI_DOCS_TO_ZH: "true" + run: | + set -euo pipefail + cd ai-pr-translator/scripts + python commit_sync_workflow.py + + - name: Prepare translated changes + id: changes + if: always() && steps.source_files.outputs.has_source_changes == 'true' + shell: bash + working-directory: docs + env: + HEAD_REF: ${{ steps.commits.outputs.head_ref }} + SOURCE_BRANCH: ${{ env.SOURCE_BRANCH }} + FAILURE_REPORT: ${{ github.workspace }}/ai-pr-translator/scripts/temp_output/translation-failures.md + run: | + set -euo pipefail + + if [ -s "${FAILURE_REPORT}" ]; then + { + echo "failure_summary< Before merging this PR, manually translate the failed files above or rerun this workflow with workflow_dispatch and file_names set to those paths." + echo "EOF" + } >> "${GITHUB_OUTPUT}" + fi + + if [ -z "$(git status --porcelain)" ]; then + echo "has_changes=false" >> "${GITHUB_OUTPUT}" + exit 0 + fi + + if [ "${GITHUB_EVENT_NAME}" = "schedule" ]; then + python -c 'import json, os; from pathlib import Path; Path("latest_translation_commit.json").write_text(json.dumps({"target": os.environ["SOURCE_BRANCH"], "sha": os.environ["HEAD_REF"]}, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")' + else + echo "Skipping latest_translation_commit.json update for ${GITHUB_EVENT_NAME} run." + fi + + echo "has_changes=true" >> "${GITHUB_OUTPUT}" + + - name: Set build metadata + id: build_meta + if: steps.changes.outputs.has_changes == 'true' + shell: bash + run: | + echo "date=$(TZ=Asia/Shanghai date +'%Y-%m-%d')" >> "${GITHUB_OUTPUT}" + echo "id=$(TZ=Asia/Shanghai date +'%Y%m%d')-$(date +%s)" >> "${GITHUB_OUTPUT}" + + - name: Create PR + if: steps.changes.outputs.has_changes == 'true' + uses: peter-evans/create-pull-request@v8 + with: + path: docs + token: ${{ github.token }} + branch: zh-translation/cloud-${{ steps.build_meta.outputs.id }} + base: ${{ env.CN_CLOUD_BRANCH }} + title: "${{ env.CN_CLOUD_BRANCH }}: translate Cloud doc changes from ${{ env.SOURCE_REPO }} ${{ env.SOURCE_BRANCH }} on ${{ steps.build_meta.outputs.date }}" + labels: | + translation/no-need + body: | + ### What is changed, added or deleted? (Required) + + Translate Cloud documentation changes from `pingcap/docs` `${{ env.SOURCE_BRANCH }}` to Chinese via `ai-pr-translator` commit-diff sync. + + English commit diff: + + https://github.com/${{ env.SOURCE_REPO }}/compare/${{ steps.commits.outputs.base_ref }}...${{ steps.commits.outputs.head_ref }} + + ### Which TiDB version(s) do your changes apply to? (Required) + + - [x] ${{ env.CN_CLOUD_BRANCH }} + + ### What is the related PR or file link(s)? + + - Source repo: `${{ env.SOURCE_REPO }}` + - Source branch: `${{ env.SOURCE_BRANCH }}` + - Cloud TOCs: `${{ env.CLOUD_TOC_FILES }}` + - Source files: `${{ steps.source_files.outputs.files }}` + - Sync outcome: `${{ steps.sync.outcome }}` + + ${{ steps.changes.outputs.failure_summary }} + + ### Do your changes match any of the following descriptions? + + - [ ] Delete files + - [ ] Change aliases + - [ ] Need modification after applied to another branch + - [ ] Might cause conflicts after applied to another branch + delete-branch: true