@@ -42,9 +42,10 @@ def stub_env
4242 let ( :posted_bodies ) { { } }
4343
4444 before do
45- allow ( GithubCli ) . to receive ( :capture_success ) do |*args , **_kwargs |
45+ allow ( GithubCli ) . to receive ( :capture_success ) do |*args , **kwargs |
4646 key = capture_key ( args )
4747 calls << key
48+ posted_bodies [ key ] = extract_body ( args , kwargs )
4849 capture_responses . fetch ( key ) { raise "unexpected capture_success: #{ key } " }
4950 end
5051
@@ -69,6 +70,7 @@ def extract_body(args, kwargs)
6970 def capture_key ( args )
7071 return "issue list" if args [ 1 ..2 ] == %w[ issue list ]
7172 return "issue create" if args [ 1 ..2 ] == %w[ issue create ]
73+ return "comment create" if args [ 1 ..3 ] == %w[ api -X POST ]
7274 return "comment list" if args [ 1 ] == "api" && args [ 2 ] . match? ( %r{/issues/\d +/comments\z } )
7375 return "comment body" if args [ 1 ] == "api" && args [ 2 ] . match? ( %r{/issues/comments/\d +\z } )
7476
@@ -77,7 +79,6 @@ def capture_key(args)
7779
7880 def run_key ( args )
7981 return "label create" if args [ 1 ..2 ] == %w[ label create ]
80- return "issue comment" if args [ 1 ..2 ] == %w[ issue comment ]
8182 return "comment patch" if args [ 1 ..3 ] == %w[ api -X PATCH ]
8283
8384 raise "unrecognized run args: #{ args . inspect } "
@@ -92,16 +93,66 @@ def report
9293 )
9394 end
9495
96+ def report_with_cache ( suite_name , issue_number_cache , report_comment_id_cache = nil )
97+ described_class . report (
98+ summary : "#{ suite_name } regressed" ,
99+ suite_name : suite_name ,
100+ github_run_url : "https://github.com/run/1" ,
101+ bencher_url : "https://bencher.dev/dash" ,
102+ issue_number_cache : issue_number_cache ,
103+ report_comment_id_cache : report_comment_id_cache
104+ )
105+ end
106+
95107 context "when no regression issue exists yet" do
96108 before do
97109 capture_responses [ "issue list" ] = ""
98110 capture_responses [ "issue create" ] = "https://github.com/shakacode/react_on_rails/issues/123\n "
99111 capture_responses [ "comment list" ] = ""
112+ capture_responses [ "comment create" ] = "999\n "
100113 end
101114
102115 it "creates the issue, parses the number from the URL, and posts the first comment" do
103116 expect ( report ) . to eq ( "123" )
104- expect ( calls ) . to eq ( [ "label create" , "issue list" , "issue create" , "comment list" , "issue comment" ] )
117+ expect ( calls ) . to eq ( [ "label create" , "issue list" , "issue create" , "comment list" , "comment create" ] )
118+ end
119+
120+ it "reuses a just-created issue number for later suites in the same reporter run" do
121+ issue_number_cache = { }
122+
123+ expect ( report_with_cache ( "Core" , issue_number_cache ) ) . to eq ( "123" )
124+ expect ( report_with_cache ( "Pro" , issue_number_cache ) ) . to eq ( "123" )
125+
126+ expect ( calls . count ( "issue list" ) ) . to eq ( 1 )
127+ expect ( calls . count ( "issue create" ) ) . to eq ( 1 )
128+ end
129+
130+ it "reuses a just-created report comment for later suites in the same reporter run" do
131+ issue_number_cache = { }
132+ report_comment_id_cache = { }
133+ capture_responses [ "comment body" ] = "Core regressed"
134+
135+ expect ( report_with_cache ( "Core" , issue_number_cache , report_comment_id_cache ) ) . to eq ( "123" )
136+ expect ( report_with_cache ( "Pro" , issue_number_cache , report_comment_id_cache ) ) . to eq ( "123" )
137+
138+ expect ( calls . count ( "comment list" ) ) . to eq ( 1 )
139+ expect ( calls . count ( "comment create" ) ) . to eq ( 1 )
140+ expect ( calls ) . to include ( "comment patch" )
141+ expect ( posted_bodies . fetch ( "comment patch" ) ) . to include ( "Core regressed" )
142+ expect ( posted_bodies . fetch ( "comment patch" ) ) . to include ( "Pro regressed" )
143+ end
144+
145+ it "does not create duplicate same-run comments after a comment id parse miss" do
146+ issue_number_cache = { }
147+ report_comment_id_cache = { }
148+ capture_responses [ "comment create" ] = "\n "
149+
150+ expect ( report_with_cache ( "Core" , issue_number_cache , report_comment_id_cache ) ) . to eq ( "" )
151+ expect ( report_with_cache ( "Pro" , issue_number_cache , report_comment_id_cache ) ) . to eq ( "" )
152+
153+ expect ( calls . count ( "comment list" ) ) . to eq ( 1 )
154+ expect ( calls . count ( "comment create" ) ) . to eq ( 1 )
155+ expect ( calls ) . not_to include ( "comment patch" )
105156 end
106157 end
107158
@@ -163,7 +214,7 @@ def section_for(suite, content = "")
163214
164215 it "aborts without posting a duplicate comment" do
165216 expect ( report ) . to eq ( "" )
166- expect ( calls ) . not_to include ( "issue comment" )
217+ expect ( calls ) . not_to include ( "comment create " )
167218 expect ( calls ) . not_to include ( "comment patch" )
168219 end
169220 end
@@ -205,6 +256,16 @@ def section_for(suite, content = "")
205256 . and output ( "" ) . to_stderr
206257 expect ( calls ) . not_to include ( "comment list" )
207258 end
259+
260+ it "does not create duplicate same-run issues after the parse miss" do
261+ issue_number_cache = { }
262+
263+ expect ( report_with_cache ( "Core" , issue_number_cache ) ) . to eq ( "" )
264+ expect ( report_with_cache ( "Pro" , issue_number_cache ) ) . to eq ( "" )
265+
266+ expect ( calls . count ( "issue list" ) ) . to eq ( 1 )
267+ expect ( calls . count ( "issue create" ) ) . to eq ( 1 )
268+ end
208269 end
209270 end
210271
@@ -221,11 +282,13 @@ def section_for(suite, content = "")
221282 #!/usr/bin/env bash
222283 if [ "$1" = "issue" ] && [ "$2" = "create" ]; then
223284 echo "https://github.com/shakacode/react_on_rails/issues/7"
285+ elif [ "$1" = "api" ] && [ "$2" = "-X" ] && [ "$3" = "POST" ]; then
286+ echo "777"
224287 fi
225288 exit 0
226289 BASH
227290
228- def run_script ( script , artifacts_dir , gh_stub :)
291+ def run_script ( script , artifacts_dir , gh_stub :, extra_env : { } )
229292 Dir . mktmpdir do |bin_dir |
230293 File . write ( File . join ( bin_dir , "gh" ) , gh_stub )
231294 File . chmod ( 0o755 , File . join ( bin_dir , "gh" ) )
@@ -238,7 +301,7 @@ def run_script(script, artifacts_dir, gh_stub:)
238301 "GITHUB_RUN_ID" => "999" ,
239302 "GITHUB_RUN_NUMBER" => "42" ,
240303 "GITHUB_ACTOR" => "octocat"
241- }
304+ } . merge ( extra_env )
242305 Open3 . capture2e ( env , "ruby" , script , artifacts_dir )
243306 end
244307 end
@@ -275,6 +338,51 @@ def write_payload(dir, artifact:, suite:, shard_label: "1/1", summary: nil, regr
275338 end
276339 end
277340
341+ it "creates only one issue for multiple suites even when live issue lookup stays empty" do
342+ Dir . mktmpdir do |dir |
343+ write_payload ( dir , artifact : "regression-core" , suite : "Core" )
344+ write_payload ( dir , artifact : "regression-pro" , suite : "Pro" )
345+
346+ call_log = File . join ( dir , "gh-calls.log" )
347+ counting_gh = <<~BASH
348+ #!/usr/bin/env bash
349+ printf '%s\\ n' "$*" >> "$GH_CALL_LOG"
350+ if [ "$1" = "issue" ] && [ "$2" = "create" ]; then
351+ echo "https://github.com/shakacode/react_on_rails/issues/7"
352+ elif [ "$1" = "api" ] && [ "$2" = "-X" ] && [ "$3" = "POST" ]; then
353+ echo "777"
354+ fi
355+ exit 0
356+ BASH
357+
358+ output , status = run_script ( script , dir , gh_stub : counting_gh , extra_env : { "GH_CALL_LOG" => call_log } )
359+
360+ expect ( status ) . to be_success
361+ expect ( output ) . to match ( /issue #7/ )
362+ expect ( File . readlines ( call_log ) . count { |line | line . start_with? ( "issue create" ) } ) . to eq ( 1 )
363+ expect ( File . readlines ( call_log ) . count { |line | line . start_with? ( "api -X POST" ) } ) . to eq ( 1 )
364+ end
365+ end
366+
367+ it "shares one issue-number cache across suite reports in the same run" do
368+ Dir . mktmpdir do |dir |
369+ write_payload ( dir , artifact : "regression-core" , suite : "Core" )
370+ write_payload ( dir , artifact : "regression-pro" , suite : "Pro" )
371+
372+ caches = [ ]
373+ allow ( Github ) . to receive ( :run_url ) . and_return ( "https://github.com/run/1" )
374+ allow ( RegressionIssueReporter ) . to receive ( :report ) do |issue_number_cache :, **_attributes |
375+ caches << issue_number_cache
376+ issue_number_cache [ "created" ] = "7"
377+ "7"
378+ end
379+
380+ expect ( report_regressions ( dir ) ) . to be ( true )
381+ expect ( caches . size ) . to eq ( 2 )
382+ expect ( caches [ 0 ] ) . to equal ( caches [ 1 ] )
383+ end
384+ end
385+
278386 it "combines a sharded suite's payloads into a single report" do
279387 Dir . mktmpdir do |dir |
280388 write_payload ( dir , artifact : "regression-pro-shard-1" , suite : "Pro" , shard_label : "1/2" )
0 commit comments