Skip to content

Commit 73e9609

Browse files
committed
New workflow and scripts updates
1 parent 1e2f05e commit 73e9609

20 files changed

Lines changed: 290 additions & 170 deletions

‎.github/workflows/build-and-deploy.yml‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ name: Build and Deploy to GitHub Pages
22

33
on:
44
schedule:
5-
- cron: '0 2 * * *'
5+
- cron: '0 6 * * *'
66
push:
77
branches:
88
- 3.14
9-
paths-ignore: []
109
workflow_dispatch:
1110

1211
permissions:

‎.github/workflows/lint.yml‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ name: Lint Check
22

33
on:
44
schedule:
5-
- cron: '0 0 * * *'
5+
# After the 04:00 sync and 05:00 maintenance, so it lints tonight's result.
6+
# (Pushes made with GITHUB_TOKEN do not trigger this workflow.)
7+
- cron: '0 7 * * *'
68
push:
79
branches:
8-
- '*'
10+
- '**' # '*' does not match branch names containing a slash
911
pull_request:
1012
branches:
1113
- '*'
@@ -59,7 +61,7 @@ jobs:
5961
working-directory: Doc/locales/fa/LC_MESSAGES
6062

6163
- name: Check PO file validity
62-
run: find . -name '*.po' -exec msgfmt --check {} \;
64+
run: find . -name '*.po' -print0 | xargs -0 -n1 msgfmt --check -o /dev/null
6365
working-directory: Doc/locales/fa/LC_MESSAGES
6466

6567
- name: Check markup preservation

‎.github/workflows/maintenance.yml‎

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,27 @@ name: Scheduled Maintenance
22

33
on:
44
schedule:
5-
- cron: '30 3 * * *'
5+
# Runs after the 04:00 CPython sync so the status table and headers
6+
# reflect today's msgids instead of yesterday's.
7+
- cron: '0 5 * * *'
68
workflow_dispatch: {}
79

810
permissions:
911
contents: write
1012

13+
# Shared with sync-cpython.yml so the two never push at the same time.
1114
concurrency:
12-
group: maintenance
15+
group: repo-writes
1316
cancel-in-progress: false
1417

1518
jobs:
1619
maintenance:
1720
runs-on: ubuntu-latest
21+
timeout-minutes: 30
1822
steps:
1923
- uses: actions/checkout@v4
2024
with:
21-
fetch-depth: 0
25+
fetch-depth: 0 # needed if team_stats/contributor_chart read git history
2226

2327
- name: Set up Python
2428
uses: actions/setup-python@v4
@@ -40,11 +44,21 @@ jobs:
4044
- name: Update contributor chart and README stats block
4145
run: python3 scripts/contributor_chart.py
4246

43-
- name: Commit if changed
47+
- name: Stage changes
48+
run: git add --all
49+
50+
# Drops .po files whose only change is POT-Creation-Date.
51+
- name: Unstage POT-Creation-Date-only changes
52+
run: python3 scripts/unstage_cosmetic.py
53+
54+
- name: Commit and push if changed
4455
run: |
45-
git config user.name "github-actions[bot]"
46-
git config user.email "github-actions[bot]@users.noreply.github.com"
47-
git add --all
48-
git diff --staged --quiet && echo "No changes to commit" && exit 0
49-
git commit -m "chore: update translation status, PO headers, team credits, and contributor chart"
50-
git push
56+
git config user.name "github-actions[bot]"
57+
git config user.email "github-actions[bot]@users.noreply.github.com"
58+
if git diff --staged --quiet; then
59+
echo "No changes to commit"
60+
exit 0
61+
fi
62+
git commit -m "chore: update translation status, PO headers, team credits, and contributor chart"
63+
git pull --rebase
64+
git push

‎.github/workflows/sync-with-cpython.yml‎

Lines changed: 113 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,23 @@ on:
66
workflow_dispatch:
77
inputs:
88
cpython_tag:
9-
description: 'CPython tag to sync against (e.g. 3.14)'
9+
description: 'CPython tag/branch to sync against (e.g. 3.14)'
1010
required: false
1111
default: '3.14'
1212

1313
permissions:
1414
contents: write
1515
issues: write
1616

17+
# Shared with maintenance.yml so the two never push at the same time.
1718
concurrency:
18-
group: sync
19+
group: repo-writes
1920
cancel-in-progress: false
2021

2122
jobs:
2223
sync:
2324
runs-on: ubuntu-latest
25+
timeout-minutes: 45
2426
env:
2527
CPYTHON_TAG: ${{ github.event.inputs.cpython_tag || '3.14' }}
2628
steps:
@@ -29,115 +31,149 @@ jobs:
2931
with:
3032
fetch-depth: 0
3133

34+
# --- Skip the expensive build if upstream hasn't moved -------------
35+
- name: Get upstream head
36+
id: upstream
37+
run: |
38+
sha=$(git ls-remote https://github.com/python/cpython \
39+
"refs/heads/$CPYTHON_TAG" "refs/tags/$CPYTHON_TAG" \
40+
| head -1 | cut -f1)
41+
echo "sha=$sha" >> "$GITHUB_OUTPUT"
42+
# Marker lives outside the repo so `git add --all` never sees it.
43+
echo "$sha" > "$RUNNER_TEMP/sync-marker"
44+
45+
- name: Check whether this upstream head was already synced
46+
id: seen
47+
# Fail open: no SHA -> no lookup -> full run.
48+
if: steps.upstream.outputs.sha != ''
49+
uses: actions/cache/restore@v4
50+
with:
51+
path: ${{ runner.temp }}/sync-marker
52+
key: synced-${{ env.CPYTHON_TAG }}-${{ steps.upstream.outputs.sha }}
53+
lookup-only: true
54+
55+
- name: Decide whether to run
56+
run: |
57+
if [ "${{ steps.seen.outputs.cache-hit }}" = "true" ] \
58+
&& [ "${{ github.event_name }}" != "workflow_dispatch" ]; then
59+
echo "Upstream ${{ steps.upstream.outputs.sha }} already synced; skipping."
60+
echo "SKIP=true" >> "$GITHUB_ENV"
61+
fi
62+
63+
# --- Sync ------------------------------------------------------------
3264
- name: Set up Python
65+
if: env.SKIP != 'true'
3366
uses: actions/setup-python@v4
3467
with:
3568
python-version: '3.12'
3669

3770
- name: Install gettext
71+
if: env.SKIP != 'true'
3872
run: sudo apt-get install -y gettext
3973

4074
- name: Install Python dependencies
75+
if: env.SKIP != 'true'
76+
# Consider installing from CPython's Doc/requirements.txt instead of
77+
# unpinned sphinx, so Sphinx upgrades can't change msgids on their own.
4178
run: pip install sphinx sphinx-intl
4279

43-
# Item 4: fetch/build/merge/validate now all live in one shared
44-
# module (scripts/po_sync.py) instead of inline bash/awk here, so
45-
# this workflow can't drift from update_python_version.py the way
46-
# it did before (missing --no-location --no-wrap on one side).
4780
- name: Sync msgids (fetch, build gettext, merge, validate)
81+
if: env.SKIP != 'true'
4882
run: python scripts/po_sync.py sync-only "$CPYTHON_TAG" --create-new
4983

50-
- name: Ensure translation label exists
51-
env:
52-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
53-
run: |
54-
gh label create "translation" \
55-
--color "0075ca" \
56-
--description "Translation review needed" \
57-
--repo ${{ github.repository }} \
58-
2>/dev/null || true
84+
- name: Stage changes
85+
if: env.SKIP != 'true'
86+
run: git add --all
5987

60-
- name: Open issue for new and fuzzy strings
61-
env:
62-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
88+
- name: Unstage POT-Creation-Date-only changes
89+
if: env.SKIP != 'true'
90+
run: python scripts/unstage_cosmetic.py
91+
92+
# --- Build the report from what is actually staged -------------------
93+
- name: Build review report (new files + newly fuzzy strings)
94+
if: env.SKIP != 'true'
6395
run: |
64-
tmpfile=$(mktemp)
96+
report="$RUNNER_TEMP/report.md"
97+
: > "$report"
98+
work=$(mktemp -d)
6599
66-
# --- New PO files (untracked, since nothing is staged yet) ---
67-
new_files=$(git ls-files --others --exclude-standard -- '*.po' \
68-
':(exclude).cpython-src' ':(exclude).pot-templates')
100+
# New PO files
101+
new_files=$(git diff --staged --name-only --diff-filter=A -- '*.po')
69102
if [ -n "$new_files" ]; then
70-
new_count=$(echo "$new_files" | wc -l)
71103
{
72-
echo "## 🆕 New PO files ($new_count)"
104+
echo "## 🆕 New PO files ($(echo "$new_files" | wc -l))"
73105
echo "$new_files" | sed 's/^/- `/; s/$/`/'
74106
echo ""
75-
} >> "$tmpfile"
107+
} >> "$report"
76108
fi
77109
78-
# --- Fuzzy strings ---
79-
fuzzy_out=$(mktemp)
110+
# Fuzzy entries that are new in this run (present now, absent at HEAD)
111+
fuzzy_out="$work/fuzzy.md"
112+
: > "$fuzzy_out"
113+
git diff --staged --name-only --diff-filter=M -- '*.po' |
80114
while IFS= read -r f; do
81-
fuzzy=$(msgattrib --only-fuzzy --no-obsolete "$f" 2>/dev/null)
82-
if [ -n "$fuzzy" ]; then
83-
entries=$(echo "$fuzzy" | awk '
84-
/^msgid / {
85-
first=$0; msg=$0"\n"; lines=1; incapture=1; next
86-
}
87-
incapture && /^"/ {
88-
msg = msg $0 "\n"; lines++; next
89-
}
90-
incapture && /^msgstr/ {
91-
incapture=0
92-
if (!(first == "msgid \"\"" && lines==1)) {
93-
printf "- %s\n", msg
94-
}
95-
next
96-
}
97-
')
98-
count=$(echo "$entries" | grep -c '^- ' || true)
99-
if [ "${count:-0}" -gt 0 ]; then
100-
echo "### $f ($count fuzzy)" >> "$fuzzy_out"
101-
echo "$entries" | head -20 >> "$fuzzy_out"
102-
echo "" >> "$fuzzy_out"
103-
fi
115+
git show "HEAD:$f" > "$work/old_full.po"
116+
msgattrib --only-fuzzy --no-obsolete --no-wrap "$work/old_full.po" > "$work/old.po" 2>/dev/null || : > "$work/old.po"
117+
msgattrib --only-fuzzy --no-obsolete --no-wrap "$f" > "$work/new.po" 2>/dev/null || : > "$work/new.po"
118+
# entries in exactly one of old/new, then keep those also in new
119+
msgcomm --less-than=2 --no-wrap "$work/old.po" "$work/new.po" > "$work/sym.po" 2>/dev/null || : > "$work/sym.po"
120+
msgcomm --no-wrap "$work/new.po" "$work/sym.po" > "$work/added.po" 2>/dev/null || : > "$work/added.po"
121+
count=$(grep -c '^#, .*fuzzy' "$work/added.po" || true)
122+
if [ "${count:-0}" -gt 0 ]; then
123+
{
124+
echo "### \`$f\` ($count new fuzzy)"
125+
grep -E '^msgid ".+"' "$work/added.po" | sed 's/^msgid /- /' | head -10
126+
[ "$count" -gt 10 ] && echo "- … and $((count - 10)) more"
127+
echo ""
128+
} >> "$fuzzy_out"
104129
fi
105-
done < <(find . -name "*.po" \
106-
-not -path "./.git/*" \
107-
-not -path "./.cpython-src/*" \
108-
-not -path "./.pot-templates/*")
130+
done
109131
110132
if [ -s "$fuzzy_out" ]; then
111-
{
112-
echo "## 🔍 Fuzzy strings"
113-
cat "$fuzzy_out"
114-
} >> "$tmpfile"
115-
fi
116-
117-
# --- One issue for both ---
118-
if [ -s "$tmpfile" ]; then
119-
echo "Triggered by sync with \`$CPYTHON_TAG\`." >> "$tmpfile"
120-
gh issue create \
121-
--title "🔍 Translation review needed after CPython sync ($(date +%Y-%m-%d))" \
122-
--body-file "$tmpfile" \
123-
--label "translation" \
124-
--repo ${{ github.repository }}
133+
{ echo "## 🔍 Newly fuzzy strings"; cat "$fuzzy_out"; } >> "$report"
125134
fi
126-
rm -f "$tmpfile" "$fuzzy_out"
127-
128-
- name: Stage changes
129-
run: git add --all
130135
131-
- name: Unstage POT-Creation-Date-only changes
132-
run: python scripts/unstage_cosmetic.py
133-
134-
- name: Commit if changed
136+
# --- Commit + push ---------------------------------------------------
137+
- name: Commit and push if changed
138+
id: commit
139+
if: env.SKIP != 'true'
135140
run: |
136141
git config user.name "github-actions[bot]"
137142
git config user.email "github-actions[bot]@users.noreply.github.com"
138143
if git diff --staged --quiet; then
139-
echo "Nothing to commit, skipping."
144+
echo "Nothing to commit."
145+
echo "committed=false" >> "$GITHUB_OUTPUT"
140146
exit 0
141147
fi
142148
git commit -m "chore: sync msgids with CPython $CPYTHON_TAG"
149+
git pull --rebase
143150
git push
151+
echo "committed=true" >> "$GITHUB_OUTPUT"
152+
153+
# Only after a successful push, so a failed run can't create duplicates.
154+
- name: Open issue for new files / newly fuzzy strings
155+
if: env.SKIP != 'true' && steps.commit.outputs.committed == 'true'
156+
env:
157+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
158+
run: |
159+
report="$RUNNER_TEMP/report.md"
160+
if [ -s "$report" ]; then
161+
gh label create "translation" \
162+
--color "0075ca" \
163+
--description "Translation review needed" \
164+
--repo "${{ github.repository }}" 2>/dev/null || true
165+
echo "Triggered by sync with \`$CPYTHON_TAG\` (commit $(git rev-parse --short HEAD))." >> "$report"
166+
gh issue create \
167+
--title "🔍 Translation review needed after CPython sync ($(date +%Y-%m-%d))" \
168+
--body-file "$report" \
169+
--label "translation" \
170+
--repo "${{ github.repository }}"
171+
fi
172+
173+
# Record the upstream head as synced (only reached if everything above passed).
174+
- name: Remember synced upstream head
175+
if: env.SKIP != 'true' && steps.upstream.outputs.sha != ''
176+
uses: actions/cache/save@v4
177+
with:
178+
path: ${{ runner.temp }}/sync-marker
179+
key: synced-${{ env.CPYTHON_TAG }}-${{ steps.upstream.outputs.sha }}

‎builtins/constants.po‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ msgstr ""
1212
"Report-Msgid-Bugs-To: \n"
1313
"POT-Creation-Date: 2026-09-19 20:08+0330\n"
1414
"PO-Revision-Date: 2026-09-19 20:08+0330\n"
15-
"Last-Translator: Automatically generated\n"
15+
"Last-Translator: Sepehr Rasouli <sepehrrasouli06@gmail.com>, 2026\n"
1616
"Language-Team: none\n"
1717
"Language: fa\n"
1818
"MIME-Version: 1.0\n"

‎builtins/exceptions.po‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ msgstr ""
1212
"Report-Msgid-Bugs-To: \n"
1313
"POT-Creation-Date: 2026-09-19 20:08+0330\n"
1414
"PO-Revision-Date: 2026-09-19 20:08+0330\n"
15-
"Last-Translator: Automatically generated\n"
15+
"Last-Translator: Sepehr Rasouli <sepehrrasouli06@gmail.com>, 2026\n"
1616
"Language-Team: none\n"
1717
"Language: fa\n"
1818
"MIME-Version: 1.0\n"

‎builtins/functions.po‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ msgstr ""
1212
"Report-Msgid-Bugs-To: \n"
1313
"POT-Creation-Date: 2026-09-24 04:09+0000\n"
1414
"PO-Revision-Date: 2026-09-24 07:55+0330\n"
15-
"Last-Translator: Automatically generated\n"
15+
"Last-Translator: Sepehr Rasouli <sepehrrasouli06@gmail.com>, 2026\n"
1616
"Language-Team: none\n"
1717
"Language: fa\n"
1818
"MIME-Version: 1.0\n"

‎builtins/index.po‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ msgstr ""
1212
"Report-Msgid-Bugs-To: \n"
1313
"POT-Creation-Date: 2026-09-21 11:59+0000\n"
1414
"PO-Revision-Date: 2026-09-19 20:08+0330\n"
15-
"Last-Translator: Automatically generated\n"
15+
"Last-Translator: Sepehr Rasouli <sepehrrasouli06@gmail.com>, 2026\n"
1616
"Language-Team: none\n"
1717
"Language: fa\n"
1818
"MIME-Version: 1.0\n"

‎builtins/stdtypes.po‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ msgstr ""
1212
"Report-Msgid-Bugs-To: \n"
1313
"POT-Creation-Date: 2026-09-21 11:59+0000\n"
1414
"PO-Revision-Date: 2026-09-21 13:27+0330\n"
15-
"Last-Translator: Automatically generated\n"
15+
"Last-Translator: Sepehr Rasouli <sepehrrasouli06@gmail.com>, 2026\n"
1616
"Language-Team: none\n"
1717
"Language: fa\n"
1818
"MIME-Version: 1.0\n"

0 commit comments

Comments
 (0)