Skip to content

Sync with CPython

Sync with CPython #54

name: Sync with CPython
on:
schedule:
- cron: '0 4 * * *'
workflow_dispatch:
inputs:
cpython_tag:
description: 'CPython tag/branch to sync against (e.g. 3.14)'
required: false
default: '3.14'
permissions:
contents: write
issues: write
# Shared with maintenance.yml so the two never push at the same time.
concurrency:
group: repo-writes
cancel-in-progress: false
jobs:
sync:
runs-on: ubuntu-latest
timeout-minutes: 45
env:
CPYTHON_TAG: ${{ github.event.inputs.cpython_tag || '3.14' }}
steps:
- name: Checkout translation repo
uses: actions/checkout@v4
with:
fetch-depth: 0
# --- Skip the expensive build if upstream hasn't moved -------------
- name: Get upstream head
id: upstream
run: |
sha=$(git ls-remote https://github.com/python/cpython \
"refs/heads/$CPYTHON_TAG" "refs/tags/$CPYTHON_TAG" \
| head -1 | cut -f1)
echo "sha=$sha" >> "$GITHUB_OUTPUT"
# Marker lives outside the repo so `git add --all` never sees it.
echo "$sha" > "$RUNNER_TEMP/sync-marker"
- name: Check whether this upstream head was already synced
id: seen
# Fail open: no SHA -> no lookup -> full run.
if: steps.upstream.outputs.sha != ''
uses: actions/cache/restore@v4
with:
path: ${{ runner.temp }}/sync-marker
key: synced-${{ env.CPYTHON_TAG }}-${{ steps.upstream.outputs.sha }}
lookup-only: true
- name: Decide whether to run
run: |
if [ "${{ steps.seen.outputs.cache-hit }}" = "true" ] \
&& [ "${{ github.event_name }}" != "workflow_dispatch" ]; then
echo "Upstream ${{ steps.upstream.outputs.sha }} already synced; skipping."
echo "SKIP=true" >> "$GITHUB_ENV"
fi
# --- Sync ------------------------------------------------------------
- name: Set up Python
if: env.SKIP != 'true'
uses: actions/setup-python@v4
with:
python-version: '3.12'
- name: Install gettext
if: env.SKIP != 'true'
run: sudo apt-get install -y gettext
- name: Install Python dependencies
if: env.SKIP != 'true'
# polib is used by scripts/review_report.py to build the issue body.
# Consider installing sphinx from CPython's Doc/requirements.txt
# instead of unpinned, so Sphinx upgrades can't change msgids on
# their own.
run: pip install sphinx sphinx-intl polib
- name: Sync msgids (fetch, build gettext, merge, validate)
if: env.SKIP != 'true'
run: python scripts/po_sync.py sync-only "$CPYTHON_TAG" --create-new
- name: Stage changes
if: env.SKIP != 'true'
run: git add --all
- name: Unstage POT-Creation-Date-only changes
if: env.SKIP != 'true'
run: python scripts/unstage_cosmetic.py
# --- Build the report from what is actually staged -------------------
# New PO files, newly fuzzy strings (old -> new diff) and new
# untranslated strings. Writes an empty file if there is nothing to
# report, in which case no issue is opened.
- name: Build review report (new files, newly fuzzy, new untranslated)
if: env.SKIP != 'true'
run: python scripts/review_report.py --output "$RUNNER_TEMP/report.md"
# --- Commit + push ---------------------------------------------------
- name: Commit and push if changed
id: commit
if: env.SKIP != 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
if git diff --staged --quiet; then
echo "Nothing to commit."
echo "committed=false" >> "$GITHUB_OUTPUT"
exit 0
fi
git commit -m "chore: sync msgids with CPython $CPYTHON_TAG"
git pull --rebase
git push
echo "committed=true" >> "$GITHUB_OUTPUT"
# Only after a successful push, so a failed run can't create duplicates.
- name: Open issue for new files / fuzzy / untranslated strings
if: env.SKIP != 'true' && steps.commit.outputs.committed == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
report="$RUNNER_TEMP/report.md"
if [ -s "$report" ]; then
gh label create "translation" \
--color "0075ca" \
--description "Translation review needed" \
--repo "${{ github.repository }}" 2>/dev/null || true
echo "Triggered by sync with \`$CPYTHON_TAG\` (commit $(git rev-parse --short HEAD))." >> "$report"
gh issue create \
--title "🔍 Translation review needed after CPython sync ($(date +%Y-%m-%d))" \
--body-file "$report" \
--label "translation" \
--repo "${{ github.repository }}"
fi
# Record the upstream head as synced (only reached if everything above passed).
- name: Remember synced upstream head
if: env.SKIP != 'true' && steps.upstream.outputs.sha != ''
uses: actions/cache/save@v4
with:
path: ${{ runner.temp }}/sync-marker
key: synced-${{ env.CPYTHON_TAG }}-${{ steps.upstream.outputs.sha }}