@@ -187,7 +187,9 @@ async function getTsServerRepoResult(
187
187
downloadDir : string ,
188
188
replayScriptArtifactPath : string ,
189
189
rawErrorArtifactPath : string ,
190
- diagnosticOutput : boolean ) : Promise < RepoResult > {
190
+ diagnosticOutput : boolean ,
191
+ isPr : boolean ,
192
+ ) : Promise < RepoResult > {
191
193
192
194
if ( ! await cloneRepo ( repo , userTestsDir , downloadDir , diagnosticOutput ) ) {
193
195
return { status : "Git clone failed" } ;
@@ -233,7 +235,6 @@ async function getTsServerRepoResult(
233
235
}
234
236
235
237
console . log ( "No issues found" ) ;
236
- return { status : "Detected no interesting changes" } ;
237
238
case exercise . EXIT_LANGUAGE_SERVICE_DISABLED :
238
239
console . log ( "Skipping since language service was disabled" ) ;
239
240
return { status : "Language service disabled in new TS" } ;
@@ -253,9 +254,13 @@ async function getTsServerRepoResult(
253
254
return { status : "Unknown failure" } ;
254
255
}
255
256
256
- console . log ( `Issue found in ${ newTsServerPath } (new):` ) ;
257
- console . log ( insetLines ( prettyPrintServerHarnessOutput ( newSpawnResult . stdout , /*filter*/ false ) ) ) ;
258
- await fs . promises . writeFile ( rawErrorPath , prettyPrintServerHarnessOutput ( newSpawnResult . stdout , /*filter*/ false ) ) ;
257
+ const newServerFailed = ! newSpawnResult . code ;
258
+
259
+ if ( newServerFailed ) {
260
+ console . log ( `Issue found in ${ newTsServerPath } (new):` ) ;
261
+ console . log ( insetLines ( prettyPrintServerHarnessOutput ( newSpawnResult . stdout , /*filter*/ false ) ) ) ;
262
+ await fs . promises . writeFile ( rawErrorPath , prettyPrintServerHarnessOutput ( newSpawnResult . stdout , /*filter*/ false ) ) ;
263
+ }
259
264
260
265
console . log ( `Testing with ${ oldTsServerPath } (old)` ) ;
261
266
const oldSpawnResult = await spawnWithTimeoutAsync ( repoDir , process . argv [ 0 ] , [ path . join ( __dirname , ".." , "node_modules" , "@typescript" , "server-replay" , "replay.js" ) , repoDir , replayScriptPath , oldTsServerPath , "-u" ] , executionTimeout ) ;
@@ -268,13 +273,32 @@ async function getTsServerRepoResult(
268
273
// NB: Unlike newServerFailed, this includes timeouts because "it used to timeout" is useful context for an error in the new server
269
274
const oldServerFailed = ! oldSpawnResult || ! ! oldSpawnResult . code || ! ! oldSpawnResult . signal ;
270
275
276
+ if ( ! newServerFailed && ! oldServerFailed ) {
277
+ return { status : "Detected no interesting changes" } ;
278
+ }
279
+
271
280
if ( oldServerFailed ) {
272
281
console . log ( `Issue found in ${ oldTsServerPath } (old):` ) ;
273
282
console . log (
274
283
insetLines (
275
284
oldSpawnResult ?. stdout
276
285
? prettyPrintServerHarnessOutput ( oldSpawnResult . stdout , /*filter*/ false )
277
286
: `Timed out after ${ executionTimeout } ms` ) ) ;
287
+
288
+ // We don't want to drown PRs with comments.
289
+ // Override the results to say nothing interesting changed.
290
+ if ( isPr && newServerFailed && oldSpawnResult ) {
291
+ const oldOut = parseServerHarnessOutput ( oldSpawnResult . stdout ) ;
292
+ const newOut = parseServerHarnessOutput ( newSpawnResult . stdout ) ;
293
+
294
+ if (
295
+ typeof oldOut !== "string" && typeof newOut !== "string"
296
+ && oldOut . request_seq === newOut . request_seq
297
+ && oldOut . command === newOut . command
298
+ ) {
299
+ return { status : "Detected no interesting changes" } ;
300
+ }
301
+ }
278
302
}
279
303
280
304
const owner = repo . owner ? `${ mdEscape ( repo . owner ) } /` : "" ;
@@ -288,7 +312,7 @@ async function getTsServerRepoResult(
288
312
: `Timed out after ${ executionTimeout } ms` ;
289
313
summary += `
290
314
<details>
291
- <summary>:warning: Note that ${ path . basename ( path . dirname ( path . dirname ( oldTsServerPath ) ) ) } also had errors :warning:</summary>
315
+ <summary>:warning: Note that ${ path . basename ( path . dirname ( path . dirname ( oldTsServerPath ) ) ) } had errors :warning:</summary>
292
316
293
317
\`\`\`
294
318
${ oldServerError }
@@ -297,6 +321,16 @@ ${oldServerError}
297
321
</details>
298
322
299
323
` ;
324
+ if ( ! newServerFailed ) {
325
+ summary += `
326
+ :tada: New server no longer has errors :tada:
327
+ ` ;
328
+ return { status : "Detected interesting changes" , summary }
329
+ }
330
+ }
331
+
332
+ if ( ! newServerFailed ) {
333
+ return { status : "Detected no interesting changes" } ;
300
334
}
301
335
302
336
summary += `
@@ -621,6 +655,8 @@ export async function mainAsync(params: GitParams | UserParams): Promise<void> {
621
655
// An object is easier to de/serialize than a real map
622
656
const statusCounts : { [ P in RepoStatus ] ?: number } = { } ;
623
657
658
+ const isPr = params . testType === "user" && ! ! params . prNumber
659
+
624
660
let i = 1 ;
625
661
for ( const repo of repos ) {
626
662
console . log ( `Starting #${ i ++ } / ${ repos . length } : ${ repo . url ?? repo . name } ` ) ;
@@ -637,7 +673,7 @@ export async function mainAsync(params: GitParams | UserParams): Promise<void> {
637
673
const rawErrorFileName = `${ repoPrefix } .${ rawErrorFileNameSuffix } ` ;
638
674
const { status, summary, replayScriptPath, rawErrorPath } = params . entrypoint === "tsc"
639
675
? await getTscRepoResult ( repo , userTestsDir , oldTsEntrypointPath , newTsEntrypointPath , params . buildWithNewWhenOldFails , downloadDir , diagnosticOutput )
640
- : await getTsServerRepoResult ( repo , userTestsDir , oldTsEntrypointPath , newTsEntrypointPath , downloadDir , path . join ( params . resultDirName , replayScriptFileName ) , path . join ( params . resultDirName , rawErrorFileName ) , diagnosticOutput ) ;
676
+ : await getTsServerRepoResult ( repo , userTestsDir , oldTsEntrypointPath , newTsEntrypointPath , downloadDir , path . join ( params . resultDirName , replayScriptFileName ) , path . join ( params . resultDirName , rawErrorFileName ) , diagnosticOutput , isPr ) ;
641
677
console . log ( `Repo ${ repo . url ?? repo . name } had status "${ status } "` ) ;
642
678
statusCounts [ status ] = ( statusCounts [ status ] ?? 0 ) + 1 ;
643
679
if ( summary ) {
@@ -805,24 +841,39 @@ ${spawnResult.stderr}
805
841
` ) ;
806
842
}
807
843
808
- function prettyPrintServerHarnessOutput ( error : string , filter : boolean ) : string {
809
- try {
810
- const errorObj = JSON . parse ( error ) ;
811
- if ( errorObj . message ) {
812
- return `Req #${ errorObj . request_seq } - ${ errorObj . command }
813
- ${ filter ? filterToTsserverLines ( errorObj . message ) : errorObj . message } `;
814
- }
815
844
816
- // It's not really clear how this could happen, but reporting the whole repsonse should be fine
817
- // if there's no message property
818
- return JSON . stringify ( errorObj , undefined , 2 ) ;
845
+ export interface ServerHarnessOutput {
846
+ request_seq : number ;
847
+ command : string ;
848
+ message : string
849
+ }
850
+
851
+ function parseServerHarnessOutput ( error : string ) : ServerHarnessOutput | string {
852
+ try {
853
+ return JSON . parse ( error )
819
854
}
820
855
catch {
821
856
// Sometimes, the response isn't JSON and that's fine
822
857
return error ;
823
858
}
824
859
}
825
860
861
+ function prettyPrintServerHarnessOutput ( error : string , filter : boolean ) : string {
862
+ const errorObj = parseServerHarnessOutput ( error ) ;
863
+ if ( typeof errorObj === "string" ) {
864
+ return errorObj ;
865
+ }
866
+
867
+ if ( errorObj . message ) {
868
+ return `Req #${ errorObj . request_seq } - ${ errorObj . command }
869
+ ${ filter ? filterToTsserverLines ( errorObj . message ) : errorObj . message } `;
870
+ }
871
+
872
+ // It's not really clear how this could happen, but reporting the whole repsonse should be fine
873
+ // if there's no message property
874
+ return JSON . stringify ( errorObj , undefined , 2 ) ;
875
+ }
876
+
826
877
function filterToTsserverLines ( stackLines : string ) : string {
827
878
const tsserverRegex = / ^ .* t s s e r v e r \. j s .* $ / mg;
828
879
let tsserverLines = "" ;
0 commit comments