Skip to content

Commit 1aca600

Browse files
committed
Don't upload locales again if the version hasn't changed
1 parent 7a46b95 commit 1aca600

2 files changed

Lines changed: 92 additions & 32 deletions

File tree

.github/workflows/upload-locales.yml

Lines changed: 81 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,80 @@ jobs:
2626
- name: Checkout
2727
uses: actions/checkout@v4
2828

29+
# Read the data version directly from the on-disk version
30+
# files before doing any expensive work. The version is
31+
# derived from `priv/localize/version` (CLDR release) and
32+
# `priv/localize/localize_patch_version` (Localize patch
33+
# counter). No Elixir compile is required for this step.
34+
- name: Read data version
35+
id: version
36+
run: |
37+
cldr_version=$(cat priv/localize/version | tr -d '[:space:]')
38+
patch_raw=$(cat priv/localize/localize_patch_version | tr -d '[:space:]')
39+
# `localize_patch_version` is stored as "{cldr_version}:{patch}".
40+
# If the recorded CLDR version matches the current one, take
41+
# the numeric patch; otherwise treat the patch as 0.
42+
recorded_cldr="${patch_raw%%:*}"
43+
recorded_patch="${patch_raw##*:}"
44+
if [ "${recorded_cldr}" = "${cldr_version}" ]; then
45+
patch_version="${recorded_patch}"
46+
else
47+
patch_version="0"
48+
fi
49+
data_version="v${cldr_version}.${patch_version}"
50+
echo "data_version=${data_version}" >> "$GITHUB_OUTPUT"
51+
echo "Data version: ${data_version}"
52+
53+
- name: Install rclone
54+
run: |
55+
curl -fsSL https://rclone.org/install.sh | sudo bash
56+
57+
- name: Configure rclone for Cloudflare R2
58+
env:
59+
R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
60+
R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
61+
R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
62+
run: |
63+
mkdir -p ~/.config/rclone
64+
cat > ~/.config/rclone/rclone.conf << EOF
65+
[r2]
66+
type = s3
67+
provider = Cloudflare
68+
access_key_id = ${R2_ACCESS_KEY_ID}
69+
secret_access_key = ${R2_SECRET_ACCESS_KEY}
70+
endpoint = https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com
71+
acl = private
72+
no_check_bucket = true
73+
EOF
74+
75+
# Short-circuit: if the target R2 prefix already contains ETF
76+
# files for this data_version, there is nothing to do. This
77+
# avoids re-generating and re-uploading the same data when a
78+
# release tag is pushed without a corresponding CLDR or patch
79+
# version bump.
80+
- name: Check if data version already exists on R2
81+
id: check_existing
82+
env:
83+
DATA_VERSION: ${{ steps.version.outputs.data_version }}
84+
run: |
85+
existing=$(rclone lsf "r2:${R2_BUCKET}/${DATA_VERSION}/" --include "*.etf" 2>/dev/null | wc -l | tr -d '[:space:]')
86+
echo "Found ${existing} existing ETF file(s) at r2:${R2_BUCKET}/${DATA_VERSION}/"
87+
if [ "${existing}" -gt 0 ]; then
88+
echo "skip=true" >> "$GITHUB_OUTPUT"
89+
echo "::notice::Data version ${DATA_VERSION} already exists on R2 with ${existing} file(s); skipping generation and upload."
90+
else
91+
echo "skip=false" >> "$GITHUB_OUTPUT"
92+
fi
93+
2994
- name: Set up Elixir
95+
if: steps.check_existing.outputs.skip != 'true'
3096
uses: erlef/setup-beam@v1
3197
with:
3298
elixir-version: "1.19"
3399
otp-version: "28"
34100

35101
- name: Restore dependency cache
102+
if: steps.check_existing.outputs.skip != 'true'
36103
uses: actions/cache@v4
37104
with:
38105
path: |
@@ -43,24 +110,19 @@ jobs:
43110
mix-locales-
44111
45112
- name: Install dependencies
113+
if: steps.check_existing.outputs.skip != 'true'
46114
run: mix deps.get
47115

48116
- name: Compile
117+
if: steps.check_existing.outputs.skip != 'true'
49118
run: mix compile
50119

51120
- name: Generate locale ETFs
121+
if: steps.check_existing.outputs.skip != 'true'
52122
run: mix localize.generate_locales
53123

54-
- name: Read data version
55-
id: version
56-
run: |
57-
cldr_version=$(cat priv/localize/version | tr -d '[:space:]')
58-
patch_version=$(cat priv/localize/localize_patch_version | tr -d '[:space:]')
59-
data_version="v${cldr_version}.${patch_version}"
60-
echo "data_version=${data_version}" >> "$GITHUB_OUTPUT"
61-
echo "Data version: ${data_version}"
62-
63124
- name: Verify generated locales
125+
if: steps.check_existing.outputs.skip != 'true'
64126
run: |
65127
count=$(ls priv/localize/locales/*.etf 2>/dev/null | wc -l)
66128
echo "Generated ${count} locale ETF files"
@@ -69,29 +131,8 @@ jobs:
69131
exit 1
70132
fi
71133
72-
- name: Install rclone
73-
run: |
74-
curl -fsSL https://rclone.org/install.sh | sudo bash
75-
76-
- name: Configure rclone for Cloudflare R2
77-
env:
78-
R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
79-
R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
80-
R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
81-
run: |
82-
mkdir -p ~/.config/rclone
83-
cat > ~/.config/rclone/rclone.conf << EOF
84-
[r2]
85-
type = s3
86-
provider = Cloudflare
87-
access_key_id = ${R2_ACCESS_KEY_ID}
88-
secret_access_key = ${R2_SECRET_ACCESS_KEY}
89-
endpoint = https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com
90-
acl = private
91-
no_check_bucket = true
92-
EOF
93-
94134
- name: Upload locales to R2
135+
if: steps.check_existing.outputs.skip != 'true'
95136
env:
96137
DATA_VERSION: ${{ steps.version.outputs.data_version }}
97138
run: |
@@ -115,6 +156,7 @@ jobs:
115156
--verbose
116157
117158
- name: Verify upload
159+
if: steps.check_existing.outputs.skip != 'true'
118160
env:
119161
DATA_VERSION: ${{ steps.version.outputs.data_version }}
120162
run: |
@@ -125,3 +167,11 @@ jobs:
125167
echo "::warning::Upload count mismatch: ${uploaded} uploaded vs ${local_count} local"
126168
fi
127169
echo "Upload complete: ${uploaded} locale files to ${R2_BUCKET}/${DATA_VERSION}/"
170+
171+
- name: Skipped summary
172+
if: steps.check_existing.outputs.skip == 'true'
173+
env:
174+
DATA_VERSION: ${{ steps.version.outputs.data_version }}
175+
run: |
176+
echo "Skipped: data version ${DATA_VERSION} already present on R2 at ${R2_BUCKET}/${DATA_VERSION}/"
177+
echo "Nothing was regenerated or uploaded. Bump the CLDR or Localize patch version and push a new tag to trigger a real upload."

DEVELOPMENT.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,17 @@ Two GitHub Actions workflows live in `.github/workflows/`:
438438

439439
* `ci.yml` — runs `mix test`, `mix format --check-formatted`, and `mix dialyzer` against a matrix of Elixir/OTP versions on every PR and push.
440440

441-
* `upload-locales.yml` — regenerates all 766 locale ETFs and uploads them to Cloudflare R2 (the CDN behind `https://elixir-localize.com/locales`). Triggered on pushes to `main`. Crucially, this workflow does **not** bump the patch version — `mix localize.generate_locales` no longer auto-bumps for exactly this reason.
441+
* `upload-locales.yml` — regenerates all 766 locale ETFs and uploads them to Cloudflare R2 (the CDN behind `https://elixir-localize.com/locales`). Triggered on pushes of `v*` tags. The workflow:
442+
443+
1. Reads the current `data_version` (e.g. `v48.2.1`) directly from `priv/localize/version` and `priv/localize/localize_patch_version` before any compile or generation.
444+
445+
2. Configures `rclone` for R2 and checks whether the target prefix `r2:locales/{data_version}/` already contains ETF files.
446+
447+
3. If the prefix is already populated, the workflow logs a notice and **skips the Elixir setup, compile, generate, and upload steps entirely** — nothing is regenerated or re-uploaded.
448+
449+
4. If the prefix is empty, the workflow sets up Elixir, runs `mix localize.generate_locales`, uploads via `rclone sync`, and verifies the upload count.
450+
451+
This short-circuit exists so that release tags can be re-pushed or re-applied (for example to trigger a Hex publish retry) without accidentally overwriting data that is already live on the CDN. The only way to publish a new set of ETFs is to bump either the CLDR version or the Localize patch counter (via `mix localize.bump_patch_version`) and then tag the commit. `mix localize.generate_locales` itself does not bump the patch — for exactly this reason.
442452

443453
## Release process
444454

0 commit comments

Comments
 (0)