@@ -589,26 +589,90 @@ describe("package acceptance workflow", () => {
589589 [ "npm_telegram" , "Dispatch and monitor npm Telegram E2E" ] ,
590590 [ "performance" , "Dispatch and monitor OpenClaw Performance" ] ,
591591 ] as const ;
592-
593- for ( const [ jobName , stepName ] of childDispatches ) {
592+ const dispatchScripts = childDispatches . map ( ( [ jobName , stepName ] ) => {
594593 const job = workflowJob ( FULL_RELEASE_VALIDATION_WORKFLOW , jobName ) ;
595- const script = workflowStep ( job , stepName ) . run ?? "" ;
594+ return workflowStep ( job , stepName ) . run ?? "" ;
595+ } ) ;
596596
597+ for ( const script of dispatchScripts ) {
597598 expect ( script . match ( / g h w o r k f l o w r u n / gu) ) . toHaveLength ( 1 ) ;
598599 expect ( script ) . not . toContain ( "gh_with_retry workflow run" ) ;
599600 expectTextToIncludeAll ( script , [
600601 "A failed dispatch POST can still create a run. Never retry it" ,
601602 "set +e" ,
602603 "dispatch_status=$?" ,
604+ 'if [[ "$dispatch_status" -ne 0 && ! "$dispatch_output" =~ $GH_TRANSIENT_SERVER_OR_NETWORK_PATTERN ]]' ,
605+ "dispatch failed with non-ambiguous status ${dispatch_status}; refusing adoption polling." ,
603606 'DISPATCH_RUN_NAME="$dispatch_run_name" CHILD_WORKFLOW_REF="$CHILD_WORKFLOW_REF"' ,
604607 ".display_title == env.DISPATCH_RUN_NAME and .head_branch == env.CHILD_WORKFLOW_REF" ,
605608 "Multiple runs matched ${dispatch_run_name}; refusing to guess." ,
606609 "The dispatch was not retried to avoid creating a duplicate child." ,
607610 "adopted exact run ${run_id}" ,
608611 ] ) ;
612+ expect ( script . indexOf ( "dispatch failed with non-ambiguous status" ) ) . toBeLessThan (
613+ script . indexOf ( 'run_id=""' ) ,
614+ ) ;
615+ }
616+
617+ const parsedWorkflow = readWorkflow ( FULL_RELEASE_VALIDATION_WORKFLOW ) ;
618+ const transientPattern = parsedWorkflow . env ?. GH_TRANSIENT_SERVER_OR_NETWORK_PATTERN ;
619+ expect ( transientPattern ) . toBeDefined ( ) ;
620+ const transientError = new RegExp ( transientPattern ?? "" , "u" ) ;
621+ for ( const message of [
622+ "could not create workflow dispatch event: HTTP 500: Failed to run workflow dispatch" ,
623+ "gh: HTTP 502" ,
624+ "500 Internal Server Error" ,
625+ "error connecting to api.github.com" ,
626+ "context deadline exceeded" ,
627+ "read: connection reset by peer" ,
628+ "connect: connection refused" ,
629+ "net/http: TLS handshake timeout" ,
630+ "read: i/o timeout" ,
631+ "network is unreachable" ,
632+ "unexpected EOF" ,
633+ 'Post "https://api.github.com/repos/openclaw/openclaw/actions/workflows/ci.yml/dispatches": EOF' ,
634+ "EOF" ,
635+ "ETIMEDOUT" ,
636+ "ECONNRESET" ,
637+ "EAI_AGAIN" ,
638+ ] ) {
639+ expect ( transientError . test ( message ) , message ) . toBe ( true ) ;
640+ }
641+ for ( const message of [
642+ "HTTP 400: Bad Request" ,
643+ "HTTP 401: Bad credentials" ,
644+ "HTTP 403: Resource not accessible by integration" ,
645+ "HTTP 404: workflow not found" ,
646+ "HTTP 422: Validation Failed" ,
647+ "HTTP 429: too many requests" ,
648+ "unknown flag --field" ,
649+ "EOFError while parsing local input" ,
650+ ] ) {
651+ expect ( transientError . test ( message ) , message ) . toBe ( false ) ;
652+ }
653+
654+ const summaryScript =
655+ workflowStep (
656+ workflowJob ( FULL_RELEASE_VALIDATION_WORKFLOW , "summary" ) ,
657+ "Verify child workflow results" ,
658+ ) . run ?? "" ;
659+ for ( const script of [ ...dispatchScripts , summaryScript ] ) {
660+ expect ( script . match ( / g h _ w i t h _ r e t r y \( \) / gu) ) . toHaveLength ( 1 ) ;
661+ expectTextToIncludeAll ( script , [
662+ '"$output" == *"HTTP 429"*' ,
663+ '"$output" == *"abuse detection"*' ,
664+ '"$output" =~ $GH_TRANSIENT_SERVER_OR_NETWORK_PATTERN' ,
665+ 'return "$status"' ,
666+ ] ) ;
609667 }
610668
611669 const workflow = readFileSync ( FULL_RELEASE_VALIDATION_WORKFLOW , "utf8" ) ;
670+ const retryCalls = workflow . split ( "\n" ) . filter ( ( line ) => line . includes ( "gh_with_retry " ) ) ;
671+ expect ( retryCalls ) . toHaveLength ( 28 ) ;
672+ for ( const call of retryCalls ) {
673+ expect ( call ) . toMatch ( / g h _ w i t h _ r e t r y ( a p i | r u n v i e w ) / u) ;
674+ }
675+ expect ( workflow ) . not . toMatch ( / g h _ w i t h _ r e t r y ( w o r k f l o w r u n | r u n c a n c e l ) / u) ;
612676 expectTextToIncludeAll ( workflow , [
613677 'dispatch_id="full-release-validation-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}-ci"' ,
614678 'dispatch_id="full-release-validation-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}-plugin-prerelease"' ,
0 commit comments