Skip to content

Commit c928d46

Browse files
committed
update config
1 parent d1886dd commit c928d46

File tree

13 files changed

+7348
-34
lines changed

13 files changed

+7348
-34
lines changed
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
# This workflow is an example used during the Paris Dev Group meetup on November 5th 2025.
2+
# Une CI/CD pour vos Agentforce : état des lieux
3+
# By @nabondance
4+
5+
name: Agentforce Validate
6+
# This workflow runs Salesforce Agent tests and aggregates the results.
7+
# It is split into several steps for better readability and understanding.
8+
9+
on:
10+
pull_request:
11+
types: [opened, synchronize, ready_for_review, reopened]
12+
branches: [ main ]
13+
14+
jobs:
15+
setup-deploy:
16+
runs-on: ubuntu-latest
17+
container: salesforce/cli:latest-slim
18+
19+
steps:
20+
- name: Checkout Code
21+
uses: actions/checkout@v5
22+
23+
- name: Install pnpm
24+
uses: pnpm/action-setup@v4
25+
with:
26+
version: 10
27+
28+
- name: Setup Node.js
29+
id: setup-node
30+
uses: actions/setup-node@v4
31+
with:
32+
node-version-file: .node-version
33+
cache: pnpm
34+
cache-dependency-path: 'pnpm-lock.yaml'
35+
36+
- name: Install Dependencies
37+
id: pnpm-install
38+
run: pnpm install
39+
40+
- name: 'Authenticate to Dev Hub'
41+
run: |
42+
echo "${{ secrets.DEVHUB_SFDX_AUTH_URL }}" > ./authfile
43+
sf org login sfdx-url --sfdxurlfile=authfile --alias=devhub
44+
45+
- name: 'Get org from pool'
46+
run: |
47+
pnpm sfp pool fetch --targetdevhubusername=devhub --tag=ci-pool --alias=so-ci
48+
49+
- name: 'Deploy Agentforce to org'
50+
run: |
51+
sf project deploy start --target-org=so-ci --manifest=manifestAgent.xml --wait=30
52+
53+
- name: 'Capture org auth URL'
54+
id: capture-org
55+
run: |
56+
echo "=== DEBUG: Extracting sfdxAuthUrl ==="
57+
AUTH_URL=$(sf org display --target-org=so-ci --verbose --json | tr -d '\000-\037' | jq -r '.result.sfdxAuthUrl')
58+
59+
# Save auth URL to artifact
60+
mkdir -p auth-artifact
61+
echo "$AUTH_URL" > auth-artifact/auth-url.txt
62+
echo "=== DEBUG: Auth URL saved to artifact ==="
63+
64+
- name: Upload auth URL artifact
65+
uses: actions/upload-artifact@v4
66+
with:
67+
name: org-auth-url
68+
path: auth-artifact/
69+
70+
list-tests:
71+
name: List Agent Tests
72+
needs: setup-deploy
73+
runs-on: ubuntu-latest
74+
container: salesforce/cli:latest-slim
75+
outputs:
76+
matrix: ${{ steps.set-matrix.outputs.matrix }}
77+
78+
steps:
79+
- uses: actions/checkout@v5
80+
81+
- name: Download auth URL artifact
82+
uses: actions/download-artifact@v4
83+
with:
84+
name: org-auth-url
85+
path: auth-artifact
86+
87+
- name: Authenticate to org
88+
run: |
89+
echo "=== DEBUG: Reading auth URL from artifact ==="
90+
AUTH_URL=$(cat auth-artifact/auth-url.txt)
91+
echo "AUTH_URL from artifact: '$AUTH_URL'"
92+
93+
if [ -z "$AUTH_URL" ] || [ "$AUTH_URL" = "null" ]; then
94+
echo "ERROR: Auth URL is empty or null from artifact"
95+
exit 1
96+
fi
97+
98+
echo "$AUTH_URL" > ./authfileci
99+
sf org login sfdx-url --sfdxurlfile=authfileci --alias=so-ci
100+
101+
- name: List agent tests and set matrix
102+
id: set-matrix
103+
run: |
104+
TESTS=$(sf agent test list --target-org=so-ci --json | jq -c '[.result[].fullName]')
105+
if [ "$TESTS" == "[]" ]; then
106+
echo "No tests found. Failing early."
107+
exit 1
108+
fi
109+
echo "matrix={\"test\":$TESTS}" >> "$GITHUB_OUTPUT"
110+
111+
run-agent-test:
112+
name: Run Agent Test - ${{ matrix.test }}
113+
needs: [setup-deploy, list-tests]
114+
runs-on: ubuntu-latest
115+
container: salesforce/cli:latest-slim
116+
strategy:
117+
fail-fast: false
118+
matrix: ${{ fromJson(needs.list-tests.outputs.matrix) }}
119+
120+
steps:
121+
- uses: actions/checkout@v5
122+
123+
- name: Download auth URL artifact
124+
uses: actions/download-artifact@v4
125+
with:
126+
name: org-auth-url
127+
path: auth-artifact
128+
129+
- name: Authenticate to org
130+
run: |
131+
AUTH_URL=$(cat auth-artifact/auth-url.txt)
132+
echo "$AUTH_URL" > ./authfileci
133+
sf org login sfdx-url --sfdxurlfile=authfileci --alias=so-ci
134+
135+
- name: Run test and get result
136+
id: test
137+
run: |
138+
mkdir -p test-results
139+
RUN_ID=$(sf agent test run --target-org=so-ci --api-name="${{ matrix.test }}" --wait 10 --json | jq -r '.result.runId')
140+
RESULT=$(sf agent test results --target-org=so-ci --job-id="$RUN_ID" --json)
141+
# Clean control characters before saving JSON
142+
echo "$RESULT" | tr -d '\000-\037' > "test-results/${{ matrix.test }}.json"
143+
144+
- name: Upload individual result
145+
uses: actions/upload-artifact@v4
146+
with:
147+
name: agent-test-results-${{ matrix.test }}
148+
path: test-results/
149+
150+
validate-results:
151+
name: Validate Results
152+
needs: run-agent-test
153+
runs-on: ubuntu-latest
154+
155+
steps:
156+
- name: Download all test results
157+
uses: actions/download-artifact@v4
158+
with:
159+
path: all-results
160+
pattern: agent-test-results-*
161+
merge-multiple: true
162+
163+
- name: Summarize test outcomes
164+
id: summary
165+
run: |
166+
total=0
167+
passed=0
168+
failed=0
169+
170+
ls -al all-results/
171+
172+
# Check if any JSON files exist
173+
if ! ls all-results/ 1> /dev/null 2>&1; then
174+
echo "No test result files found"
175+
exit 1
176+
fi
177+
178+
for file in all-results/*; do
179+
echo "Processing file: $file"
180+
181+
# Check if file is valid JSON and has expected structure
182+
if ! jq -e '.result.testCases' "$file" > /dev/null 2>&1; then
183+
echo "Skipping invalid or malformed JSON file: $file"
184+
continue
185+
fi
186+
187+
p=$(jq '[.result.testCases[]? | .testResults[]? | select(.result == "PASS")] | length' "$file" 2>/dev/null || echo "0")
188+
f=$(jq '[.result.testCases[]? | .testResults[]? | select(.result == "FAILURE")] | length' "$file" 2>/dev/null || echo "0")
189+
190+
total=$((total + p + f))
191+
passed=$((passed + p))
192+
failed=$((failed + f))
193+
194+
echo "File $file: $p passed, $f failed"
195+
done
196+
197+
if [ $total -eq 0 ]; then
198+
echo "No test results found in any files"
199+
exit 1
200+
fi
201+
202+
percentage=$((passed * 100 / total))
203+
echo "TOTAL=$total" >> "$GITHUB_OUTPUT"
204+
echo "PASSED=$passed" >> "$GITHUB_OUTPUT"
205+
echo "FAILED=$failed" >> "$GITHUB_OUTPUT"
206+
echo "PERCENT=$percentage" >> "$GITHUB_OUTPUT"
207+
208+
- name: Display summary
209+
run: |
210+
echo "=================================="
211+
echo " Agent Test Summary "
212+
echo "=================================="
213+
echo "Total Tests : ${{ steps.summary.outputs.TOTAL }}"
214+
echo "Tests Passed: ${{ steps.summary.outputs.PASSED }}"
215+
echo "Tests Failed: ${{ steps.summary.outputs.FAILED }}"
216+
echo "Pass : ${{ steps.summary.outputs.PERCENT }}%"
217+
echo "=================================="
218+
219+
- name: Enforce pass threshold
220+
if: ${{ steps.summary.outputs.PERCENT < 75 }}
221+
run: |
222+
echo "❌ Agent tests failed threshold (75%). Only ${{ steps.summary.outputs.PERCENT }}% passed."
223+
exit 1
224+
225+
cleanup:
226+
name: Return Org to Pool
227+
needs: [setup-deploy, validate-results]
228+
if: always()
229+
runs-on: ubuntu-latest
230+
container: salesforce/cli:latest-slim
231+
232+
steps:
233+
- name: Checkout Code
234+
uses: actions/checkout@v5
235+
236+
- name: Install pnpm
237+
uses: pnpm/action-setup@v4
238+
with:
239+
version: 10
240+
241+
- name: Install Dependencies
242+
run: pnpm install
243+
244+
- name: Download auth URL artifact
245+
uses: actions/download-artifact@v4
246+
with:
247+
name: org-auth-url
248+
path: auth-artifact
249+
250+
- name: Authenticate to DevHub
251+
run: |
252+
echo "${{ secrets.DEVHUB_SFDX_AUTH_URL }}" > ./authfile
253+
sf org login sfdx-url --sfdxurlfile=authfile --alias=devhub
254+
255+
- name: Return org to pool
256+
run: |
257+
AUTH_URL=$(cat auth-artifact/auth-url.txt)
258+
echo "$AUTH_URL" > ./org-auth.txt
259+
sf org login sfdx-url --sfdxurlfile=org-auth.txt --alias=so-ci
260+
pnpm sfp pool delete --targetdevhubusername=devhub --tag=ci-pool --myorg=so-ci
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# This workflow is an example of pool preparation based on @flxbl-io library.
2+
# By @nabondance
3+
#-----------------------------------------------------------------------------------------------------
4+
# To know more about flxbl, visit https://docs.flxbl.io
5+
6+
name: 'Prepare Pools - Auto Triggered'
7+
8+
on:
9+
workflow_dispatch:
10+
inputs:
11+
gitRef:
12+
description: 'Commit Id from where the pools should be created'
13+
required: false
14+
default: 'main'
15+
# Uncomment the following lines to enable scheduled runs
16+
# schedule:
17+
# - cron: '0 9-20/3 * * MON-FRI'
18+
19+
# Set the environment variables for DevHub authentication
20+
# DEVHUB_SFDX_AUTH_URL
21+
22+
jobs:
23+
replenish-pools:
24+
runs-on: ubuntu-latest
25+
container: ghcr.io/flxbl-io/sfp:latest
26+
timeout-minutes: 20
27+
strategy:
28+
fail-fast: false
29+
matrix:
30+
include:
31+
- pooltag: 'pool-ci'
32+
poolfile: 'config/pools/ci-pool.json'
33+
- pooltag: 'pool-dev'
34+
poolfile: 'config/pools/dev-pool.json'
35+
steps:
36+
- name: 'Checkout code'
37+
uses: actions/checkout@v4
38+
with:
39+
ref: ${{ github.event.inputs.gitRef }}
40+
fetch-depth: 0
41+
submodules: 'recursive'
42+
43+
- name: 'Install pnpm'
44+
uses: pnpm/action-setup@v4
45+
with:
46+
version: 10
47+
48+
- name: 'Setup Node.js'
49+
id: setup-node
50+
uses: actions/setup-node@v4
51+
with:
52+
node-version-file: .node-version
53+
cache: pnpm
54+
cache-dependency-path: 'pnpm-lock.yaml'
55+
56+
- name: 'Install Dependencies'
57+
id: pnpm-install
58+
run: pnpm install
59+
60+
- name: 'Authenticate Dev Hub'
61+
run: |
62+
echo "${{ secrets.DEVHUB_SFDX_AUTH_URL }}" > ./authfile
63+
sf org login sfdx-url --sfdxurlfile=authfile --alias=devhub
64+
65+
- name: 'Prepare a pool of scratch orgs'
66+
run: 'sfp prepare --poolconfig=${{ matrix.poolfile }} --targetdevhubusername=devhub'
67+
68+
# Publish artifacts
69+
- uses: actions/upload-artifact@v4
70+
if: ${{ always() }}
71+
with:
72+
name: scratchorg-logs-pool-${{ matrix.pooltag }}
73+
path: .sfpowerscripts/prepare_logs

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@
55
node_modules
66
.DS_Store
77

8-
notes.md
8+
.sfpowerscripts
9+
.claude
10+
11+
authFile.json
12+
notes.md

.node-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
22.14.0

0 commit comments

Comments
 (0)