mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-15 10:56:13 +00:00
* chore(models): migrate active GPT-5.5 references * test(workboard): expect GPT-5.6 Sol default * chore: keep release notes in PR body * test(models): align picker fixtures with Sol default * test: update PDF default model expectation * test(qa): migrate thinking smoke to Luna * test(gateway): align mock catalog with Sol default * ci: retrigger exact-head PR checks * test(gateway): document default catalog invariant
313 lines
11 KiB
YAML
313 lines
11 KiB
YAML
name: Native App Locale Refresh
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
paths:
|
|
- apps/android/app/src/main/**
|
|
- apps/ios/**
|
|
- apps/macos/Sources/**
|
|
- apps/macos/Package.swift
|
|
- apps/shared/OpenClawKit/Sources/**
|
|
- apps/.i18n/native/**
|
|
- apps/.i18n/native-source.json
|
|
- scripts/control-ui-i18n.ts
|
|
- scripts/native-app-i18n.ts
|
|
- ui/src/i18n/.i18n/glossary.*.json
|
|
- .github/actions/create-generated-pr-tokens/action.yml
|
|
- .github/actions/publish-generated-pr/action.yml
|
|
- .github/workflows/native-app-locale-refresh.yml
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
concurrency:
|
|
group: native-app-locale-refresh
|
|
# Finish the active full refresh; GitHub retains only the newest pending run for this group.
|
|
# Publisher overlap checks defer stale generated paths to that queued reconciliation run.
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
resolve-base:
|
|
if: >-
|
|
github.repository == 'openclaw/openclaw' &&
|
|
(github.event_name != 'workflow_dispatch' || github.ref == 'refs/heads/main')
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
sha: ${{ steps.base.outputs.sha }}
|
|
steps:
|
|
- name: Resolve default branch head
|
|
id: base
|
|
env:
|
|
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
|
|
GH_TOKEN: ${{ github.token }}
|
|
REPOSITORY: ${{ github.repository }}
|
|
run: |
|
|
set -euo pipefail
|
|
sha="$(
|
|
timeout --signal=TERM --kill-after=10s 60s \
|
|
gh api --method GET "repos/${REPOSITORY}/commits/${DEFAULT_BRANCH}" --jq .sha
|
|
)"
|
|
if [[ ! "${sha}" =~ ^[0-9a-f]{40}$ ]]; then
|
|
echo "Unable to resolve ${DEFAULT_BRANCH} to an exact commit." >&2
|
|
exit 1
|
|
fi
|
|
echo "sha=${sha}" >> "${GITHUB_OUTPUT}"
|
|
|
|
publisher-preflight:
|
|
name: Verify generated PR App permissions
|
|
needs: resolve-base
|
|
if: needs.resolve-base.result == 'success'
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
with:
|
|
ref: ${{ needs.resolve-base.outputs.sha }}
|
|
persist-credentials: false
|
|
submodules: false
|
|
|
|
- name: Create generated PR tokens
|
|
uses: ./.github/actions/create-generated-pr-tokens
|
|
with:
|
|
contents-client-id: Iv23liOECG0slfuhz093
|
|
contents-private-key: ${{ secrets.CLAWSWEEPER_APP_PRIVATE_KEY }}
|
|
pull-request-app-id: ${{ secrets.MANTIS_GITHUB_APP_ID }}
|
|
pull-request-private-key: ${{ secrets.MANTIS_GITHUB_APP_PRIVATE_KEY }}
|
|
|
|
refresh:
|
|
needs: [resolve-base, publisher-preflight]
|
|
if: >-
|
|
needs.resolve-base.result == 'success' &&
|
|
needs.publisher-preflight.result == 'success'
|
|
strategy:
|
|
fail-fast: false
|
|
max-parallel: 2
|
|
matrix:
|
|
locale:
|
|
[
|
|
zh-CN,
|
|
zh-TW,
|
|
pt-BR,
|
|
de,
|
|
es,
|
|
ja-JP,
|
|
ko,
|
|
fr,
|
|
hi,
|
|
ar,
|
|
it,
|
|
tr,
|
|
uk,
|
|
id,
|
|
pl,
|
|
th,
|
|
vi,
|
|
nl,
|
|
fa,
|
|
ru,
|
|
sv,
|
|
]
|
|
runs-on: ubuntu-latest
|
|
name: Refresh native ${{ matrix.locale }}
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
with:
|
|
ref: ${{ needs.resolve-base.outputs.sha }}
|
|
persist-credentials: false
|
|
submodules: false
|
|
|
|
- name: Setup Node environment
|
|
uses: ./.github/actions/setup-node-env
|
|
with:
|
|
install-bun: "false"
|
|
|
|
- name: Ensure translation provider secrets exist
|
|
env:
|
|
OPENCLAW_DOCS_I18N_OPENAI_API_KEY: ${{ secrets.OPENCLAW_DOCS_I18N_OPENAI_API_KEY }}
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [ -z "${OPENCLAW_DOCS_I18N_OPENAI_API_KEY:-}" ] && [ -z "${OPENAI_API_KEY:-}" ] && [ -z "${ANTHROPIC_API_KEY:-}" ]; then
|
|
echo "Missing OPENCLAW_DOCS_I18N_OPENAI_API_KEY, OPENAI_API_KEY, or ANTHROPIC_API_KEY secret."
|
|
exit 1
|
|
fi
|
|
|
|
- name: Refresh native locale artifact
|
|
env:
|
|
OPENCLAW_DOCS_I18N_OPENAI_API_KEY: ${{ secrets.OPENCLAW_DOCS_I18N_OPENAI_API_KEY }}
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
ANTHROPIC_MODEL: claude-opus-4-8
|
|
OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL_BARE || 'gpt-5.6-sol' }}
|
|
OPENCLAW_CONTROL_UI_I18N_THINKING: low
|
|
OPENCLAW_CONTROL_UI_I18N_AUTH_OPTIONAL: "0"
|
|
LOCALE: ${{ matrix.locale }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
run_refresh() {
|
|
local provider="$1"
|
|
local model="$2"
|
|
local openai_api_key="${3-}"
|
|
if [ "$provider" = "openai" ]; then
|
|
OPENAI_API_KEY="$openai_api_key" \
|
|
OPENCLAW_CONTROL_UI_I18N_PROVIDER="$provider" \
|
|
OPENCLAW_CONTROL_UI_I18N_MODEL="$model" \
|
|
node --import tsx scripts/native-app-i18n.ts sync --write --locale "${LOCALE}"
|
|
return
|
|
fi
|
|
OPENCLAW_CONTROL_UI_I18N_PROVIDER="$provider" \
|
|
OPENCLAW_CONTROL_UI_I18N_MODEL="$model" \
|
|
node --import tsx scripts/native-app-i18n.ts sync --write --locale "${LOCALE}"
|
|
}
|
|
|
|
run_openai_refresh() {
|
|
local status=1
|
|
if [ -n "${OPENCLAW_DOCS_I18N_OPENAI_API_KEY:-}" ]; then
|
|
set +e
|
|
run_refresh openai "${OPENAI_MODEL}" "${OPENCLAW_DOCS_I18N_OPENAI_API_KEY}"
|
|
status="$?"
|
|
set -e
|
|
if [ "$status" -eq 0 ]; then
|
|
return 0
|
|
fi
|
|
if [ -z "${OPENAI_API_KEY:-}" ] || [ "${OPENAI_API_KEY}" = "${OPENCLAW_DOCS_I18N_OPENAI_API_KEY}" ]; then
|
|
return "$status"
|
|
fi
|
|
echo "::warning::Docs OpenAI native locale refresh key failed for ${LOCALE}; retrying with repository OpenAI key."
|
|
fi
|
|
if [ -z "${OPENAI_API_KEY:-}" ]; then
|
|
return "$status"
|
|
fi
|
|
run_refresh openai "${OPENAI_MODEL}" "${OPENAI_API_KEY}"
|
|
}
|
|
|
|
if [ -n "${ANTHROPIC_API_KEY:-}" ]; then
|
|
set +e
|
|
run_refresh anthropic "${ANTHROPIC_MODEL}"
|
|
status="$?"
|
|
set -e
|
|
if [ "$status" -eq 0 ]; then
|
|
exit 0
|
|
fi
|
|
if [ -z "${OPENCLAW_DOCS_I18N_OPENAI_API_KEY:-}" ] && [ -z "${OPENAI_API_KEY:-}" ]; then
|
|
exit "$status"
|
|
fi
|
|
echo "::warning::Anthropic native locale refresh failed for ${LOCALE}; retrying with OpenAI."
|
|
fi
|
|
|
|
run_openai_refresh
|
|
|
|
- name: Prepare locale artifact
|
|
env:
|
|
LOCALE: ${{ matrix.locale }}
|
|
run: |
|
|
set -euo pipefail
|
|
artifact_dir="${RUNNER_TEMP}/native-locale-${LOCALE}"
|
|
mkdir -p "${artifact_dir}"
|
|
git add -A apps/.i18n/native
|
|
git diff --cached --binary --full-index -- apps/.i18n/native > "${artifact_dir}/${LOCALE}.patch"
|
|
|
|
- name: Upload locale artifact
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: native-locale-${{ matrix.locale }}
|
|
path: ${{ runner.temp }}/native-locale-${{ matrix.locale }}/${{ matrix.locale }}.patch
|
|
if-no-files-found: error
|
|
retention-days: 1
|
|
|
|
finalize:
|
|
name: Commit native locale refresh
|
|
needs: [resolve-base, publisher-preflight, refresh]
|
|
if: >-
|
|
needs.resolve-base.result == 'success' &&
|
|
needs.publisher-preflight.result == 'success' &&
|
|
needs.refresh.result == 'success'
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
with:
|
|
ref: ${{ needs.resolve-base.outputs.sha }}
|
|
fetch-depth: 0
|
|
persist-credentials: false
|
|
submodules: false
|
|
|
|
- name: Download locale artifacts
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
pattern: native-locale-*
|
|
path: ${{ runner.temp }}/native-locale-artifacts
|
|
merge-multiple: true
|
|
|
|
- name: Apply locale artifacts
|
|
run: |
|
|
set -euo pipefail
|
|
while IFS= read -r patch; do
|
|
if [ -s "${patch}" ]; then
|
|
git apply "${patch}"
|
|
fi
|
|
done < <(find "${RUNNER_TEMP}/native-locale-artifacts" -type f -name '*.patch' | sort)
|
|
|
|
- name: Setup Node environment
|
|
uses: ./.github/actions/setup-node-env
|
|
with:
|
|
install-bun: "false"
|
|
|
|
# Every worker observes the same source inventory. Generate it once here
|
|
# so locale patches remain independent and can be applied sequentially.
|
|
- name: Refresh shared native inventory
|
|
run: node --import tsx scripts/native-app-i18n.ts sync --write
|
|
|
|
- name: Validate native locale refresh
|
|
run: node --import tsx scripts/native-app-i18n.ts check
|
|
|
|
- name: Open or update generated locale PR
|
|
uses: ./.github/actions/publish-generated-pr
|
|
with:
|
|
contents-client-id: Iv23liOECG0slfuhz093
|
|
contents-private-key: ${{ secrets.CLAWSWEEPER_APP_PRIVATE_KEY }}
|
|
pull-request-app-id: ${{ secrets.MANTIS_GITHUB_APP_ID }}
|
|
pull-request-private-key: ${{ secrets.MANTIS_GITHUB_APP_PRIVATE_KEY }}
|
|
base-branch: ${{ github.event.repository.default_branch }}
|
|
head-branch: automation/native-app-locale-refresh
|
|
commit-message: "chore(i18n): refresh native locales"
|
|
pr-title: "chore(i18n): refresh native locales"
|
|
generated-paths: |
|
|
apps/.i18n/native
|
|
apps/.i18n/native-source.json
|
|
invalidation-paths: |
|
|
apps/android/app/src/main
|
|
apps/ios
|
|
apps/macos/Sources
|
|
apps/macos/Package.swift
|
|
apps/shared/OpenClawKit/Sources
|
|
scripts/control-ui-i18n.ts
|
|
scripts/native-app-i18n.ts
|
|
ui/src/i18n/.i18n/glossary.*.json
|
|
.github/actions/create-generated-pr-tokens/action.yml
|
|
.github/actions/publish-generated-pr/action.yml
|
|
.github/workflows/native-app-locale-refresh.yml
|
|
pr-body: |
|
|
## What Problem This Solves
|
|
|
|
Keeps generated native app locales synchronized without bypassing protected-branch checks.
|
|
|
|
## Why This Change Was Made
|
|
|
|
The Native App Locale Refresh workflow generated this update from `${{ needs.resolve-base.outputs.sha }}` and published it through a reviewable automation branch.
|
|
|
|
## User Impact
|
|
|
|
No direct user-facing change beyond refreshed translations.
|
|
|
|
## Evidence
|
|
|
|
- [Locale refresh run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
|
|
- `node --import tsx scripts/native-app-i18n.ts check`
|