This is an automated email from the ASF dual-hosted git repository.
morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris-website.git
The following commit(s) were added to refs/heads/master by this push:
new 37358394612a [fix](i18n) Label automated translation PRs ai-translate
(#4549)
37358394612a is described below
commit 37358394612a1d4e47132ddfe96e1b165a648b08
Author: Mingyu Chen (Rayner) <[email protected]>
AuthorDate: Thu Oct 29 00:02:32 2026 +0000
[fix](i18n) Label automated translation PRs ai-translate (#4549)
Automated Japanese, Korean and Russian translation PRs now receive
`ai-translate` alongside their existing `translate-<locale>` label. The
shared workflow verifies that both labels exist before calling the
translation model.
Validation: 49 focused translation workflow/publication tests and 27
workflow security tests passed; `git diff --check` passed. The local
end-to-end publication simulator passed and recorded both `translate-ja`
and `ai-translate` in the actual PR command. All three PR checks passed
on final head `33ef82c501a4e43d7ed0886fa426d27e2a06bd7e`: Build Check
(389 tests passed, one conditional skip), Markdown Links and File Sizes.
The repository already has all four required labels.
Self-review against AGENTS.md:
- Goal: the shared publisher covers all three language workflows and
adds both labels when creating a PR.
- Scope: limited to the publisher, shared workflow preflight, existing
regression test and local publication simulator.
- Information architecture: no documentation, version, locale or
navigation content changes.
- Links and routes: no paths, anchors, slugs or sidebar entries change.
- Frontend/build conventions: no rendering or build behavior changes;
existing workflow triggers, permissions, checkout settings and
credentials are preserved.
- Validation: tests cover successful label checks and failure for either
missing label in every language; simulated publication and all normal PR
checks passed.
- Other issues: none found.
---------
Co-authored-by: morningman <[email protected]>
---
.github/workflows/translation-run.yml | 7 +++--
.../i18n/__tests__/translation-workflows.test.cjs | 32 ++++++++++++++--------
scripts/i18n/simulate-workflow.cjs | 5 ++--
scripts/i18n/workflow-publish.cjs | 2 +-
4 files changed, 30 insertions(+), 16 deletions(-)
diff --git a/.github/workflows/translation-run.yml
b/.github/workflows/translation-run.yml
index f46a84a5d292..a43ae4b18811 100644
--- a/.github/workflows/translation-run.yml
+++ b/.github/workflows/translation-run.yml
@@ -157,11 +157,14 @@ jobs:
id: fresh
run: node scripts/i18n/workflow-scan.cjs
"$RUNNER_TEMP/$TRANSLATION_WORKSPACE"
# The publisher labels the PR only after the model calls and the branch
push.
- - name: Verify the PR label before model calls
+ - name: Verify the PR labels before model calls
if: steps.fresh.outputs.can_generate == 'true'
env:
GH_TOKEN: ${{ github.token }}
- run: test "$(gh api
"repos/apache/doris-website/labels/translate-$I18N_LOCALE" --jq .name)" =
"translate-$I18N_LOCALE"
+ run: |
+ for label in "translate-$I18N_LOCALE" ai-translate; do
+ test "$(gh api "repos/apache/doris-website/labels/$label" --jq
.name)" = "$label"
+ done
- name: Install ossutil for the pinned Codex package and auth pool
if: steps.fresh.outputs.can_generate == 'true'
run: |
diff --git a/scripts/i18n/__tests__/translation-workflows.test.cjs
b/scripts/i18n/__tests__/translation-workflows.test.cjs
index 6ed0f7ee0629..8c02f972ca0d 100644
--- a/scripts/i18n/__tests__/translation-workflows.test.cjs
+++ b/scripts/i18n/__tests__/translation-workflows.test.cjs
@@ -139,28 +139,38 @@ test('discovery and generation exchange artifacts in the
caller workspace', () =
assert(scripts.every(step => step.run.endsWith('
"$RUNNER_TEMP/$TRANSLATION_WORKSPACE"')));
const index = name => generate.findIndex(step => step.name === name);
assert(index('Reconcile again immediately before model calls') <
index('Replan exact source and open PRs'));
- assert(index('Replan exact source and open PRs') < index('Verify the PR
label before model calls'));
+ assert(index('Replan exact source and open PRs') < index('Verify the PR
labels before model calls'));
assert.equal(generate.find(step => step.id ===
'translation').env.I18N_CODEX_MODEL,
"${{ vars.I18N_CODEX_MODEL || 'gpt-6-sol' }}");
});
-test('the label check runs before auth loading and fails for a missing locale
label', t => {
+test('the label check runs before auth loading and requires both PR labels for
every language', t => {
const steps = shared.jobs.generate.steps;
- const label = steps.findIndex(step => step.name === 'Verify the PR label
before model calls');
+ const label = steps.findIndex(step => step.name === 'Verify the PR labels
before model calls');
const auth = steps.findIndex(step => step.id === 'auth');
assert(label >= 0 && label < auth);
assert.equal(steps[label].if, "steps.fresh.outputs.can_generate ==
'true'");
assert.equal(steps[label].env.GH_TOKEN, '${{ github.token }}');
const bin = fs.mkdtempSync(path.join(os.tmpdir(), 'translation-label-'));
t.after(() => fs.rmSync(bin, {recursive: true, force: true}));
- // The mock answers like the labels API: the name, or nothing when missing.
- fs.writeFileSync(path.join(bin, 'gh'), '#!/bin/sh\ncase "$2" in
*/labels/translate-ja) echo translate-ja;; */labels/translate-ru) echo
translate-ru;; esac\n',
- {mode: 0o755});
- const run = locale => spawnSync('bash', ['-e', '-c', steps[label].run],
- {env: {...process.env, PATH: `${bin}:${process.env.PATH}`,
I18N_LOCALE: locale}}).status;
- assert.equal(run('ja'), 0);
- assert.equal(run('ru'), 0);
- assert.notEqual(run('ko'), 0);
+ // The mock answers like the labels API, including a failed request for a
missing label.
+ fs.writeFileSync(path.join(bin, 'gh'), `#!/bin/sh
+case "$2" in
+
*/labels/translate-ja|*/labels/translate-ko|*/labels/translate-ru|*/labels/ai-translate)
+ label="\${2##*/}";;
+ *) exit 1;;
+esac
+test "$label" != "$TEST_MISSING_LABEL" || exit 1
+echo "$label"
+`, {mode: 0o755});
+ const run = (locale, missing = '') => spawnSync('bash', ['-e', '-c',
steps[label].run],
+ {env: {...process.env, PATH: `${bin}:${process.env.PATH}`,
I18N_LOCALE: locale,
+ TEST_MISSING_LABEL: missing}}).status;
+ for (const locale of Object.keys(callers)) {
+ assert.equal(run(locale), 0, locale);
+ assert.notEqual(run(locale, `translate-${locale}`), 0, `${locale}:
missing language label`);
+ assert.notEqual(run(locale, 'ai-translate'), 0, `${locale}: missing
shared label`);
+ }
});
test('publication preserves the verified runtime and refresh path', () => {
diff --git a/scripts/i18n/simulate-workflow.cjs
b/scripts/i18n/simulate-workflow.cjs
index 9870775dab81..5a45731bc5fa 100644
--- a/scripts/i18n/simulate-workflow.cjs
+++ b/scripts/i18n/simulate-workflow.cjs
@@ -82,10 +82,11 @@ if (args[0] === 'api' && args.some(arg =>
arg.startsWith('repos/apache/doris-web
assert(!args.includes('--draft'));
assert.equal(value('--base'), 'master');
assert.equal(value('--repo'), 'apache/doris-website');
- assert.equal(value('--label'), 'translate-ja');
+ const labels = args.flatMap((arg, index) => arg === '--label' ?
[args[index + 1]] : []);
+ assert.deepEqual(labels, ['translate-ja', 'ai-translate']);
const body = fs.readFileSync(value('--body-file'), 'utf8');
assert.match(body, /japanese-translation-automation:v1
bot-head=[a-f0-9]{40}/);
- const record = {draft: false, base: value('--base'), head:
value('--head'), labels: [value('--label')], body,
+ const record = {draft: false, base: value('--base'), head:
value('--head'), labels, body,
url: 'https://example.invalid/apache/doris-website/pull/1'};
fs.writeFileSync(process.env.I18N_SIM_PR_RECORD, JSON.stringify(record,
null, 2) + '\\n');
process.stdout.write(record.url + '\\n');
diff --git a/scripts/i18n/workflow-publish.cjs
b/scripts/i18n/workflow-publish.cjs
index 8eaa73bf1896..49d1ba8f8647 100644
--- a/scripts/i18n/workflow-publish.cjs
+++ b/scripts/i18n/workflow-publish.cjs
@@ -98,7 +98,7 @@ async function main() {
execFileSync('gh', ['auth', 'setup-git'], {cwd: root, stdio: 'inherit'});
git('push', 'origin', `HEAD:refs/heads/${branch}`);
const url = execFileSync('gh', ['pr', 'create', '--repo',
'apache/doris-website', '--base', 'master',
- '--head', branch, '--label', `translate-${locale}`,
+ '--head', branch, '--label', `translate-${locale}`, '--label',
'ai-translate',
'--title', `docs(i18n): machine ${language} translation candidates`,
'--body-file', bodyFile], {cwd: root, encoding: 'utf8'}).trim();
if (process.env.GITHUB_STEP_SUMMARY)
fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY,
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]