Skip to content

docs: add CLI changelog entry for v0.136.0 (#1168) #143

docs: add CLI changelog entry for v0.136.0 (#1168)

docs: add CLI changelog entry for v0.136.0 (#1168) #143

Workflow file for this run

name: Sync Japanese Docs
on:
push:
branches:
- main
paths:
- 'docs/**/*.mdx'
- 'docs/**/*.md'
- '!docs/jp/**'
workflow_dispatch:
concurrency:
group: sync-jp-docs
cancel-in-progress: false
permissions:
contents: write
pull-requests: write
jobs:
sync-jp-docs:
runs-on: ubuntu-latest
timeout-minutes: 30
env:
DROID_VERSION: '0.108.0'
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Validate API key
env:
FACTORY_API_KEY: ${{ secrets.FACTORY_API_KEY }}
shell: bash
run: |
set -euo pipefail
[ -n "${FACTORY_API_KEY:-}" ] || { echo "FACTORY_API_KEY is missing"; exit 1; }
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
- name: Install pinned Droid CLI
shell: bash
run: |
set -euo pipefail
npm install -g "droid@${DROID_VERSION}"
NPM_GLOBAL_BIN="$(npm config get prefix)/bin"
echo "$NPM_GLOBAL_BIN" >> "$GITHUB_PATH"
"$NPM_GLOBAL_BIN/droid" --version
- name: Sync and translate changed English docs to Japanese
id: sync
env:
FACTORY_API_KEY: ${{ secrets.FACTORY_API_KEY }}
shell: bash
run: |
set -euo pipefail
BRANCH="docs/auto-sync-jp-docs"
TITLE="docs: sync and translate English doc changes to Japanese"
git fetch origin main
git fetch origin "$BRANCH" || true
BEFORE="${{ github.event.before }}"
if [ "$BEFORE" = "0000000000000000000000000000000000000000" ] || [ -z "$BEFORE" ]; then
BEFORE="$(git rev-parse HEAD~1 2>/dev/null || echo "")"
fi
if [ -z "$BEFORE" ]; then
echo "Cannot determine base commit, skipping."
{
echo "synced=false"
echo "reason=no_base_commit"
} >> "$GITHUB_OUTPUT"
exit 0
fi
if [ "${{ github.actor }}" = "github-actions[bot]" ]; then
echo "Skipping JP sync for github-actions[bot] push."
{
echo "synced=false"
echo "reason=bot_push"
} >> "$GITHUB_OUTPUT"
{
echo "## JP sync"
echo "- Skipped: push actor was github-actions[bot]."
} >> "$GITHUB_STEP_SUMMARY"
exit 0
fi
changed_entries_file="$(mktemp)"
git diff \
--name-status \
--find-renames \
--diff-filter=ACMR \
"$BEFORE" \
"${{ github.sha }}" \
-- 'docs/**/*.mdx' 'docs/**/*.md' ':!docs/jp/**' \
> "$changed_entries_file"
if [ ! -s "$changed_entries_file" ]; then
echo "No English doc changes detected."
{
echo "synced=false"
echo "reason=no_english_changes"
} >> "$GITHUB_OUTPUT"
exit 0
fi
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git checkout -B "$BRANCH" "origin/main"
if git show-ref --verify --quiet "refs/remotes/origin/$BRANCH"; then
mapfile -t existing_jp_files < <(git diff --name-only --diff-filter=ACMR origin/main...origin/"$BRANCH" -- docs/jp)
if [ "${#existing_jp_files[@]}" -gt 0 ]; then
git checkout "origin/$BRANCH" -- "${existing_jp_files[@]}"
fi
fi
manifest_file="$(mktemp)"
prompt_file="$(mktemp)"
snapshot_root="$(mktemp -d)"
cleanup() {
rm -f "$changed_entries_file" "$manifest_file" "$prompt_file"
rm -rf "$snapshot_root"
}
trap cleanup EXIT
jp_targets=0
while IFS=$'\t' read -r status first second; do
[ -n "$status" ] || continue
source_path="$first"
old_source_path=""
if [[ "$status" == R* ]]; then
old_source_path="$first"
source_path="$second"
fi
jp_file="${source_path/docs\//docs/jp/}"
snapshot_path="$snapshot_root/$source_path"
mkdir -p "$(dirname "$snapshot_path")"
mkdir -p "$(dirname "$jp_file")"
if [ -n "$old_source_path" ]; then
old_jp_file="${old_source_path/docs\//docs/jp/}"
if [ -e "$old_jp_file" ] && [ "$old_jp_file" != "$jp_file" ]; then
if [ -e "$jp_file" ]; then
rm -f "$old_jp_file"
else
mv "$old_jp_file" "$jp_file"
fi
fi
fi
git show "${{ github.sha }}:$source_path" > "$snapshot_path"
jp_targets=$((jp_targets + 1))
done < "$changed_entries_file"
if [ "$jp_targets" -eq 0 ]; then
echo "No Japanese docs targets were generated."
{
echo "synced=false"
echo "reason=no_jp_targets"
} >> "$GITHUB_OUTPUT"
exit 0
fi
BEFORE="$BEFORE" GITHUB_SHA="${{ github.sha }}" CHANGED_ENTRIES_FILE="$changed_entries_file" SNAPSHOT_ROOT="$snapshot_root" python3 - <<'PY' > "$manifest_file"
from pathlib import Path
import os
import subprocess
before = os.environ["BEFORE"]
sha = os.environ["GITHUB_SHA"]
changed_entries_file = Path(os.environ["CHANGED_ENTRIES_FILE"])
snapshot_root = Path(os.environ["SNAPSHOT_ROOT"])
changed_entries = [
line.strip().split("\t")
for line in changed_entries_file.read_text().splitlines()
if line.strip()
]
def run(*args: str) -> str:
return subprocess.run(args, check=True, capture_output=True, text=True).stdout
print("## Translation manifest")
print()
print("Use the English diffs below to scope edits, but read the full English source file and current Japanese target file before you edit.")
print()
for index, entry in enumerate(changed_entries, start=1):
status = entry[0]
old_source = None
if status.startswith("R"):
old_source = entry[1]
source = entry[2]
else:
source = entry[1]
snapshot_path = snapshot_root / source
target = source.replace("docs/", "docs/jp/", 1)
target_exists = Path(target).exists()
diff_paths = [source] if old_source is None else [old_source, source]
diff = run("git", "diff", "--find-renames", "--unified=2", before, sha, "--", *diff_paths).rstrip()
if not diff:
diff = "(No textual diff was produced; inspect the file pair directly before deciding no change is needed.)"
print(f"### {index}. `{source}`")
if old_source is not None:
print(f"- English path changed from `{old_source}`")
print(f"- English source snapshot: `{snapshot_path}`")
print(f"- Japanese target file: `{target}`")
print(f"- Existing Japanese target before this run: {'yes' if target_exists else 'no'}")
print("- Preferred edit scope: only the Japanese sections affected by the English diff below, unless the file is new or the diff forces a broader rewrite.")
print()
print("```diff")
print(diff)
print("```")
print()
PY
{
cat .github/prompts/sync-jp-docs.md
echo
cat "$manifest_file"
} > "$prompt_file"
droid exec \
--auto medium \
--model gpt-5.4 \
--reasoning-effort high \
--disabled-tools execute-cli \
--file "$prompt_file"
git add docs/jp/
if git diff --cached --quiet; then
echo "No Japanese docs changes to commit."
{
echo "synced=false"
echo "reason=no_jp_changes"
} >> "$GITHUB_OUTPUT"
exit 0
fi
changed_count="$(wc -l < "$changed_entries_file" | tr -d ' ')"
{
echo "## JP sync"
echo "- English docs changed: $changed_count"
echo "- Japanese targets requested: $jp_targets"
} >> "$GITHUB_STEP_SUMMARY"
{
echo "branch=$BRANCH"
echo "title=$TITLE"
echo "synced=true"
echo "reason=synced"
} >> "$GITHUB_OUTPUT"
- name: Upsert PR with synced docs
id: pr
if: steps.sync.outputs.synced == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
set -euo pipefail
BRANCH="${{ steps.sync.outputs.branch }}"
TITLE="${{ steps.sync.outputs.title }}"
BODY="Auto-generated by the sync-jp-docs Droid Exec workflow. This PR is reused for cumulative JP sync updates, so please review each commit for translation accuracy."
REPO_OWNER="${{ github.repository_owner }}"
find_open_pr_number() {
gh pr list \
--base main \
--head "$BRANCH" \
--state open \
--json number,isCrossRepository,headRepositoryOwner \
--jq ".[] | select((.isCrossRepository | not) and .headRepositoryOwner.login == \"$REPO_OWNER\") | .number" \
| head -n 1
}
find_reopenable_pr_number() {
gh pr list \
--base main \
--head "$BRANCH" \
--state closed \
--json number,isCrossRepository,headRepositoryOwner,mergedAt \
--jq ".[] | select((.isCrossRepository | not) and .headRepositoryOwner.login == \"$REPO_OWNER\" and (.mergedAt == null)) | .number" \
| head -n 1
}
git commit -m "$TITLE"
git push --force-with-lease origin "$BRANCH"
open_pr="$(find_open_pr_number)"
if [ -n "$open_pr" ] && [ "$open_pr" != "null" ]; then
gh pr edit "$open_pr" --title "$TITLE" --body "$BODY"
{
echo "pr_number=$open_pr"
echo "action=updated"
} >> "$GITHUB_OUTPUT"
exit 0
fi
closed_pr="$(find_reopenable_pr_number)"
if [ -n "$closed_pr" ] && [ "$closed_pr" != "null" ]; then
gh pr reopen "$closed_pr"
gh pr edit "$closed_pr" --title "$TITLE" --body "$BODY"
{
echo "pr_number=$closed_pr"
echo "action=reopened"
} >> "$GITHUB_OUTPUT"
exit 0
fi
gh pr create \
--base main \
--head "$BRANCH" \
--title "$TITLE" \
--body "$BODY"
created_pr="$(find_open_pr_number)"
{
echo "pr_number=$created_pr"
echo "action=created"
} >> "$GITHUB_OUTPUT"
- name: Summary
shell: bash
run: |
if [ "${{ steps.sync.outputs.synced }}" != "true" ]; then
reason="${{ steps.sync.outputs.reason }}"
echo "## JP sync" >> "$GITHUB_STEP_SUMMARY"
case "$reason" in
bot_push)
echo "ℹ️ Skipping JP sync for github-actions[bot] push"
echo "- Skipped: push actor was github-actions[bot]." >> "$GITHUB_STEP_SUMMARY"
;;
no_jp_changes)
echo "ℹ️ English docs changed, but no JP updates were needed"
echo "- English docs changed, but Droid produced no Japanese doc edits." >> "$GITHUB_STEP_SUMMARY"
;;
no_jp_targets)
echo "ℹ️ No JP targets were generated"
echo "- English docs changed, but no Japanese target files were derived." >> "$GITHUB_STEP_SUMMARY"
;;
no_base_commit)
echo "ℹ️ Could not determine base commit for JP sync"
echo "- Skipped: could not determine the base commit for diffing English docs." >> "$GITHUB_STEP_SUMMARY"
;;
*)
echo "ℹ️ No English doc changes to sync"
echo "- No English documentation changes required translation." >> "$GITHUB_STEP_SUMMARY"
;;
esac
exit 0
fi
{
echo "- PR action: ${{ steps.pr.outputs.action }}"
echo "- PR number: #${{ steps.pr.outputs.pr_number }}"
} >> "$GITHUB_STEP_SUMMARY"
echo "✅ Japanese docs sync PR ${{ steps.pr.outputs.action }} (#${{ steps.pr.outputs.pr_number }})"