Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions .depcheckrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ ignores:
- 'esbuild-register'
# tsx runs all scripts/tooling/*.ts files directly (CLI wrapper, MCP server, yarn pre/post hooks, report CLI)
- 'tsx'
# agent-device is used as a CLI (`yarn agent-device`), not imported
- 'agent-device'
# xml2js is used in .github/scripts/ for E2E test report processing
- 'xml2js'
# jest-junit is used as a Jest reporter in tests/jest.e2e.detox.config.js
Expand Down
36 changes: 19 additions & 17 deletions .github/workflows/rerun-ci-on-skipped-e2e-labels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,40 +61,42 @@ jobs:
echo "run_id=$LATEST_RUN_ID" >> "$GITHUB_OUTPUT"

- name: Wait for cancellation to complete
if: steps.cancel.outputs.cancelled == 'true' && steps.find.outputs.run_id
if: steps.cancel.outputs.cancelled == 'true'
run: |
RUN_ID="${{ steps.find.outputs.run_id }}"
MAX_WAIT=600
ELAPSED=0
IN_PROGRESS=1

echo "Waiting up to ${MAX_WAIT}s for workflow to finish cancelling..."
echo "Waiting up to ${MAX_WAIT}s for all CI runs to finish cancelling..."

while [ $ELAPSED -lt $MAX_WAIT ]; do
STATUS=$(gh run view "$RUN_ID" --repo "$REPO" --json status --jq '.status')
echo "Status: $STATUS (${ELAPSED}s elapsed)"
IN_PROGRESS=$(gh run list \
--repo "$REPO" \
--branch "$HEAD_REF" \
--workflow "ci.yml" \
--json databaseId,status \
--jq '[.[] | select(.status == "in_progress" or .status == "queued")] | length')

echo "In-progress/queued runs: $IN_PROGRESS (${ELAPSED}s elapsed)"

if [ "$STATUS" != "in_progress" ] && [ "$STATUS" != "queued" ]; then
echo "Workflow ready for rerun"
if [ "$IN_PROGRESS" -eq 0 ]; then
echo "No active runs remaining — ready to rerun"
break
fi

sleep 15
ELAPSED=$((ELAPSED + 15))
done

FINAL_STATUS=$(gh run view "$RUN_ID" --repo "$REPO" --json status --jq '.status')
if [ "$FINAL_STATUS" = "in_progress" ] || [ "$FINAL_STATUS" = "queued" ]; then
echo "Timeout: workflow still $FINAL_STATUS after ${MAX_WAIT}s"
if [ "$IN_PROGRESS" -gt 0 ]; then
echo "Timeout: $IN_PROGRESS run(s) still active after ${MAX_WAIT}s"
exit 1
fi

- name: Rerun CI workflow
if: steps.find.outputs.run_id
if: github.event.pull_request.state == 'open' && steps.find.outputs.run_id
run: |
RUN_ID="${{ steps.find.outputs.run_id }}"
echo "Re-running workflow $RUN_ID..."
if gh run rerun "$RUN_ID" --repo "$REPO"; then
echo "CI workflow re-triggered successfully"
else
echo "Rerun not possible (run may not be in a retriable state)"
fi
echo "Re-running CI workflow run $RUN_ID..."
gh run rerun "$RUN_ID" --repo "$REPO"
echo "CI workflow re-triggered successfully"
14 changes: 13 additions & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,10 @@ def jscFlavor = 'org.webkit:android-jsc:+'
*/
def reactNativeArchitectures() {
def value = project.getProperties().get("reactNativeArchitectures")
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
if (value) {
return value.split(",").toList()
}
return ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
}


Expand Down Expand Up @@ -191,6 +194,15 @@ android {
resValue "string", "com_braze_api_key", "${System.env.MM_BRAZE_API_KEY_ANDROID ?: ''}"
resValue "string", "com_braze_custom_endpoint", "${System.env.MM_BRAZE_SDK_ENDPOINT ?: ''}"

ndk {
// Restrict packaged .so files (including those pulled from third-party AARs
// like Facebook Conceal and react-native-fast-crypto) to the ABIs listed in
// reactNativeArchitectures. Without this, AGP packages every ABI shipped in
// dependency AARs regardless, which is what put x86_64 libconceal.so and
// libsecp256k1.so into the AAB and triggered Play's 16 KB alignment warning.
abiFilters(*reactNativeArchitectures())
}

// Explicitly specify supported languages for the app, ensuring the app locales are valid when uploading to the Play Store
resourceConfigurations += ['en', 'de', 'el', 'es', 'fr', 'hi', 'id', 'ja', 'ko', 'pt', 'ru', 'tl', 'tr', 'vi', 'zh']
}
Expand Down
9 changes: 7 additions & 2 deletions android/gradle.properties.release
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,13 @@ android.enableJetifier=true
# Enable AAPT2 PNG crunching
android.enablePngCrunchInReleaseBuilds=true

# ALL architectures for Play Store distribution (differs from E2E which uses x86_64 only)
reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
# Play Store distribution architectures. x86_64 is excluded because the
# AAR-bundled libconceal.so (react-native-keychain) and libsecp256k1.so
# (react-native-fast-crypto) ship 4 KB-aligned x86_64 binaries that fail
# Play's 16 KB page-size check. No real phone uses x86_64 (Chromebooks/
# emulators only), so dropping it silences the warning without affecting
# users. Enforced at packaging time via ndk.abiFilters in app/build.gradle.
reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86

# New Architecture + Hermes
newArchEnabled=true
Expand Down
2 changes: 2 additions & 0 deletions app/components/Nav/Main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import ProtectYourWalletModal from '../../UI/ProtectYourWalletModal';
import MainNavigator from './MainNavigator';
import { query } from '@metamask/controller-utils';
import EarnTransactionMonitor from '../../UI/Earn/components/EarnTransactionMonitor';
import MoneyTransactionMonitor from '../../UI/Money/components/MoneyTransactionMonitor/MoneyTransactionMonitor';

import {
setInfuraAvailabilityBlocked,
Expand Down Expand Up @@ -425,6 +426,7 @@ const Main = (props) => {
<Notification navigation={props.navigation} />
<RampOrders />
<EarnTransactionMonitor />
<MoneyTransactionMonitor />
{renderDeprecatedNetworkAlert(
props.chainId,
props.backUpSeedphraseVisible,
Expand Down
5 changes: 5 additions & 0 deletions app/components/Nav/Main/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ jest.mock(
() => () => mockReact.createElement('EarnTransactionMonitorMock'),
);

jest.mock(
'../../UI/Money/components/MoneyTransactionMonitor/MoneyTransactionMonitor',
() => () => mockReact.createElement('MoneyTransactionMonitorMock'),
);

jest.mock('../../UI/ProtectYourWalletModal', () => ({
__esModule: true,
default: () => mockReact.createElement('ProtectYourWalletModalMock'),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import { render } from '@testing-library/react-native';
import MoneyTransactionMonitor from './MoneyTransactionMonitor';
import { useMoneyTransactionStatus } from '../../hooks/useMoneyTransactionStatus';

jest.mock('../../hooks/useMoneyTransactionStatus');

describe('MoneyTransactionMonitor', () => {
const mockUseMoneyTransactionStatus = jest.mocked(useMoneyTransactionStatus);

beforeEach(() => {
jest.clearAllMocks();
});

afterEach(() => {
jest.resetAllMocks();
});

it('renders without crashing', () => {
const result = render(<MoneyTransactionMonitor />);

expect(result).toBeDefined();
});

it('calls useMoneyTransactionStatus exactly once', () => {
render(<MoneyTransactionMonitor />);

expect(mockUseMoneyTransactionStatus).toHaveBeenCalledTimes(1);
});

it('returns null', () => {
const { toJSON } = render(<MoneyTransactionMonitor />);

expect(toJSON()).toBeNull();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';
import { useMoneyTransactionStatus } from '../../hooks/useMoneyTransactionStatus';

const MoneyTransactionMonitor: React.FC = () => {
useMoneyTransactionStatus();
return null;
};

export default MoneyTransactionMonitor;
Loading
Loading