diff --git a/.github/actions/create-workflow-failure-issue/action.yml b/.github/actions/create-workflow-failure-issue/action.yml index dd653e96472d..3bbb95775751 100644 --- a/.github/actions/create-workflow-failure-issue/action.yml +++ b/.github/actions/create-workflow-failure-issue/action.yml @@ -98,6 +98,14 @@ runs: --repo "$ISSUE_REPO" \ --label "workflow-failure" \ --label "workflow-generated" \ + --label "engineering" \ + --label "priority-2" \ --title "[Workflow Failure] $WORKFLOW_NAME" \ --body "$body") echo "issue_url=$url" >> "$GITHUB_OUTPUT" + + # Set the type separately, and tolerate failure. This action is itself the + # failure path, so losing the whole issue because issue types are unavailable + # or `gh` is too old (--type needs gh 2.94+) would hide the original failure. + gh issue edit "$url" --type Bug \ + || echo "Warning: could not set issue type on $url; leaving it unset." diff --git a/.github/workflows/check-for-spammy-pr.yml b/.github/workflows/check-for-spammy-pr.yml index 0334d594750d..130dd44e0346 100644 --- a/.github/workflows/check-for-spammy-pr.yml +++ b/.github/workflows/check-for-spammy-pr.yml @@ -15,7 +15,9 @@ permissions: jobs: spammy-pr-check: name: Label PRs that only delete files or touch a large number of files - if: github.repository == 'github/docs' && github.event_name == 'pull_request_target' + if: > + github.repository == 'github/docs' && github.event_name == 'pull_request_target' && + github.event.pull_request.user.login != 'docs-bot' runs-on: ubuntu-latest steps: - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 @@ -49,6 +51,6 @@ jobs: owner: owner, repo: repo, issue_number: pull_number, - body: `This pull request may have been opened accidentally. I'm going to close it now, but feel free to check out our [contribution guidelines](https://docs.github.com/en/contributing), or raise a new issue.` + body: `This pull request may have been opened accidentally. I'm going to close it now, but feel free to check out our [contribution guidelines](https://docs.github.com/en/contributing), or raise an issue.`, }); } diff --git a/src/languages/lib/correct-translation-content.ts b/src/languages/lib/correct-translation-content.ts index 396f51694697..9a38a94decee 100644 --- a/src/languages/lib/correct-translation-content.ts +++ b/src/languages/lib/correct-translation-content.ts @@ -58,6 +58,17 @@ export function correctTranslatedContentStrings( '{%$1 data variables.$2$3', ) + // Translators sometimes inserted a stray space right after a dot inside + // a `{% data variables.X.Y %}` path (e.g. `{% data variables.product. + // prodname_pages %}` or `{% data variables. product.prodname_pages %}`). + // Liquid parses the space as ending the variable lookup early, breaking + // the tag. Collapse the space back out. The English source never has + // a space after a dot in a variable path, so this is safe globally. + content = content.replace( + /\{%(-?)\s*data\s+(?:variables|reusables)(?:\.\s*[A-Za-z0-9_-]+)+(?=\s*-?%\})/g, + (path) => path.replace(/\.\s+/g, '.'), + ) + // The translation pipeline frequently splits Markdown bullet markers // (`*` and `-`) and table-cell pipes (`|`) onto their own line, with // the actual content pushed to the next line as deeply indented text. diff --git a/src/languages/tests/correct-translation-content.ts b/src/languages/tests/correct-translation-content.ts index 39fa9b7898ea..16f73128ac31 100644 --- a/src/languages/tests/correct-translation-content.ts +++ b/src/languages/tests/correct-translation-content.ts @@ -1664,6 +1664,27 @@ describe('correctTranslatedContentStrings', () => { expect(fix('{% data .reusables.foo.bar %}', 'zh')).toBe('{% data reusables.foo.bar %}') }) + test('fixes stray space after a dot inside {% data variables/reusables paths', () => { + // Translators sometimes inserted a stray space right after a dot in a + // multi-segment `variables.X.Y` / `reusables.X.Y` path (e.g. wrapping + // long lines mid-path). Liquid parses the space as ending the variable + // lookup early, breaking the tag. Confirmed in de-de, ja-jp, ru-ru. + expect(fix('{% data variables.product. prodname_pages %}', 'de')).toBe( + '{% data variables.product.prodname_pages %}', + ) + expect(fix('{% data variables. product.prodname_pro %}', 'ja')).toBe( + '{% data variables.product.prodname_pro %}', + ) + expect(fix('{% data variables.copilot. copilot_chat_short %}', 'ru')).toBe( + '{% data variables.copilot.copilot_chat_short %}', + ) + expect(fix('{%- data reusables.foo. bar -%}', 'de')).toBe('{%- data reusables.foo.bar -%}') + // Already-correct input is left unchanged. + expect(fix('{% data variables.product.prodname_pages %}', 'de')).toBe( + '{% data variables.product.prodname_pages %}', + ) + }) + test('fixes singular variable / reusable in {% data paths', () => { // `{% data variable.product.X %}` (singular) → `{% data variables.product.X %}` expect(fix('{% data variable.product.prodname_container_registry %}', 'zh')).toBe(