Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
b6f7dc1
✨ rates: make Coinbase an optional provider
DimaMishchenko Oct 9, 2026
1e3b221
✅ e2e: make provider navigation checks precise
DimaMishchenko Oct 9, 2026
0140385
✅ widgets: isolate installed display fixtures
DimaMishchenko Oct 9, 2026
8490091
♻️ rates: use a code-level Coinbase flag
DimaMishchenko Oct 10, 2026
6cd064e
✨ rates: replace Coinbase with Coin Metrics
DimaMishchenko Oct 15, 2026
653281f
🔧 ci: sync main workflow updates
DimaMishchenko Oct 15, 2026
2264995
🐛 rates: finish reference-price validation
DimaMishchenko Oct 15, 2026
ad46d95
♻️ rates: make Coin Metrics the standard provider
DimaMishchenko Oct 15, 2026
e199c7a
✅ history: validate the converted widget chart
DimaMishchenko Oct 15, 2026
3d926fb
🐛 history: preserve full-day chart caches
DimaMishchenko Oct 15, 2026
102ac8c
✅ history: keep chart fixtures inside their cache window
DimaMishchenko Oct 15, 2026
b1d4eda
🐛 widgets: simplify history harness fixture inference
DimaMishchenko Oct 15, 2026
ec35c55
✨ rates: refresh archives and clarify conversion notices
DimaMishchenko Oct 15, 2026
80a1194
✅ history: verify live generation before merge
DimaMishchenko Oct 15, 2026
5f679c3
🐛 history: use documented source client and fix navigator coverage
DimaMishchenko Oct 15, 2026
496b4cb
📝 sources: simplify Frankfurter documentation
DimaMishchenko Oct 15, 2026
a425768
🔧 history: run archive refresh only on schedule
DimaMishchenko Oct 15, 2026
0abf227
♻️ rates: remove obsolete provider modes and cache migrations
DimaMishchenko Oct 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .github/workflows/history-refresh.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Refresh bundled history

on:
schedule:
- cron: '0 6 1 * *'

permissions:
contents: read

concurrency:
group: currency-history-refresh
cancel-in-progress: false

jobs:
generate:
if: github.ref == 'refs/heads/main' && github.event_name == 'schedule'
runs-on: ubuntu-latest
timeout-minutes: 30
outputs:
changed: ${{ steps.generate.outputs.changed }}
base_sha: ${{ steps.generate.outputs.base_sha }}
steps:
- uses: actions/checkout@v7
with:
ref: main
persist-credentials: false
- name: Test archive generation
run: python3 -m unittest discover -s Scripts/History -p 'test_*.py'
- name: Refresh selected history and provenance
id: generate
run: |
echo "base_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
python3 Scripts/History/generate_archive.py
- uses: actions/upload-artifact@v7
if: steps.generate.outputs.changed == 'true'
with:
name: currency-history-refresh
path: Domain/ExchangeRates/Sources/ExchangeRates/Resources/history-monthly-v1.json
if-no-files-found: error
retention-days: 7
propose:
needs: generate
if: >-
github.ref == 'refs/heads/main' &&
github.event_name == 'schedule' &&
needs.generate.outputs.changed == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v7
with:
ref: main
fetch-depth: 0
persist-credentials: false
- uses: actions/download-artifact@v8
with:
name: currency-history-refresh
path: ${{ runner.temp }}/currency-history-refresh
- name: Update the dedicated review branch
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
BASE_SHA: ${{ needs.generate.outputs.base_sha }}
run: >-
python3 Scripts/History/propose_refresh.py
--candidate "$RUNNER_TEMP/currency-history-refresh/history-monthly-v1.json"
2 changes: 2 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ jobs:
run: |
python3 Scripts/CI/test_skip_rules.py
python3 Scripts/CI/test_project_structure.py
- name: Test bundled-history generation
run: python3 -m unittest discover -s Scripts/History -p 'test_*.py'
- uses: actions/setup-node@v7
with:
node-version: 24
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ xcuserdata/
Tuist/Dependencies/

.validation/

__pycache__/
267 changes: 0 additions & 267 deletions AppExtensions/CurrencyWatchWidgets/Resources/WatchWidgets.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -2938,95 +2938,6 @@
}
}
},
"hourlyCloses": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Completed hourly closes · UTC"
}
},
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "已完成的小时收盘价 · UTC"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "確定した時間足終値 · UTC"
}
},
"es": {
"stringUnit": {
"state": "translated",
"value": "Cierres horarios completados · UTC"
}
},
"de": {
"stringUnit": {
"state": "translated",
"value": "Abgeschlossene Stundenkurse · UTC"
}
},
"fr": {
"stringUnit": {
"state": "translated",
"value": "Clôtures horaires terminées · UTC"
}
},
"pt-BR": {
"stringUnit": {
"state": "translated",
"value": "Fechamentos horários concluídos · UTC"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "완료된 시간별 종가 · UTC"
}
},
"zh-Hant": {
"stringUnit": {
"state": "translated",
"value": "已完成的小時收盤價 · UTC"
}
},
"it": {
"stringUnit": {
"state": "translated",
"value": "Chiusure orarie completate · UTC"
}
},
"tr": {
"stringUnit": {
"state": "translated",
"value": "Tamamlanan saatlik kapanışlar · UTC"
}
},
"ru": {
"stringUnit": {
"state": "translated",
"value": "Завершённые часовые закрытия · UTC"
}
},
"uk": {
"stringUnit": {
"state": "translated",
"value": "Завершені годинні закриття · UTC"
}
},
"et": {
"stringUnit": {
"state": "translated",
"value": "Lõppenud tundide sulgemishinnad · UTC"
}
}
}
},
"referenceHistory": {
"extractionState": "manual",
"localizations": {
Expand Down Expand Up @@ -4807,184 +4718,6 @@
}
}
},
"dailyCloses": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Daily closes · UTC"
}
},
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "每日收盘价 · UTC"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "日足終値 · UTC"
}
},
"es": {
"stringUnit": {
"state": "translated",
"value": "Cierres diarios · UTC"
}
},
"de": {
"stringUnit": {
"state": "translated",
"value": "Tagesschlusskurse · UTC"
}
},
"fr": {
"stringUnit": {
"state": "translated",
"value": "Clôtures quotidiennes · UTC"
}
},
"pt-BR": {
"stringUnit": {
"state": "translated",
"value": "Fechamentos diários · UTC"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "일별 종가 · UTC"
}
},
"zh-Hant": {
"stringUnit": {
"state": "translated",
"value": "每日收盤價 · UTC"
}
},
"it": {
"stringUnit": {
"state": "translated",
"value": "Chiusure giornaliere · UTC"
}
},
"tr": {
"stringUnit": {
"state": "translated",
"value": "Günlük kapanışlar · UTC"
}
},
"ru": {
"stringUnit": {
"state": "translated",
"value": "Дневные закрытия · UTC"
}
},
"uk": {
"stringUnit": {
"state": "translated",
"value": "Денні закриття · UTC"
}
},
"et": {
"stringUnit": {
"state": "translated",
"value": "Päeva sulgemishinnad · UTC"
}
}
}
},
"monthlyCloses": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Monthly closes · UTC"
}
},
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "每月收盘价 · UTC"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "月足終値 · UTC"
}
},
"es": {
"stringUnit": {
"state": "translated",
"value": "Cierres mensuales · UTC"
}
},
"de": {
"stringUnit": {
"state": "translated",
"value": "Monatsschlusskurse · UTC"
}
},
"fr": {
"stringUnit": {
"state": "translated",
"value": "Clôtures mensuelles · UTC"
}
},
"pt-BR": {
"stringUnit": {
"state": "translated",
"value": "Fechamentos mensais · UTC"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "월별 종가 · UTC"
}
},
"zh-Hant": {
"stringUnit": {
"state": "translated",
"value": "每月收盤價 · UTC"
}
},
"it": {
"stringUnit": {
"state": "translated",
"value": "Chiusure mensili · UTC"
}
},
"tr": {
"stringUnit": {
"state": "translated",
"value": "Aylık kapanışlar · UTC"
}
},
"ru": {
"stringUnit": {
"state": "translated",
"value": "Месячные закрытия · UTC"
}
},
"uk": {
"stringUnit": {
"state": "translated",
"value": "Місячні закриття · UTC"
}
},
"et": {
"stringUnit": {
"state": "translated",
"value": "Kuu sulgemishinnad · UTC"
}
}
}
},
"monthlyReference": {
"extractionState": "manual",
"localizations": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import AppIntents
import Conversion
import CurrencyApplication
import ExchangeRates
import Foundation
import WidgetKit
Expand Down Expand Up @@ -68,7 +69,8 @@ struct WatchWidgetSwapIntent: AppIntent {
func perform() async throws -> some IntentResult {
guard codes.count >= 2 else { return .result() }
let directory = WatchWidgetAppGroup.directory()
let rates = RateStore(directory: directory).loadRates()
let rates = RateStore(directory: directory)
.loadRates()
try WidgetStore(directory: directory)
.updateWidgetInput(
key: key, codes: codes, amount: initialAmount
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import AppIntents
import Conversion
import CurrencyApplication
import ExchangeRates
import Foundation
import Widgets
Expand Down
Loading
Loading