fix(i18n): resolve ISO 639-2/B language codes (ger, fre, dut) instead of showing "Unknown" #1136
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: auto-merge | |
| # Tier-based auto-merge for safe-tier-1 / safe-tier-2 PRs. | |
| # | |
| # A PR is eligible to merge iff ALL of: | |
| # 1. State == OPEN, mergeable, not draft, not from a fork. | |
| # 2. Has label `safe-tier-1` (or `safe-tier-2` and the operator has set | |
| # repo variable AUTOPILOT_TIER2_ENABLED == 'true'). | |
| # The label-as-contract is enforced by .github/workflows/ | |
| # tier-label-guard.yml: anyone outside TIER_LABEL_TRUSTED_LABELERS | |
| # who applies a tier label has it stripped immediately. By the time | |
| # this workflow sees the label, a trusted author has signed for it. | |
| # 3. Filename is NOT in FORBIDDEN_PATHS_REGEX (re-verified by | |
| # `python -m scripts.lib.tier_policy validate-fork-pr`, since the | |
| # PR head might have been updated after the label was applied). | |
| # 4. Diff content does NOT match FORBIDDEN_DIFF_CONTENT_REGEX. | |
| # 5. Tier-2 only: diff size <= TIER2_MAX_ADDITIONS LOC and | |
| # <= TIER2_MAX_FILES files (re-verified at this step). | |
| # 6. Tier-2 only: non-translation/docs PRs update CHANGES-vs-upstream.md. | |
| # | |
| # If all of the above pass we call `gh pr merge --auto --squash`. GitHub | |
| # itself then waits for required status checks (per branch protection) | |
| # to become green before merging. We do NOT poll required checks here; | |
| # that responsibility is delegated to GitHub. The list of required | |
| # checks per tier (TIER{1,2}_REQUIRED_CHECKS in tier-policy.config) is | |
| # the documented contract for what branch protection should require — | |
| # `Test Suite Summary` is the unified gate (it knows about tier-2 via | |
| # the PR's labels and fails when Integration Tests didn't pass on a | |
| # tier-2 PR). | |
| # | |
| # All numeric/regex policy values live in .github/policy/tier-policy.config. | |
| # Anything else: the workflow comments why and stops. It never bypasses | |
| # checks, never merges without a label, never `--admin`-overrides. | |
| on: | |
| pull_request: | |
| types: [labeled, synchronize, reopened] | |
| permissions: | |
| pull-requests: write | |
| contents: write | |
| checks: read | |
| concurrency: | |
| group: auto-merge-tier-${{ github.event.pull_request.number }} | |
| cancel-in-progress: false | |
| jobs: | |
| evaluate: | |
| # Bail early for fork PRs — `gh pr merge --auto` won't work for them | |
| # anyway (you can't enable auto-merge from outside the head repo), | |
| # and we want one clear refusal line in the log rather than letting | |
| # the later steps fail in confusing ways. | |
| if: github.event.pull_request.head.repo.full_name == github.repository | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout main (for tier-policy.config + scripts/lib) | |
| # Critical: ref must be main, NOT the PR head. The policy file | |
| # and validator module used to gate the PR are always the ones | |
| # currently on main; a malicious PR cannot widen its own auto- | |
| # merge rules by editing the policy or shadowing the module in | |
| # its branch. | |
| uses: actions/checkout@v7 | |
| with: | |
| ref: main | |
| fetch-depth: 1 | |
| - name: Set up Python (for scripts.lib.tier_policy) | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.13' | |
| - name: Evaluate and (maybe) enable auto-merge | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| REPO: ${{ github.repository }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| TIER2_ENABLED: ${{ vars.AUTOPILOT_TIER2_ENABLED }} | |
| run: | | |
| set -euo pipefail | |
| if [ ! -f .github/policy/tier-policy.config ]; then | |
| echo "::error::missing .github/policy/tier-policy.config — auto-merge cannot run safely" | |
| exit 1 | |
| fi | |
| comment_and_skip() { | |
| local reason="$1" | |
| gh pr comment "$PR_NUMBER" --repo "$REPO" --body "🤖 auto-merge skipped: $reason" | |
| echo "skip #$PR_NUMBER: $reason" | |
| exit 0 | |
| } | |
| echo "=== evaluating PR #$PR_NUMBER ===" | |
| META=$(gh pr view "$PR_NUMBER" --repo "$REPO" \ | |
| --json state,mergeable,labels,files,headRefName,headRefOid,title,isDraft) | |
| state=$(jq -r .state <<<"$META") | |
| mergeable=$(jq -r .mergeable <<<"$META") | |
| is_draft=$(jq -r .isDraft <<<"$META") | |
| labels=$(jq -r '.labels[].name' <<<"$META" | tr '\n' ',') | |
| if [ "$state" != "OPEN" ]; then | |
| echo "PR state=$state, skipping"; exit 0 | |
| fi | |
| if [ "$is_draft" = "true" ]; then | |
| echo "PR is draft, skipping"; exit 0 | |
| fi | |
| if [ "$mergeable" != "MERGEABLE" ]; then | |
| echo "PR mergeable=$mergeable, skipping"; exit 0 | |
| fi | |
| # Tier label gate. tier-label-guard.yml ensures the label was | |
| # applied by a trusted account; if a stale safe-tier label | |
| # somehow survives a force-push (rare — tier-label-guard.yml | |
| # fires per-labeling, so a `synchronize` event that re-adds a | |
| # label wouldn't re-trigger the guard), the validate step | |
| # below catches forbidden content regardless. | |
| if [[ ",$labels," == *",safe-tier-1,"* ]]; then | |
| tier="safe-tier-1" | |
| elif [[ ",$labels," == *",safe-tier-2,"* ]]; then | |
| if [ "${TIER2_ENABLED:-false}" != "true" ]; then | |
| echo "PR has safe-tier-2 but AUTOPILOT_TIER2_ENABLED!=true, skipping" | |
| exit 0 | |
| fi | |
| tier="safe-tier-2" | |
| else | |
| echo "PR has no safe-tier label, skipping" | |
| exit 0 | |
| fi | |
| echo "tier=$tier" | |
| # ─── Run validation through the shared policy module ─────── | |
| # scripts/lib/tier_policy.py is the single source of truth. | |
| # It owns: forbidden-path filename check, tier-2 LOC/file cap | |
| # check, diff-content sensitive-token scan. The CLI returns | |
| # JSON with `ok` + `category` + `reason`. | |
| pr_json=$(mktemp) | |
| diff_text=$(mktemp) | |
| # `--json additions,files` mirrors what validate_fork_pr expects. | |
| gh pr view "$PR_NUMBER" --repo "$REPO" --json additions,changedFiles,files > "$pr_json" | |
| gh pr diff "$PR_NUMBER" --repo "$REPO" > "$diff_text" | |
| result=$(python -m scripts.lib.tier_policy validate-fork-pr \ | |
| --tier "$tier" "$pr_json" "$diff_text") | |
| rm -f "$pr_json" "$diff_text" | |
| echo "validate-fork-pr result: $result" | |
| ok=$(jq -r '.ok' <<<"$result") | |
| category=$(jq -r '.category' <<<"$result") | |
| reason=$(jq -r '.reason' <<<"$result") | |
| if [ "$ok" != "true" ]; then | |
| # Demote to needs-review and stop. tier-2 demotion strips | |
| # both labels because the operator may have intended tier-1 | |
| # but the validator caught something requiring eyes. | |
| gh pr edit "$PR_NUMBER" --repo "$REPO" \ | |
| --remove-label safe-tier-1 --remove-label safe-tier-2 \ | |
| --add-label needs-review || true | |
| comment_and_skip "$reason" | |
| fi | |
| # ─── Tier-2 only: CHANGES-vs-upstream.md update required ─── | |
| # Tier-2 PRs that touch any non-doc, non-po file MUST also | |
| # update CHANGES-vs-upstream.md (CLAUDE.md hard rule for | |
| # tracking divergence). Tier-1 (.po + *.md only) is exempt. | |
| if [ "$tier" = "safe-tier-2" ]; then | |
| files=$(jq -r '.files[].path' <<<"$META") | |
| has_code=0 | |
| has_changes_update=0 | |
| while IFS= read -r f; do | |
| # Case patterns match positionally — the explicit | |
| # CHANGES-vs-upstream.md branch MUST precede *.md or | |
| # the wildcard wins and `has_changes_update` never | |
| # gets set, demoting every tier-2 PR that correctly | |
| # updates CHANGES-vs-upstream.md. | |
| case "$f" in | |
| CHANGES-vs-upstream.md) has_changes_update=1 ;; | |
| *.po|*.pot) ;; | |
| *.md|README*) ;; | |
| *) has_code=1 ;; | |
| esac | |
| done <<<"$files" | |
| if [ "$has_code" = "1" ] && [ "$has_changes_update" = "0" ]; then | |
| comment_and_skip "tier-2 PRs with code changes must update CHANGES-vs-upstream.md to document the divergence. Add a row, push, and CI will re-evaluate." | |
| fi | |
| fi | |
| # ─── Enable auto-merge ──────────────────────────────────── | |
| # We do NOT poll required checks here. GitHub waits for them | |
| # via branch protection (validate-author + Fast Tests + Test | |
| # Suite Summary required; the summary is tier-aware and fails | |
| # on integration-tests failure for safe-tier-2 PRs). This is | |
| # the workflow_run polling loop that the old version did, but | |
| # delegated to GitHub itself — fewer places for the state | |
| # machine to live, no more race-on-completion bugs. | |
| # | |
| # --auto requires the repo to have "Allow auto-merge" enabled | |
| # in settings (it is). | |
| echo "Enabling auto-merge for PR #$PR_NUMBER under $tier" | |
| gh pr merge "$PR_NUMBER" --repo "$REPO" --auto --squash --delete-branch | |
| gh pr comment "$PR_NUMBER" --repo "$REPO" \ | |
| --body "🤖 auto-merge enabled under tier \`$tier\`. GitHub will merge once required status checks complete." |