Skip to content

Commit 6e38093

Browse files
@W-21340586 Add PR validation pipeline (#49)
* Add PR validation pipeline with lint, tests, and build checks - Add GitHub Actions workflow for automated PR validation - Add ESLint, Prettier, and TypeScript type checking - Add npm scripts: lint, format, typecheck - Validate all 4 build variants (Android/iOS × Service/Employee) - Fix lint errors and apply consistent formatting - Add comprehensive CI/CD documentation Total runtime: ~20-25 minutes per PR Build matrix runs in parallel with aggressive caching * Address lint errors * Address issues raised from PR feedback
1 parent b364b95 commit 6e38093

29 files changed

+1456
-514
lines changed

.eslintrc.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
module.exports = {
2+
root: true,
3+
extends: '@react-native',
4+
parser: '@typescript-eslint/parser',
5+
plugins: ['@typescript-eslint'],
6+
overrides: [
7+
{
8+
files: ['*.ts', '*.tsx'],
9+
rules: {
10+
'@typescript-eslint/no-shadow': ['error'],
11+
'no-shadow': 'off',
12+
'no-undef': 'off',
13+
},
14+
},
15+
],
16+
rules: {
17+
// Customizations - keep minimal to avoid disruption
18+
'react-native/no-inline-styles': 'warn',
19+
'prettier/prettier': [
20+
'error',
21+
{
22+
endOfLine: 'auto',
23+
},
24+
],
25+
},
26+
};

.github/workflows/pr-checks.yml

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
name: PR Validation
2+
3+
# Trigger on pull requests to dev and pushes to dev (for verification)
4+
on:
5+
pull_request:
6+
branches: [ dev ]
7+
push:
8+
branches: [ dev ]
9+
10+
# Cancel in-progress runs for the same PR/branch
11+
concurrency:
12+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
13+
cancel-in-progress: true
14+
15+
jobs:
16+
# Job 1: Fast checks (lint, format, typecheck)
17+
lint-and-typecheck:
18+
name: Lint & Type Check
19+
runs-on: ubuntu-latest
20+
timeout-minutes: 10
21+
22+
steps:
23+
- name: Checkout code
24+
uses: actions/checkout@v4
25+
26+
- name: Setup Node.js
27+
uses: actions/setup-node@v4
28+
with:
29+
node-version: '18'
30+
cache: 'npm'
31+
32+
- name: Install dependencies
33+
run: npm ci --legacy-peer-deps --ignore-scripts
34+
35+
- name: Run ESLint
36+
run: npm run lint
37+
38+
- name: Check formatting
39+
run: npm run format
40+
41+
- name: Run TypeScript type check
42+
run: npm run typecheck
43+
44+
# Job 2: Unit tests
45+
unit-tests:
46+
name: Unit Tests
47+
runs-on: ubuntu-latest
48+
timeout-minutes: 10
49+
needs: lint-and-typecheck # Only run if lint passes
50+
51+
steps:
52+
- name: Checkout code
53+
uses: actions/checkout@v4
54+
55+
- name: Setup Node.js
56+
uses: actions/setup-node@v4
57+
with:
58+
node-version: '18'
59+
cache: 'npm'
60+
61+
- name: Install dependencies
62+
run: npm ci --legacy-peer-deps --ignore-scripts
63+
64+
- name: Run tests
65+
run: npm test -- --coverage --maxWorkers=2
66+
67+
- name: Upload coverage reports
68+
uses: codecov/codecov-action@v4
69+
if: always()
70+
with:
71+
fail_ci_if_error: false
72+
token: ${{ secrets.CODECOV_TOKEN }}
73+
74+
# Job 3: Build validation matrix (parallel builds)
75+
build-validation:
76+
name: Build ${{ matrix.platform }} - ${{ matrix.variant }}
77+
runs-on: ${{ matrix.os }}
78+
timeout-minutes: 30
79+
needs: unit-tests # Only run if tests pass
80+
81+
strategy:
82+
fail-fast: false # Don't cancel other builds if one fails
83+
matrix:
84+
include:
85+
# Android builds (Linux runner)
86+
- platform: Android
87+
variant: Service Agent
88+
os: ubuntu-latest
89+
setup-script: node installandroid.js service
90+
build-script: npm run build:android:service
91+
cache-paths: |
92+
~/.gradle/caches
93+
~/.gradle/wrapper
94+
android/.gradle
95+
cache-key: gradle
96+
97+
- platform: Android
98+
variant: Employee Agent
99+
os: ubuntu-latest
100+
setup-script: node installandroid.js employee
101+
build-script: npm run build:android:employee
102+
cache-paths: |
103+
~/.gradle/caches
104+
~/.gradle/wrapper
105+
android/.gradle
106+
cache-key: gradle
107+
108+
# iOS builds (macOS runner)
109+
- platform: iOS
110+
variant: Service Agent
111+
os: macos-14
112+
setup-script: node installios.js service
113+
build-script: npm run build:ios:service
114+
cache-paths: ios/Pods
115+
cache-key: pods
116+
117+
- platform: iOS
118+
variant: Employee Agent
119+
os: macos-14
120+
setup-script: node installios.js employee
121+
build-script: npm run build:ios:employee
122+
cache-paths: ios/Pods
123+
cache-key: pods
124+
125+
steps:
126+
- name: Checkout code
127+
uses: actions/checkout@v4
128+
129+
- name: Setup Node.js
130+
uses: actions/setup-node@v4
131+
with:
132+
node-version: '18'
133+
cache: 'npm'
134+
135+
# Java setup for Android builds
136+
- name: Setup Java (Android only)
137+
if: matrix.platform == 'Android'
138+
uses: actions/setup-java@v4
139+
with:
140+
distribution: 'temurin'
141+
java-version: '17'
142+
143+
# Ruby setup for iOS builds (CocoaPods)
144+
- name: Setup Ruby (iOS only)
145+
if: matrix.platform == 'iOS'
146+
uses: ruby/setup-ruby@v1
147+
with:
148+
ruby-version: '3.2'
149+
bundler-cache: false
150+
151+
# Install CocoaPods for iOS
152+
- name: Install CocoaPods (iOS only)
153+
if: matrix.platform == 'iOS'
154+
run: |
155+
gem install cocoapods -v 1.15.2
156+
pod --version
157+
158+
# Install XcodeGen for iOS
159+
- name: Install XcodeGen (iOS only)
160+
if: matrix.platform == 'iOS'
161+
run: |
162+
brew install xcodegen
163+
xcodegen --version
164+
165+
# Cache Gradle for Android
166+
- name: Cache Gradle dependencies (Android only)
167+
if: matrix.platform == 'Android'
168+
uses: actions/cache@v4
169+
with:
170+
path: ${{ matrix.cache-paths }}
171+
key: ${{ runner.os }}-${{ matrix.cache-key }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
172+
restore-keys: |
173+
${{ runner.os }}-${{ matrix.cache-key }}-
174+
175+
# Cache CocoaPods for iOS
176+
- name: Cache CocoaPods (iOS only)
177+
if: matrix.platform == 'iOS'
178+
uses: actions/cache@v4
179+
with:
180+
path: ${{ matrix.cache-paths }}
181+
key: ${{ runner.os }}-${{ matrix.cache-key }}-${{ hashFiles('ios/Podfile.*.lock') }}
182+
restore-keys: |
183+
${{ runner.os }}-${{ matrix.cache-key }}-
184+
185+
- name: Install npm dependencies
186+
run: npm ci --legacy-peer-deps --ignore-scripts
187+
188+
- name: Run platform setup
189+
run: ${{ matrix.setup-script }}
190+
191+
- name: Build ${{ matrix.platform }} - ${{ matrix.variant }}
192+
run: ${{ matrix.build-script }}
193+
194+
# Upload build logs on failure for debugging
195+
- name: Upload build logs on failure
196+
if: failure()
197+
uses: actions/upload-artifact@v4
198+
with:
199+
name: build-logs-${{ matrix.platform }}-${{ matrix.variant }}
200+
path: |
201+
android/app/build/outputs/**/*.log
202+
ios/build/Logs/**
203+
retention-days: 7
204+
if-no-files-found: ignore
205+
206+
# Summary job - all checks must pass
207+
all-checks-passed:
208+
name: All Checks Passed ✓
209+
runs-on: ubuntu-latest
210+
needs: [lint-and-typecheck, unit-tests, build-validation]
211+
if: always()
212+
213+
steps:
214+
- name: Check if all jobs succeeded
215+
run: |
216+
if [[ "${{ needs.lint-and-typecheck.result }}" != "success" ]] || \
217+
[[ "${{ needs.unit-tests.result }}" != "success" ]] || \
218+
[[ "${{ needs.build-validation.result }}" != "success" ]]; then
219+
echo "❌ One or more checks failed"
220+
exit 1
221+
fi
222+
echo "✅ All PR checks passed!"

.prettierignore

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Dependencies
2+
node_modules/
3+
**/node_modules/
4+
5+
# Build outputs
6+
ios/build/
7+
android/build/
8+
android/.gradle/
9+
*.log
10+
11+
# Native files
12+
ios/Pods/
13+
ios/*.xcworkspace/
14+
ios/*.xcodeproj/
15+
android/.idea/
16+
android/app/build/
17+
18+
# Generated files
19+
*.generated.ts
20+
*.generated.js
21+
22+
# Package files
23+
*.tgz
24+
25+
# Misc
26+
.DS_Store
27+
coverage/
28+
.idea/
29+
*.iml
30+
.vscode/
31+
.bundle/
32+
vendor/
33+
34+
# Bootconfig files (may contain sensitive data)
35+
ios/*/bootconfig.plist
36+
android/app/src/*/res/values/bootconfig.xml

.prettierrc.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module.exports = {
2+
arrowParens: 'avoid',
3+
bracketSameLine: true,
4+
bracketSpacing: true,
5+
singleQuote: true,
6+
trailingComma: 'all',
7+
tabWidth: 2,
8+
semi: true,
9+
printWidth: 100,
10+
endOfLine: 'auto',
11+
};

AgentforceSDK-ReactNative-Bridge/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Include the Salesforce Mobile SDK pods in your Podfile and perform **bootconfig*
5656
### Core Methods
5757

5858
**Configure and launch:**
59+
5960
```typescript
6061
import { AgentforceService } fromreact-native-agentforce’;
6162

@@ -80,6 +81,7 @@ await AgentforceService.setAdditionalContext({
8081
```
8182

8283
**Supported types:**
84+
8385
- `Text` - String values
8486
- `Number` - Numeric values
8587
- `Boolean` - Boolean values
@@ -89,6 +91,7 @@ await AgentforceService.setAdditionalContext({
8991
- `Json`, `Money`, `Ref`, `Variable` - Additional Android SDK types
9092

9193
**Platform notes:**
94+
9295
- Android: Uses `AgentforceContextVariable` with case-sensitive type names
9396
- iOS: Uses `AgentforceVariable` with `JSEncodableValue` enum; type is just a label
9497
- Context persists for the current conversation session

AgentforceSDK-ReactNative-Bridge/app/App.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ const App = (): JSX.Element => {
2424
headerTitleStyle: {
2525
fontWeight: 'bold',
2626
},
27-
}}
28-
>
27+
}}>
2928
<Stack.Screen
3029
name="Home"
3130
component={HomeScreen}

0 commit comments

Comments
 (0)