@@ -8,15 +8,13 @@ Documentation Retrieve record counts for Sales
88Library OperatingSystem
99Library Collections
1010Library BuiltIn
11- Library json
1211Library Process
1312Library DateTime
1413Library String
1514
1615*** Variables ***
1716${ORG_ALIAS } DeveloperOrg
1817# Windows execution
19- ${SF_CMD } cmd.exe
2018${SF_CLI } sf
2119${PYTHON } python
2220${OUTPUT_DIR } ${EXECDIR }${/ } output
@@ -82,21 +80,32 @@ Check Prerequisites
8280 ... stdout=PIPE
8381 ... stderr=PIPE
8482 Should Be Equal As Integers ${org_res.rc } 0 msg=Org alias not found or not authenticated: ${ORG_ALIAS } \n${org_res.stderr }
85- ${json_obj } = Evaluate json.loads($ org_res.stdout) modules=json
83+ ${json_obj } = Safe Parse Sf Json ${ org_res.stdout }
8684 ${result_dict } = Get From Dictionary ${json_obj } result
8785 ${api_version } = Get From Dictionary ${result_dict } apiVersion
8886 Set Suite Variable ${API_VERSION } ${api_version }
8987 Log To Console Connected to ${ORG_ALIAS } (API v${API_VERSION } )
9088
9189Safe Parse Sf Json
92- [Arguments] ${raw }
93- Should Not Be Empty ${raw } No output returned from sf.
94- # Find first JSON object start
95- ${index } = Evaluate $raw.find('{')
96- Run Keyword If ${index } == -1 Fail No JSON object found in output:\n${raw }
97- ${clean } = Evaluate $raw[$index:]
98- ${data } = Evaluate json.loads($clean) modules=json
99- RETURN ${data }
90+ [Arguments] ${raw }
91+ Should Not Be Empty ${raw } No output returned from sf.
92+ ${status1 } ${data1 } = Run Keyword And Ignore Error
93+ ... Evaluate json.loads($raw) modules=json
94+ IF '${status1 } ' == 'PASS'
95+ RETURN ${data1 }
96+ END
97+
98+ ${index } = Evaluate $raw.find('{')
99+ Run Keyword If ${index } == -1 Fail No JSON object found in output:\n${raw }
100+
101+ ${clean } = Evaluate $raw[$index:]
102+ ${status2 } ${data2 } = Run Keyword And Ignore Error
103+ ... Evaluate json.loads($clean) modules=json
104+ IF '${status2 } ' == 'PASS'
105+ RETURN ${data2 }
106+ END
107+
108+ Fail Unable to parse sf JSON output.\nRaw output:\n${raw }
100109
101110Run Sf Json
102111 [Documentation] Run an sf command and return parsed JSON dict.
@@ -120,6 +129,8 @@ Run Sf Command
120129 ${result } = Run Process
121130 ... ${SF_CLI }
122131 ... @{args }
132+ ... --target-org
133+ ... ${ORG_ALIAS }
123134 ... stdout=PIPE
124135 ... stderr=PIPE
125136 ${rc } = Set Variable ${result.rc }
@@ -136,8 +147,6 @@ Run Sf Api Request Rest Json
136147 ... request
137148 ... rest
138149 ... ${relative_url }
139- ... --target-org
140- ... ${ORG_ALIAS }
141150 Should Be Equal As Integers ${rc } 0 SF API call failed:\n${out } \n${err }
142151 ${status } ${data } = Run Keyword And Ignore Error Safe Parse Sf Json ${out }
143152 IF '${status } ' != 'PASS'
@@ -223,8 +232,15 @@ Get Skip Reason
223232 IF ${r3 } RETURN MALFORMED_QUERY
224233 ${r4 } = Run Keyword And Return Status Should Contain ${text } INVALID_TYPE
225234 IF ${r4 } RETURN INVALID_TYPE
235+ ${r5 } = Run Keyword And Return Status Should Contain ${text } INVALID_SESSION_ID
236+ IF ${r5 } RETURN INVALID_SESSION_ID
237+ ${r6 } = Run Keyword And Return Status Should Contain ${text } INSUFFICIENT_ACCESS
238+ IF ${r6 } RETURN INSUFFICIENT_ACCESS
239+ ${r7 } = Run Keyword And Return Status Should Contain ${text } REQUEST_LIMIT_EXCEEDED
240+ IF ${r7 } RETURN REQUEST_LIMIT_EXCEEDED
226241 RETURN OTHER_ERROR
227242
243+
228244Get Max Timeout For Object
229245 [Documentation] Special-case timeout for known slow objects.
230246 [Arguments] ${object_name }
@@ -303,61 +319,51 @@ Get Record Count Safe
303319 ${count } = Get From Dictionary ${result_dict } totalSize
304320 RETURN ${count } OK ${dur }
305321
322+
306323Get Tooling Object Names
307324 [Documentation] Returns filtered Tooling API sObject names using /tooling/sobjects.
308325 ... Keeps only queryable objects and removes noisy suffix patterns.
309- ${resp } = Run Sf Api Request Rest Json /services/data/v${API_VERSION } /tooling/sobjects/
310- ${is_none } = Run Keyword And Return Status Should Be Equal ${resp } ${None }
311- IF ${is_none }
312- Log To Console Tooling discovery failed; falling back to static TOOLING_OBJECTS list.
313- RETURN @{TOOLING_OBJECTS }
314- END
315- ${has_key } = Run Keyword And Return Status Dictionary Should Contain Key ${resp } sobjects
326+ ${resp } = Run Sf Api Request Rest Json /services/data/v${API_VERSION } /tooling/sobjects/
327+
328+ ${has_key } = Run Keyword And Return Status
329+ ... Dictionary Should Contain Key ${resp } sobjects
316330 IF not ${has_key }
317- Log To Console Tooling discovery response missing "sobjects"; falling back.
318- RETURN @{TOOLING_OBJECTS }
331+ Log To Console Tooling discovery response missing "sobjects"; falling back.
332+ RETURN @{TOOLING_OBJECTS }
319333 END
320- ${sobjects } = Collections.Get From Dictionary ${resp } sobjects
321- @{skip_suffixes } = Create List
322- ... Settings
323- ... Member
324- ... Members
325- ... Spec
326- ... Version
327- ... Versions
328- ... Info
329- ... Layout
330- ... Layouts
331- ... Mapping
332- ... Mappings
333- ... Definition
334- ... Definitions
335-
336- @{names } = Create List
334+
335+ ${sobjects } = Get From Dictionary ${resp } sobjects
336+ @{names } = Create List
337+
337338 FOR ${obj } IN @{sobjects }
338- ${queryable } = Collections.Get From Dictionary ${obj } queryable
339- IF not ${queryable }
339+ ${has_name } = Run Keyword And Return Status
340+ ... Dictionary Should Contain Key ${obj } name
341+ ${has_queryable } = Run Keyword And Return Status
342+ ... Dictionary Should Contain Key ${obj } queryable
343+
344+ IF not ${has_name }
340345 CONTINUE
341346 END
342- ${name } = Collections.Get From Dictionary ${obj } name
343- ${skip } = Set Variable ${FALSE }
344- FOR ${s } IN @{skip_suffixes }
345- ${ends } = Run Keyword And Return Status Should End With ${name } ${s }
346- IF ${ends }
347- ${skip } = Set Variable ${TRUE }
348- Exit For Loop
349- END
347+ IF not ${has_queryable }
348+ CONTINUE
350349 END
351- IF ${skip }
352- CONTINUE
350+
351+ ${name } = Get From Dictionary ${obj } name
352+ ${queryable } = Get From Dictionary ${obj } queryable
353+
354+ IF not ${queryable }
355+ CONTINUE
353356 END
354- Append To List ${names } ${name }
357+
358+ Append To List ${names } ${name }
355359 END
356- ${count } = Get Length ${names }
360+
361+ ${count } = Get Length ${names }
357362 IF ${count } == 0
358- Log To Console Tooling filter produced 0 objects; falling back to static list.
359- RETURN @{TOOLING_OBJECTS }
363+ Log To Console Tooling filter produced 0 objects; falling back to static list.
364+ RETURN @{TOOLING_OBJECTS }
360365 END
366+
361367 RETURN ${names }
362368
363369Log Summary All Objects
@@ -366,6 +372,7 @@ Log Summary All Objects
366372 Log To Console \nAll data objects (Object: Count):
367373 ${keys } = Get Dictionary Keys ${data_dict }
368374 FOR ${k } IN @{keys }
375+ Sort List ${keys }
369376 ${v } = Collections.Get From Dictionary ${data_dict } ${k }
370377 Log To Console ${k } : ${v }
371378 END
@@ -459,6 +466,19 @@ Get All Object Record Counts
459466 END
460467 END
461468 END
469+ # --- Summary Stats ---
470+ ${success_count } = Get Length ${data_results }
471+ ${tooling_success_count } = Get Length ${tooling_results }
472+ ${skip_count } = Get Length ${skipped_reasons }
473+ ${total_processed } = Evaluate ${success_count } + ${tooling_success_count } + ${skip_count }
474+
475+ Log To Console \n===== SUMMARY =====
476+ Log To Console Success(Data): ${success_count }
477+ Log To Console Success(Tooling): ${tooling_success_count }
478+ Log To Console Skipped: ${skip_count }
479+ Log To Console Total Processed: ${total_processed }
480+ Log To Console =====================
481+
462482 Save Results To Excel
463483 ... ${output_file }
464484 ... ${data_results }
@@ -469,12 +489,19 @@ Get All Object Record Counts
469489 Log Skipped Summary ${skipped_reasons }
470490 Log Summary All Objects ${data_results }
471491
492+ Generate Run Id
493+ ${timestamp } = Get Time
494+ ${timestamp } = Replace String ${timestamp } : -
495+ ${timestamp } = Replace String ${timestamp } ${SPACE } -
496+ RETURN ${timestamp }
497+
472498Save Results To Excel
473499 [Arguments] ${output_file } ${data_results } ${tooling_results } ${skipped_reasons } ${durations_seconds }
474- ${data_file } = Set Variable ${OUTPUT_DIR }${/ } data.json
475- ${tooling_file } = Set Variable ${OUTPUT_DIR }${/ } tooling.json
476- ${skipped_file } = Set Variable ${OUTPUT_DIR }${/ } skipped.json
477- ${durations_file } = Set Variable ${OUTPUT_DIR }${/ } durations.json
500+ ${run_id } = Generate Run Id
501+ ${data_file } = Set Variable ${OUTPUT_DIR }${/ } data_${run_id } .json
502+ ${tooling_file } = Set Variable ${OUTPUT_DIR }${/ } tooling_${run_id } .json
503+ ${skipped_file } = Set Variable ${OUTPUT_DIR }${/ } skipped_${run_id } .json
504+ ${durations_file } = Set Variable ${OUTPUT_DIR }${/ } durations_${run_id } .json
478505 ${data_json } = Evaluate json.dumps($data_results) modules=json
479506 ${tooling_json } = Evaluate json.dumps($tooling_results) modules=json
480507 ${skipped_json } = Evaluate json.dumps($skipped_reasons) modules=json
0 commit comments