Scheduled Updates (Firmware, Hardware, Translations) #7285
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: Scheduled Updates (Firmware, Hardware, Translations) | |
| on: | |
| schedule: | |
| # Hourly. This job is cheap (curl + Crowdin + PR, no build) — the slow | |
| # emulator/graph work lives in scheduled-baseline.yml on a daily cron. | |
| - cron: '0 * * * *' | |
| workflow_dispatch: # Allow manual triggering | |
| jobs: | |
| update_assets: | |
| runs-on: ubuntu-24.04 | |
| if: github.repository == 'meshtastic/Meshtastic-Android' | |
| permissions: | |
| contents: write # To commit files and push branches | |
| pull-requests: write # To create pull requests | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v7.0.0 | |
| with: | |
| token: ${{ secrets.CROWDIN_GITHUB_TOKEN }} | |
| - name: Update firmware releases list | |
| id: firmware | |
| run: | | |
| firmware_file_path="androidApp/src/main/assets/firmware_releases.json" | |
| temp_firmware_file="/tmp/new_firmware_releases.json" | |
| echo "Fetching latest firmware releases..." | |
| http_code=$(curl -s -o "$temp_firmware_file" -w '%{http_code}' https://api.meshtastic.org/github/firmware/list || true) | |
| http_code="${http_code:-0}" | |
| if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then | |
| echo "::warning::Firmware API returned HTTP $http_code. Skipping firmware update." | |
| echo "status=error" >> "$GITHUB_OUTPUT" | |
| echo "detail=HTTP $http_code from firmware API" >> "$GITHUB_OUTPUT" | |
| elif ! jq empty "$temp_firmware_file" 2>/dev/null; then | |
| echo "::warning::Firmware API returned invalid JSON data. Skipping firmware update." | |
| echo "status=error" >> "$GITHUB_OUTPUT" | |
| echo "detail=Invalid JSON response from firmware API" >> "$GITHUB_OUTPUT" | |
| else | |
| if [ ! -f "$firmware_file_path" ] || ! jq --sort-keys . "$temp_firmware_file" | diff -q - <(jq --sort-keys . "$firmware_file_path"); then | |
| echo "Changes detected in firmware list or local file missing. Updating $firmware_file_path." | |
| cp "$temp_firmware_file" "$firmware_file_path" | |
| echo "status=updated" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "No changes detected in firmware list." | |
| echo "status=unchanged" >> "$GITHUB_OUTPUT" | |
| fi | |
| fi | |
| - name: Update hardware list | |
| id: hardware | |
| run: | | |
| hardware_file_path="androidApp/src/main/assets/device_hardware.json" | |
| temp_hardware_file="/tmp/new_device_hardware.json" | |
| echo "Fetching latest device hardware data..." | |
| http_code=$(curl -s -o "$temp_hardware_file" -w '%{http_code}' https://api.meshtastic.org/resource/deviceHardware || true) | |
| http_code="${http_code:-0}" | |
| if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then | |
| echo "::warning::Hardware API returned HTTP $http_code. Skipping hardware update." | |
| echo "status=error" >> "$GITHUB_OUTPUT" | |
| echo "detail=HTTP $http_code from hardware API" >> "$GITHUB_OUTPUT" | |
| elif ! jq empty "$temp_hardware_file" 2>/dev/null; then | |
| echo "::warning::Hardware API returned invalid JSON data. Skipping hardware update." | |
| echo "status=error" >> "$GITHUB_OUTPUT" | |
| echo "detail=Invalid JSON response from hardware API" >> "$GITHUB_OUTPUT" | |
| else | |
| if [ ! -f "$hardware_file_path" ] || ! jq --sort-keys . "$temp_hardware_file" | diff -q - <(jq --sort-keys . "$hardware_file_path"); then | |
| echo "Changes detected in hardware list or local file missing. Updating $hardware_file_path." | |
| cp "$temp_hardware_file" "$hardware_file_path" | |
| echo "status=updated" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "No changes detected in hardware list." | |
| echo "status=unchanged" >> "$GITHUB_OUTPUT" | |
| fi | |
| fi | |
| - name: Sync with Crowdin | |
| uses: crowdin/github-action@v2 | |
| with: | |
| base_url: 'https://meshtastic.crowdin.com/api/v2' | |
| config: 'crowdin.yml' | |
| crowdin_branch_name: 'main' | |
| upload_sources: true | |
| upload_sources_args: '--preserve-hierarchy' | |
| upload_translations: false | |
| download_translations: true | |
| download_translations_args: '--preserve-hierarchy' | |
| create_pull_request: false | |
| commit_message: 'chore(l10n): New Crowdin Translations from scheduled update' | |
| push_translations: false | |
| push_sources: false | |
| localization_branch_name: ${{ github.ref_name }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.CROWDIN_GITHUB_TOKEN }} | |
| CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} | |
| CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} | |
| - name: Fix file permissions | |
| run: sudo chown -R $USER:$USER . | |
| # Early warning for overlength store-listing translations just pulled from | |
| # Crowdin. Non-blocking on purpose: a hard failure here would abort the job | |
| # and stop the PR from being created. The hard gate is the check-metadata | |
| # job in pull-request.yml, which runs against the PR this workflow opens. | |
| - name: Check store metadata lengths | |
| continue-on-error: true | |
| run: python3 scripts/check-metadata-length.py | |
| - name: Build PR body | |
| id: pr_body | |
| run: | | |
| firmware_status="${{ steps.firmware.outputs.status }}" | |
| firmware_detail="${{ steps.firmware.outputs.detail }}" | |
| hardware_status="${{ steps.hardware.outputs.status }}" | |
| hardware_detail="${{ steps.hardware.outputs.detail }}" | |
| body="This PR includes automated updates from the scheduled workflow:" | |
| body+=$'\n' | |
| # Firmware status | |
| case "$firmware_status" in | |
| updated) body+=$'\n'"- ✅ \`firmware_releases.json\` updated from the Meshtastic API." ;; | |
| unchanged) body+=$'\n'"- ✔️ \`firmware_releases.json\` checked — no changes detected." ;; | |
| error) body+=$'\n'"- ⚠️ \`firmware_releases.json\` skipped — ${firmware_detail}." ;; | |
| *) body+=$'\n'"- ❓ \`firmware_releases.json\` — unknown status." ;; | |
| esac | |
| # Hardware status | |
| case "$hardware_status" in | |
| updated) body+=$'\n'"- ✅ \`device_hardware.json\` updated from the Meshtastic API." ;; | |
| unchanged) body+=$'\n'"- ✔️ \`device_hardware.json\` checked — no changes detected." ;; | |
| error) body+=$'\n'"- ⚠️ \`device_hardware.json\` skipped — ${hardware_detail}." ;; | |
| *) body+=$'\n'"- ❓ \`device_hardware.json\` — unknown status." ;; | |
| esac | |
| # Crowdin (always attempted) | |
| body+=$'\n'"- Source strings were uploaded to Crowdin." | |
| body+=$'\n'"- Latest translations were downloaded from Crowdin (if available)." | |
| body+=$'\n' | |
| body+=$'\n'"Please review the changes." | |
| # Write multi-line body to output | |
| { | |
| echo "content<<PREOF" | |
| echo "$body" | |
| echo "PREOF" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Create Pull Request if changes occurred | |
| uses: peter-evans/create-pull-request@v8 | |
| with: | |
| token: ${{ secrets.CROWDIN_GITHUB_TOKEN }} | |
| commit-message: | | |
| chore: Scheduled updates (Firmware, Hardware, Translations) | |
| Automated updates for: | |
| - Firmware releases list | |
| - Device hardware list | |
| - Crowdin source string uploads | |
| - Crowdin translation downloads | |
| title: 'chore: Scheduled updates (Firmware, Hardware, Translations)' | |
| body: ${{ steps.pr_body.outputs.content }} | |
| branch: 'scheduled-updates' | |
| base: 'main' | |
| delete-branch: true | |
| add-paths: | | |
| androidApp/src/main/assets/firmware_releases.json | |
| androidApp/src/main/assets/device_hardware.json | |
| fastlane/metadata/android/** | |
| **/strings.xml | |
| docs/**/*.md | |
| labels: | | |
| automation | |
| l10n | |
| firmware | |
| hardware |