Skip to content

Commit 8e71509

Browse files
committed
Merge remote-tracking branch 'origin/chore/temp-nightly' into wsun/temp-nightly-ota-v4
2 parents 233d965 + e2c5b46 commit 8e71509

188 files changed

Lines changed: 7271 additions & 5571 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Version: 1.0.0
2+
name: 'Cursor CLI Setup'
3+
description: 'Sets up Cursor CLI with permissions and fetches issue details'
4+
5+
inputs:
6+
cursor-api-key:
7+
description: 'Cursor API key for authentication'
8+
required: true
9+
issue-number:
10+
description: 'GitHub issue number'
11+
required: true
12+
repository:
13+
description: 'GitHub repository (owner/repo)'
14+
required: true
15+
github-token:
16+
description: 'GitHub token for API calls'
17+
required: true
18+
read-only:
19+
description: 'If true, configure read-only permissions (no write access)'
20+
required: false
21+
default: 'true'
22+
23+
outputs:
24+
issue-content:
25+
description: 'Base64-encoded issue content (JSON with title, body, comments, labels)'
26+
value: ${{ steps.issue.outputs.content }}
27+
28+
runs:
29+
using: 'composite'
30+
steps:
31+
- name: Configure Cursor permissions (read-only)
32+
if: inputs.read-only == 'true'
33+
shell: bash
34+
run: |
35+
# Strict allowlist: only read source code, deny everything else
36+
mkdir -p .cursor
37+
printf '%s\n' '{"permissions":{"allow":["Read(app/**/*)","Read(src/**/*)","Read(e2e/**/*)","Read(docs/**/*)","Read(*.md)","Read(*.json)","Read(*.ts)","Read(*.tsx)","Read(*.js)"],"deny":["Shell(*)","Write(*)","Read(.env*)","Read(**/.env*)","Read(**/secrets/**)","Read(**/*.pem)","Read(**/*.key)","Read(**/*.secret)","Read(.git/**)","Read(node_modules/**)"]}}' > .cursor/permissions.json
38+
39+
- name: Configure Cursor permissions (read-write)
40+
if: inputs.read-only == 'false'
41+
shell: bash
42+
run: |
43+
# Allow reads and writes to source code, deny sensitive files
44+
mkdir -p .cursor
45+
printf '%s\n' '{"permissions":{"allow":["Read(app/**/*)","Read(src/**/*)","Read(e2e/**/*)","Read(docs/**/*)","Read(*.md)","Read(*.json)","Read(*.ts)","Read(*.tsx)","Read(*.js)","Write(app/**/*)","Write(src/**/*)","Write(e2e/**/*)","Write(docs/**/*)","Write(*.md)","Write(*.json)","Write(*.ts)","Write(*.tsx)","Write(*.js)","Shell(yarn *)","Shell(git *)"],"deny":["Read(.env*)","Read(**/.env*)","Read(**/secrets/**)","Read(**/*.pem)","Read(**/*.key)","Read(**/*.secret)","Read(node_modules/**)","Write(.env*)","Write(**/.env*)","Write(**/secrets/**)","Write(**/*.pem)","Write(**/*.key)","Write(**/*.secret)","Shell(curl *)","Shell(wget *)","Shell(npm *)","Shell(npx *)"]}}' > .cursor/permissions.json
46+
47+
- name: Install Cursor CLI
48+
shell: bash
49+
run: |
50+
curl https://cursor.com/install -fsS | bash
51+
echo "$HOME/.cursor/bin" >> "$GITHUB_PATH"
52+
53+
- name: Fetch issue details
54+
id: issue
55+
shell: bash
56+
env:
57+
GH_TOKEN: ${{ inputs.github-token }}
58+
ISSUE_NUMBER: ${{ inputs.issue-number }}
59+
REPO: ${{ inputs.repository }}
60+
run: |
61+
# Use env vars to prevent shell injection
62+
ISSUE_CONTENT=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json title,body,comments,labels)
63+
64+
# Base64 encode to safely pass through GitHub Actions outputs
65+
ENCODED=$(printf '%s' "$ISSUE_CONTENT" | base64 -w 0)
66+
echo "content=$ENCODED" >> "$GITHUB_OUTPUT"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
You are implementing a GitHub issue for the MetaMask Mobile repository.
2+
3+
## Your Task
4+
5+
1. **Understand the Issue**: Read the issue details carefully to understand what needs to be done
6+
2. **Analyze the Codebase**: Search for relevant files and understand the existing patterns
7+
3. **Implement the Solution**: Make the necessary code changes following the project's conventions
8+
4. **Write Tests**: Add unit tests for any new functionality (follow the testing guidelines)
9+
5. **Verify**: Ensure your changes don't break existing functionality
10+
11+
## Guidelines
12+
13+
- Follow the existing code style and patterns in the repository
14+
- Use TypeScript - no `any` types allowed
15+
- Use the design system components from `@metamask/design-system-react-native`
16+
- Add appropriate comments where needed
17+
- Keep changes focused on the issue scope - don't over-engineer
18+
19+
## Output
20+
21+
After implementing, provide a summary of:
22+
23+
1. Files changed and why
24+
2. Key implementation decisions
25+
3. Any potential risks or considerations for reviewers
26+
27+
Do NOT create the pull request yourself - the workflow will handle that.

.github/workflows/build-android-e2e.yml

Lines changed: 54 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -98,35 +98,78 @@ jobs:
9898
exit 1
9999
fi
100100
101-
- name: Check and restore cached APKs if Fingerprint is found
101+
- name: Restore APKs matching fingerprint from branch cache
102102
id: apk-cache-restore
103+
# This action automatically updates the cache at the end of the workflow
103104
uses: cirruslabs/cache@bba69c6578b863ad0398ad40567bd2ef70290fe0 # v4
104105
with:
105106
path: |
106107
${{ steps.determine-target-paths.outputs.apk-target-path }}/${{ steps.determine-target-paths.outputs.artifact_name }}.apk
107108
${{ steps.determine-target-paths.outputs.test-apk-target-path }}/${{ steps.determine-target-paths.outputs.artifact_name }}-androidTest.apk
108109
# Include Gradle properties in key to force rebuild when properties change
109110
# Keep the `hashFiles` call for Gradle config in-sync with these steps:
110-
# - "Cache Gradle dependencies"
111-
# - "Cache build artifacts"
112-
key: android-apk-${{ inputs.build_type }}-${{ env.CACHE_GENERATION }}-${{ steps.generate-fingerprint.outputs.fingerprint }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
111+
# - "Restore APKs matching fingerprint from branch cache"
112+
# - "Restore APKs matching fingerprint from main cache"
113+
# - "Restore Gradle dependencies from branch cache"
114+
# - "Restore Gradle dependencies from main cache"
115+
key: android-apk-${{ github.ref_name }}-${{ inputs.build_type }}-${{ env.CACHE_GENERATION }}-${{ steps.generate-fingerprint.outputs.fingerprint }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
113116

114-
- name: Cache Gradle dependencies
117+
- name: Restore APKs matching fingerprint from main cache
118+
if: ${{ steps.apk-cache-restore.outputs.cache-hit != 'true' && github.ref_name != 'main' }}
119+
id: apk-cache-restore-main
120+
# This will only restore the cache, not update it
121+
uses: cirruslabs/cache/restore@bba69c6578b863ad0398ad40567bd2ef70290fe0 # v4
122+
with:
123+
path: |
124+
${{ steps.determine-target-paths.outputs.apk-target-path }}/${{ steps.determine-target-paths.outputs.artifact_name }}.apk
125+
${{ steps.determine-target-paths.outputs.test-apk-target-path }}/${{ steps.determine-target-paths.outputs.artifact_name }}-androidTest.apk
126+
# Include Gradle properties in key to force rebuild when properties change
127+
# Keep the `hashFiles` call for Gradle config in-sync with these steps:
128+
# - "Restore APKs matching fingerprint from branch cache"
129+
# - "Restore APKs matching fingerprint from main cache"
130+
# - "Restore Gradle dependencies from branch cache"
131+
# - "Restore Gradle dependencies from main cache"
132+
key: android-apk-main-${{ inputs.build_type }}-${{ env.CACHE_GENERATION }}-${{ steps.generate-fingerprint.outputs.fingerprint }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
133+
134+
- name: Restore Gradle dependencies from branch cache
135+
id: gradle-cache-restore
136+
# This action automatically updates the cache at the end of the workflow
115137
uses: cirruslabs/cache@bba69c6578b863ad0398ad40567bd2ef70290fe0 # v4
116-
if: ${{ steps.apk-cache-restore.outputs.cache-hit != 'true' }}
138+
if: ${{ steps.apk-cache-restore.outputs.cache-hit != 'true' && steps.apk-cache-restore-main.outputs.cache-hit != 'true' }}
139+
env:
140+
GRADLE_CACHE_VERSION: 1
141+
with:
142+
path: |
143+
~/_work/.gradle/caches
144+
~/_work/.gradle/wrapper
145+
# Include Gradle properties in key to force rebuild when properties change
146+
# Keep the `hashFiles` call for Gradle config in-sync with these steps:
147+
# - "Restore APKs matching fingerprint from branch cache"
148+
# - "Restore APKs matching fingerprint from main cache"
149+
# - "Restore Gradle dependencies from branch cache"
150+
# - "Restore Gradle dependencies from main cache"
151+
key: gradle-${{ github.ref_name }}-${{ env.GRADLE_CACHE_VERSION }}-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
152+
153+
- name: Restore Gradle dependencies from main cache
154+
# This will only restore the cache, not update it
155+
uses: cirruslabs/cache/restore@bba69c6578b863ad0398ad40567bd2ef70290fe0 # v4
156+
if: ${{ steps.apk-cache-restore.outputs.cache-hit != 'true' && steps.apk-cache-restore-main.outputs.cache-hit != 'true' && steps.gradle-cache-restore.outputs.cache-hit != 'true' && github.ref_name != 'main' }}
117157
env:
118158
GRADLE_CACHE_VERSION: 1
119159
with:
120160
path: |
121161
~/_work/.gradle/caches
122162
~/_work/.gradle/wrapper
163+
# Include Gradle properties in key to force rebuild when properties change
123164
# Keep the `hashFiles` call for Gradle config in-sync with these steps:
124-
# - "Check and restore cached APKs if Fingerprint is found"
125-
# - "Cache build artifacts"
126-
key: gradle-${{ env.GRADLE_CACHE_VERSION }}-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
165+
# - "Restore APKs matching fingerprint from branch cache"
166+
# - "Restore APKs matching fingerprint from main cache"
167+
# - "Restore Gradle dependencies from branch cache"
168+
# - "Restore Gradle dependencies from main cache"
169+
key: gradle-main-${{ env.GRADLE_CACHE_VERSION }}-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
127170

128171
- name: Build Android E2E APKs
129-
if: ${{ steps.apk-cache-restore.outputs.cache-hit != 'true' }}
172+
if: ${{ steps.apk-cache-restore.outputs.cache-hit != 'true' && steps.apk-cache-restore-main.outputs.cache-hit != 'true' }}
130173
run: |
131174
echo "🏗 Building Android E2E APKs..."
132175
export NODE_OPTIONS="--max-old-space-size=4096"
@@ -179,7 +222,7 @@ jobs:
179222
MM_PREDICT_GTM_MODAL_ENABLED: 'false'
180223

181224
- name: Repack APK with JS updates using @expo/repack-app
182-
if: ${{ steps.apk-cache-restore.outputs.cache-hit == 'true' }}
225+
if: ${{ steps.apk-cache-restore.outputs.cache-hit == 'true' || steps.apk-cache-restore-main.outputs.cache-hit == 'true' }}
183226
run: |
184227
echo "📦 Repacking APK with updated JavaScript bundle using @expo/repack-app..."
185228
# Use the optimized repack script which uses @expo/repack-app
@@ -228,19 +271,6 @@ jobs:
228271
GOOGLE_SERVICES_B64_ANDROID: ${{ secrets.GOOGLE_SERVICES_B64_ANDROID }}
229272
MM_INFURA_PROJECT_ID: ${{ secrets.MM_INFURA_PROJECT_ID }}
230273

231-
# Cache build artifacts with the pre-build fingerprint
232-
- name: Cache build artifacts
233-
if: ${{ steps.apk-cache-restore.outputs.cache-hit != 'true' }}
234-
uses: cirruslabs/cache@bba69c6578b863ad0398ad40567bd2ef70290fe0 # v4
235-
with:
236-
path: |
237-
${{ steps.determine-target-paths.outputs.apk-target-path }}/${{ steps.determine-target-paths.outputs.artifact_name }}.apk
238-
${{ steps.determine-target-paths.outputs.test-apk-target-path }}/${{ steps.determine-target-paths.outputs.artifact_name }}-androidTest.apk
239-
# Keep the `hashFiles` call for Gradle config in-sync with these steps:
240-
# - "Check and restore cached APKs if Fingerprint is found"
241-
# - "Cache Gradle dependencies"
242-
key: android-apk-${{ inputs.build_type }}-${{ env.CACHE_GENERATION }}-${{ steps.generate-fingerprint.outputs.fingerprint }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
243-
244274
- name: Upload Android APK
245275
id: upload-apk
246276
uses: actions/upload-artifact@v4

.github/workflows/build-ios-e2e.yml

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,30 @@ jobs:
5757
- name: Checkout repo
5858
uses: actions/checkout@v4
5959

60-
- name: Cache Xcode derived data
60+
- name: Restore Xcode derived data from branch cache
61+
id: xcode-restore-cache
62+
# This action automatically updates the cache at the end of the workflow
6163
uses: cirruslabs/cache@bba69c6578b863ad0398ad40567bd2ef70290fe0 # v4
6264
env:
6365
XCODE_CACHE_VERSION: 1
6466
with:
6567
path: |
6668
~/Library/Developer/Xcode/DerivedData
6769
ios/build
68-
key: ${{ runner.os }}-xcode-${{ env.XCODE_CACHE_VERSION }}-${{ hashFiles('ios/**/*.{h,m,mm,swift}', 'ios/**/Podfile.lock', 'yarn.lock') }}
70+
key: ${{ runner.os }}-xcode-${{ github.ref_name }}-${{ env.XCODE_CACHE_VERSION }}-${{ hashFiles('ios/**/*.{h,m,mm,swift}', 'ios/**/Podfile.lock', 'yarn.lock') }}
71+
72+
- name: Restore Xcode derived data from main cache
73+
if: ${{ steps.xcode-restore-cache.outputs.cache-hit != 'true' && github.ref_name != 'main' }}
74+
id: xcode-restore-cache-main
75+
# This will only restore the cache, not update it
76+
uses: cirruslabs/cache/restore@bba69c6578b863ad0398ad40567bd2ef70290fe0 # v4
77+
env:
78+
XCODE_CACHE_VERSION: 1
79+
with:
80+
path: |
81+
~/Library/Developer/Xcode/DerivedData
82+
ios/build
83+
key: ${{ runner.os }}-xcode-main-${{ env.XCODE_CACHE_VERSION }}-${{ hashFiles('ios/**/*.{h,m,mm,swift}', 'ios/**/Podfile.lock', 'yarn.lock') }}
6984

7085
# Install Node.js, Xcode tools, and other iOS development dependencies
7186
- name: Installing iOS Environment Setup
@@ -112,17 +127,28 @@ jobs:
112127
echo "fingerprint=$FINGERPRINT" >> "$GITHUB_OUTPUT"
113128
echo "Current fingerprint: ${FINGERPRINT}"
114129
115-
- name: Check and restore cached iOS app if Fingerprint is found
130+
- name: Restore iOS app matching fingerprint from branch cache
116131
id: cache-restore
132+
# This action automatically updates the cache at the end of the workflow
117133
uses: cirruslabs/cache@bba69c6578b863ad0398ad40567bd2ef70290fe0 # v4
118134
with:
119135
path: |
120136
ios/build/Build/Products/Release-iphonesimulator/MetaMask.app
121-
key: ios-app-${{ steps.generate-fingerprint.outputs.fingerprint }}
137+
key: ios-app-${{ github.ref_name }}-${{ steps.generate-fingerprint.outputs.fingerprint }}
138+
139+
- name: Restore iOS app matching fingerprint from main cache
140+
if: ${{ steps.cache-restore.outputs.cache-hit != 'true' && github.ref_name != 'main' }}
141+
id: cache-restore-main
142+
# This will only restore the cache, not update it
143+
uses: cirruslabs/cache/restore@bba69c6578b863ad0398ad40567bd2ef70290fe0 # v4
144+
with:
145+
path: |
146+
ios/build/Build/Products/Release-iphonesimulator/MetaMask.app
147+
key: ios-app-main-${{ steps.generate-fingerprint.outputs.fingerprint }}
122148

123149
# Build the iOS E2E app for simulator
124150
- name: Build iOS E2E App
125-
if: ${{ steps.cache-restore.outputs.cache-hit != 'true' }}
151+
if: ${{ steps.cache-restore.outputs.cache-hit != 'true' && steps.cache-restore-main.outputs.cache-hit != 'true' }}
126152
run: |
127153
echo "🏗 Building iOS E2E App..."
128154
export NODE_OPTIONS="--max-old-space-size=8192"
@@ -157,7 +183,7 @@ jobs:
157183
GOOGLE_SERVICES_B64_ANDROID: ${{ secrets.GOOGLE_SERVICES_B64_ANDROID }}
158184

159185
- name: Repack iOS app with JS updates using @expo/repack-app
160-
if: ${{ steps.cache-restore.outputs.cache-hit == 'true' }}
186+
if: ${{ steps.cache-restore.outputs.cache-hit == 'true' || steps.cache-restore-main.outputs.cache-hit == 'true' }}
161187
run: |
162188
echo "📦 Repacking iOS app with updated JavaScript bundle using @expo/repack-app..."
163189
# Use the optimized repack script which uses @expo/repack-app
@@ -195,15 +221,6 @@ jobs:
195221
GOOGLE_SERVICES_B64_ANDROID: ${{ secrets.GOOGLE_SERVICES_B64_ANDROID }}
196222
MM_INFURA_PROJECT_ID: ${{ secrets.MM_INFURA_PROJECT_ID }}
197223

198-
# Cache build artifacts with the pre-build fingerprint
199-
- name: Cache build artifacts
200-
if: ${{ steps.cache-restore.outputs.cache-hit != 'true' }}
201-
uses: cirruslabs/cache@bba69c6578b863ad0398ad40567bd2ef70290fe0 # v4
202-
with:
203-
path: |
204-
ios/build/Build/Products/Release-iphonesimulator/MetaMask.app
205-
key: ios-app-${{ steps.generate-fingerprint.outputs.fingerprint }}
206-
207224
# Upload the iOS .app file that works in simulators
208225
- name: Upload iOS APP Artifact (Simulator)
209226
id: upload-app
@@ -219,7 +236,7 @@ jobs:
219236
# Only runs when repack step runs (cache hit), as that's when sourcemap is generated
220237
- name: Upload iOS Source Map
221238
id: upload-sourcemap
222-
if: ${{ steps.cache-restore.outputs.cache-hit == 'true' }}
239+
if: ${{ steps.cache-restore.outputs.cache-hit == 'true' || steps.cache-restore-main.outputs.cache-hit == 'true' }}
223240
uses: actions/upload-artifact@v4
224241
with:
225242
name: index.js.map

.github/workflows/cursor-issue-analysis.yml

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Version: 0.3.0
1+
# Version: 0.4.0
22
name: Cursor Issue Analysis
33

44
on:
@@ -42,40 +42,23 @@ jobs:
4242
if: steps.check-comment.outputs.exists != 'true'
4343
uses: actions/checkout@v4
4444

45-
- name: Configure Cursor permissions
45+
- name: Setup Cursor CLI
4646
if: steps.check-comment.outputs.exists != 'true'
47-
run: |
48-
# Strict allowlist: only read source code, deny everything else
49-
mkdir -p .cursor
50-
printf '%s\n' '{"permissions":{"allow":["Read(app/**/*)","Read(src/**/*)","Read(e2e/**/*)","Read(docs/**/*)","Read(*.md)","Read(*.json)","Read(*.ts)","Read(*.tsx)","Read(*.js)"],"deny":["Shell(*)","Write(*)","Read(.env*)","Read(**/.env*)","Read(**/secrets/**)","Read(**/*.pem)","Read(**/*.key)","Read(**/*.secret)","Read(.git/**)","Read(node_modules/**)"]}}' > .cursor/permissions.json
51-
52-
- name: Install Cursor CLI
53-
if: steps.check-comment.outputs.exists != 'true'
54-
run: |
55-
curl https://cursor.com/install -fsS | bash
56-
echo "$HOME/.cursor/bin" >> "$GITHUB_PATH"
57-
58-
- name: Fetch issue details
59-
if: steps.check-comment.outputs.exists != 'true'
60-
id: issue
61-
env:
62-
GH_TOKEN: ${{ github.token }}
63-
ISSUE_NUMBER: ${{ github.event.issue.number }}
64-
REPO: ${{ github.repository }}
65-
run: |
66-
# Use env vars to prevent shell injection
67-
ISSUE_CONTENT=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json title,body,comments,labels)
68-
69-
# Base64 encode to safely pass through GitHub Actions outputs
70-
ENCODED=$(printf '%s' "$ISSUE_CONTENT" | base64 -w 0)
71-
echo "content=$ENCODED" >> "$GITHUB_OUTPUT"
47+
id: cursor-setup
48+
uses: ./.github/actions/cursor-cli-setup
49+
with:
50+
cursor-api-key: ${{ secrets.CURSOR_API_KEY }}
51+
issue-number: ${{ github.event.issue.number }}
52+
repository: ${{ github.repository }}
53+
github-token: ${{ github.token }}
54+
read-only: 'true'
7255

7356
- name: Run Cursor Analysis
7457
if: steps.check-comment.outputs.exists != 'true'
7558
id: analysis
7659
env:
7760
CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }}
78-
ISSUE_CONTENT_B64: ${{ steps.issue.outputs.content }}
61+
ISSUE_CONTENT_B64: ${{ steps.cursor-setup.outputs.issue-content }}
7962
run: |
8063
# Decode issue content from base64
8164
# Note: Variable expansion in double quotes does NOT execute command substitutions

0 commit comments

Comments
 (0)