Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
1e7b024
feat(pos-app): add production OTA update support
ignaciosantise Mar 3, 2026
c2abfec
fix(pos-app): defer OTA apply and pin artifact action
ignaciosantise Mar 3, 2026
b10d931
Merge branch 'main' into feat/ota-updates
ignaciosantise Mar 3, 2026
4e6a780
fix(pos-app): switch static icons to require sources
ignaciosantise Mar 3, 2026
8951758
fix(pos-app): restore expo-asset preload and asset config
ignaciosantise Mar 4, 2026
7202028
fix(pos-app): restore expo-asset plugin and patch expo-updates env lo…
ignaciosantise Mar 4, 2026
241e712
Merge branch 'main' into feat/ota-updates
ignaciosantise Mar 4, 2026
e5f9847
fix(ci): extract fingerprint hash and safely pass values to shell
ignaciosantise Mar 4, 2026
1a1d9de
refactor(ci): use EAS fingerprint API instead of artifact-based compa…
ignaciosantise Mar 4, 2026
b1ce956
fix(ci): handle non-JSON output from eas build:list
ignaciosantise Mar 4, 2026
c07ae1a
chore(pos-app): add EAS project ID to app.json
ignaciosantise Mar 4, 2026
f5d3587
revert(ci): restore artifact-based fingerprint comparison
ignaciosantise Mar 4, 2026
073674d
refactor(ci): store native fingerprints in git branch instead of arti…
ignaciosantise Mar 4, 2026
91b26d2
fix(ci): grant contents:write to all caller workflows
ignaciosantise Mar 4, 2026
d9cd36c
fix(pos-app): enable expo-updates config and harden fingerprint push
ignaciosantise Jun 9, 2026
ec098a1
Merge remote-tracking branch 'origin/main' into feat/ota-updates
ignaciosantise Jun 9, 2026
0f26516
fix(pos-app): pin expo-updates-interface to 55.1.3 for expo-updates c…
ignaciosantise Jun 9, 2026
1fed1a5
chore(pos-app): bump to Expo SDK 55.0.26 (latest 55) and align deps
ignaciosantise Jun 9, 2026
55c6b74
fix(pos-app): add --environment to eas update for SDK 55+
ignaciosantise Jun 9, 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
150 changes: 146 additions & 4 deletions .github/workflows/ota-update-pos.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,155 @@
name: OTA Update Mobile POS
run-name: "Mobile POS OTA - production"

permissions: {}
permissions:
id-token: write
contents: read

on:
workflow_dispatch:
inputs:
message:
description: 'Update message (shown in EAS dashboard)'
required: false
type: string
default: ''

jobs:
placeholder:
publish-update:
runs-on: ubuntu-latest
steps:
- name: Echo placeholder
run: echo "OTA Update Mobile POS placeholder workflow"
- name: Checkout
uses: actions/checkout@v4

- name: Setup
uses: ./.github/actions/ci-setup
with:
root-path: dapps/pos-app
package-manager: npm

- name: Create env file
run: |
if [ -z "${{ secrets.POS_ENV_FILE }}" ]; then
echo "Error: POS_ENV_FILE secret is empty or not set"
exit 1
fi
echo "${{ secrets.POS_ENV_FILE }}" > dapps/pos-app/.env

- name: Compute current fingerprints
id: fingerprints
run: |
cd dapps/pos-app
ANDROID_FINGERPRINT=$(npx expo-updates fingerprint:generate --platform android 2>/dev/null | tail -1 | jq -r '.hash')
IOS_FINGERPRINT=$(npx expo-updates fingerprint:generate --platform ios 2>/dev/null | tail -1 | jq -r '.hash')
echo "android=$ANDROID_FINGERPRINT" >> "$GITHUB_OUTPUT"
echo "ios=$IOS_FINGERPRINT" >> "$GITHUB_OUTPUT"
echo "Current Android fingerprint: $ANDROID_FINGERPRINT"
echo "Current iOS fingerprint: $IOS_FINGERPRINT"

- name: Fetch last native build fingerprints
run: |
git fetch origin fingerprints-dont-remove --depth=1 2>/dev/null || true
git show origin/fingerprints-dont-remove:native-fingerprints/production/android.txt > /tmp/native-fingerprint-android.txt 2>/dev/null || true
git show origin/fingerprints-dont-remove:native-fingerprints/production/ios.txt > /tmp/native-fingerprint-ios.txt 2>/dev/null || true

- name: Check for native changes
id: native-check
env:
CURRENT_ANDROID_FINGERPRINT: ${{ steps.fingerprints.outputs.android }}
CURRENT_IOS_FINGERPRINT: ${{ steps.fingerprints.outputs.ios }}
run: |
HAS_NATIVE_CHANGES=false

ANDROID_FINGERPRINT_PATH=/tmp/native-fingerprint-android.txt
IOS_FINGERPRINT_PATH=/tmp/native-fingerprint-ios.txt

if [ -s "$ANDROID_FINGERPRINT_PATH" ]; then
LAST_ANDROID_FINGERPRINT=$(cat "$ANDROID_FINGERPRINT_PATH")
echo "Last native Android fingerprint: $LAST_ANDROID_FINGERPRINT"
echo "Current Android fingerprint: $CURRENT_ANDROID_FINGERPRINT"

if [ "$LAST_ANDROID_FINGERPRINT" != "$CURRENT_ANDROID_FINGERPRINT" ]; then
HAS_NATIVE_CHANGES=true
echo "::error::Android native changes detected. Current fingerprint does not match the last native Android build."
fi
else
echo "No previous native Android fingerprint found for channel 'production'."
fi

if [ -s "$IOS_FINGERPRINT_PATH" ]; then
LAST_IOS_FINGERPRINT=$(cat "$IOS_FINGERPRINT_PATH")
echo "Last native iOS fingerprint: $LAST_IOS_FINGERPRINT"
echo "Current iOS fingerprint: $CURRENT_IOS_FINGERPRINT"

if [ "$LAST_IOS_FINGERPRINT" != "$CURRENT_IOS_FINGERPRINT" ]; then
HAS_NATIVE_CHANGES=true
echo "::error::iOS native changes detected. Current fingerprint does not match the last native iOS build."
fi
else
echo "No previous native iOS fingerprint found for channel 'production'."
fi

if [ "$HAS_NATIVE_CHANGES" = "true" ]; then
echo "has_native_changes=true" >> "$GITHUB_OUTPUT"
echo "::error::Native changes detected. You must create a new native release before publishing an OTA update."
exit 1
fi

if [ ! -s "$ANDROID_FINGERPRINT_PATH" ] || [ ! -s "$IOS_FINGERPRINT_PATH" ]; then
echo "At least one platform fingerprint is missing. This can happen after initial OTA setup."
echo "Proceeding with OTA publish."
fi

echo "has_native_changes=false" >> "$GITHUB_OUTPUT"
echo "Fingerprints match — safe to publish OTA update."

- name: Setup EAS CLI
run: npm install -g eas-cli

- name: Publish OTA update
id: eas-update
working-directory: dapps/pos-app
env:
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
run: |
eas update \
--channel production \
--environment production \
--message "${{ inputs.message || format('OTA update from {0}', github.ref_name) }}" \
--non-interactive

- name: Send Slack notification
if: always() && !cancelled()
uses: slackapi/slack-github-action@v2.1.0
with:
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
webhook-type: incoming-webhook
payload: |
{
"text": "OTA Update Report - Mobile POS",
"blocks": [
{
"type": "header",
"text": { "type": "plain_text", "text": "📦 OTA Update Report - Mobile POS" }
},
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": "*Channel:*\n`production`" },
{ "type": "mrkdwn", "text": "*Branch:*\n`${{ github.ref_name }}`" },
{ "type": "mrkdwn", "text": "*Status:*\n`${{ steps.native-check.outputs.has_native_changes == 'true' && '❌ Blocked — native changes require full release' || (steps.eas-update.outcome == 'success' && '✅ Published' || '❌ Failed') }}`" },
{ "type": "mrkdwn", "text": "*Message:*\n`${{ inputs.message || 'No message' }}`" }
]
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": { "type": "plain_text", "text": "View Workflow Run" },
"url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}
]
}
]
}
57 changes: 56 additions & 1 deletion .github/workflows/release-android-base.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: release-android-base

permissions:
id-token: write
contents: read
contents: write

on:
workflow_call:
Expand Down Expand Up @@ -46,6 +46,11 @@ on:
description: "Firebase App ID for distribution"
required: true
type: string
eas-update-channel:
description: "EAS Update channel to embed in the native build (leave empty for non-OTA apps)"
required: false
default: ''
type: string
secrets:
gsa-key:
required: true
Expand Down Expand Up @@ -86,6 +91,56 @@ jobs:
cd ${{ inputs.root-path }}
npx expo prebuild --platform android

- name: Save native fingerprint
if: ${{ inputs.eas-update-channel != '' }}
env:
CHANNEL: ${{ inputs.eas-update-channel }}
run: |
cd ${{ inputs.root-path }}
FINGERPRINT=$(npx expo-updates fingerprint:generate --platform android 2>/dev/null | tail -1 | jq -r '.hash')
echo "Native fingerprint (Android): $FINGERPRINT"

cd "$GITHUB_WORKSPACE"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

# Android and iOS jobs push to the same branch concurrently, so re-base
# on the latest remote state and retry to avoid non-fast-forward failures.
pushed=false
for attempt in 1 2 3 4 5; do
git fetch origin fingerprints-dont-remove 2>/dev/null || true
if git show-ref --verify --quiet refs/remotes/origin/fingerprints-dont-remove; then
git checkout -B fingerprints-dont-remove origin/fingerprints-dont-remove
else
git checkout --orphan fingerprints-dont-remove
git rm -rf --cached . >/dev/null 2>&1 || true
fi

mkdir -p "native-fingerprints/$CHANNEL"
echo "$FINGERPRINT" > "native-fingerprints/$CHANNEL/android.txt"
git add native-fingerprints/

if git diff --cached --quiet; then
echo "Android fingerprint unchanged — nothing to push."
pushed=true
break
fi

git commit -m "Update Android native fingerprint ($CHANNEL)"
if git push origin fingerprints-dont-remove; then
echo "Pushed Android fingerprint (attempt $attempt)."
pushed=true
break
fi
echo "Push rejected (attempt $attempt) — retrying after rebase."
sleep $((attempt * 3))
done

if [ "$pushed" != "true" ]; then
echo "::error::Failed to push Android native fingerprint after retries."
exit 1
fi

- name: Install Java 17
uses: actions/setup-java@v3
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-appkit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ run-name: "AppKit - ${{ inputs.platform == 'both' && '🍎 iOS & 🤖 Android' |

permissions:
id-token: write
contents: read
contents: write

on:
workflow_dispatch:
Expand Down
57 changes: 56 additions & 1 deletion .github/workflows/release-ios-base.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: release-ios-base

permissions:
id-token: write
contents: read
contents: write

on:
workflow_call:
Expand Down Expand Up @@ -58,6 +58,11 @@ on:
required: false
default: false
type: boolean
eas-update-channel:
description: "EAS Update channel to embed in the native build (leave empty for non-OTA apps)"
required: false
default: ''
type: string
secrets:
sentry-file:
required: true
Expand Down Expand Up @@ -122,6 +127,56 @@ jobs:
cd ${{ inputs.root-path }}
npx expo prebuild --platform ios

- name: Save native fingerprint
if: ${{ inputs.eas-update-channel != '' }}
env:
CHANNEL: ${{ inputs.eas-update-channel }}
run: |
cd ${{ inputs.root-path }}
FINGERPRINT=$(npx expo-updates fingerprint:generate --platform ios 2>/dev/null | tail -1 | jq -r '.hash')
echo "Native fingerprint (iOS): $FINGERPRINT"

cd "$GITHUB_WORKSPACE"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

# Android and iOS jobs push to the same branch concurrently, so re-base
# on the latest remote state and retry to avoid non-fast-forward failures.
pushed=false
for attempt in 1 2 3 4 5; do
git fetch origin fingerprints-dont-remove 2>/dev/null || true
if git show-ref --verify --quiet refs/remotes/origin/fingerprints-dont-remove; then
git checkout -B fingerprints-dont-remove origin/fingerprints-dont-remove
else
git checkout --orphan fingerprints-dont-remove
git rm -rf --cached . >/dev/null 2>&1 || true
fi

mkdir -p "native-fingerprints/$CHANNEL"
echo "$FINGERPRINT" > "native-fingerprints/$CHANNEL/ios.txt"
git add native-fingerprints/

if git diff --cached --quiet; then
echo "iOS fingerprint unchanged — nothing to push."
pushed=true
break
fi

git commit -m "Update iOS native fingerprint ($CHANNEL)"
if git push origin fingerprints-dont-remove; then
echo "Pushed iOS fingerprint (attempt $attempt)."
pushed=true
break
fi
echo "Push rejected (attempt $attempt) — retrying after rebase."
sleep $((attempt * 3))
done

if [ "$pushed" != "true" ]; then
echo "::error::Failed to push iOS native fingerprint after retries."
exit 1
fi

- name: Set Xcode paths
run: |
# Find the .xcodeproj and .xcworkspace (works for both Expo and non-Expo)
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-pos-poc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ run-name: "Mobile POS (PoC) - ${{ inputs.platform == 'both' && '🍎 iOS & 🤖

permissions:
id-token: write
contents: read
contents: write

on:
workflow_dispatch:
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/release-pos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ run-name: "Mobile POS - ${{ inputs.platform == 'both' && '🍎 iOS & 🤖 Androi

permissions:
id-token: write
contents: read
contents: write

on:
workflow_dispatch:
Expand Down Expand Up @@ -33,6 +33,7 @@ jobs:
package-manager: 'npm'
is-expo-project: true
firebase-app-id: ${{ vars.POS_ANDROID_FIREBASE_APP_ID }}
eas-update-channel: 'production'
secrets:
env-file: ${{ secrets.POS_ENV_FILE }}
sentry-file: ${{ secrets.POS_SENTRY_FILE }}
Expand All @@ -58,6 +59,7 @@ jobs:
package-manager: 'npm'
testflight-groups: 'External'
is-expo-project: true
eas-update-channel: 'production'
secrets:
env-file: ${{ secrets.POS_ENV_FILE }}
sentry-file: ${{ secrets.POS_SENTRY_FILE }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-walletkit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ run-name: "WalletKit - ${{ inputs.platform == 'both' && '🍎 iOS & 🤖 Android

permissions:
id-token: write
contents: read
contents: write

on:
workflow_dispatch:
Expand Down
Loading