@@ -10,6 +10,10 @@ import path from 'node:path';
1010import { fileURLToPath } from 'node:url' ;
1111import { type SimpleGit , simpleGit } from 'simple-git' ;
1212import { type MockInstance , expect } from 'vitest' ;
13+ import {
14+ type ReportFragment ,
15+ downloadFromPortal ,
16+ } from '@code-pushup/portal-client' ;
1317import type { CoreConfig } from '@code-pushup/models' ;
1418import {
1519 cleanTestFolder ,
@@ -29,40 +33,57 @@ import type {
2933import type { MonorepoTool } from './monorepo/index.js' ;
3034import { runInCI } from './run.js' ;
3135
32- describe ( 'runInCI' , ( ) => {
33- const fixturesDir = path . join (
34- fileURLToPath ( path . dirname ( import . meta. url ) ) ,
35- '..' ,
36- '..' ,
37- 'mocks' ,
38- 'fixtures' ,
39- ) ;
40- const reportsDir = path . join ( fixturesDir , 'outputs' ) ;
41- const workDir = path . join ( process . cwd ( ) , 'tmp' , 'ci' , 'run-test' ) ;
42-
43- const fixturePaths = {
44- reports : {
45- before : {
46- json : path . join ( reportsDir , 'report-before.json' ) ,
47- md : path . join ( reportsDir , 'report-before.md' ) ,
48- } ,
49- after : {
50- json : path . join ( reportsDir , 'report-after.json' ) ,
51- md : path . join ( reportsDir , 'report-after.md' ) ,
52- } ,
36+ vi . mock ( '@code-pushup/portal-client' , async importOriginal => {
37+ const mod : typeof import ( '@code-pushup/portal-client' ) =
38+ await importOriginal ( ) ;
39+ return {
40+ ...mod ,
41+ downloadFromPortal : vi . fn ( simulateDownloadFromPortal ) ,
42+ } ;
43+ } ) ;
44+
45+ const fixturesDir = path . join (
46+ fileURLToPath ( path . dirname ( import . meta. url ) ) ,
47+ '..' ,
48+ '..' ,
49+ 'mocks' ,
50+ 'fixtures' ,
51+ ) ;
52+ const reportsDir = path . join ( fixturesDir , 'outputs' ) ;
53+ const workDir = path . join ( process . cwd ( ) , 'tmp' , 'ci' , 'run-test' ) ;
54+
55+ const fixturePaths = {
56+ reports : {
57+ before : {
58+ json : path . join ( reportsDir , 'report-before.json' ) ,
59+ md : path . join ( reportsDir , 'report-before.md' ) ,
60+ portal : path . join ( reportsDir , 'report-before.portal.json' ) ,
5361 } ,
54- diffs : {
55- project : {
56- json : path . join ( reportsDir , 'diff-project.json' ) ,
57- md : path . join ( reportsDir , 'diff-project.md' ) ,
58- } ,
59- merged : {
60- md : path . join ( reportsDir , 'diff-merged.md' ) ,
61- } ,
62+ after : {
63+ json : path . join ( reportsDir , 'report-after.json' ) ,
64+ md : path . join ( reportsDir , 'report-after.md' ) ,
6265 } ,
63- config : path . join ( reportsDir , 'config.json' ) ,
64- } ;
66+ } ,
67+ diffs : {
68+ project : {
69+ json : path . join ( reportsDir , 'diff-project.json' ) ,
70+ md : path . join ( reportsDir , 'diff-project.md' ) ,
71+ } ,
72+ merged : {
73+ md : path . join ( reportsDir , 'diff-merged.md' ) ,
74+ } ,
75+ } ,
76+ config : {
77+ base : path . join ( reportsDir , 'config.json' ) ,
78+ portal : path . join ( reportsDir , 'config.portal.json' ) ,
79+ } ,
80+ } ;
81+
82+ function simulateDownloadFromPortal ( ) {
83+ return utils . readJsonFile < ReportFragment > ( fixturePaths . reports . before . portal ) ;
84+ }
6585
86+ describe ( 'runInCI' , ( ) => {
6687 const logger : Logger = {
6788 error : vi . fn ( ) ,
6889 warn : vi . fn ( ) ,
@@ -87,6 +108,8 @@ describe('runInCI', () => {
87108 onStdout : expect . any ( Function ) ,
88109 } ) ;
89110
111+ let includeUploadConfig : boolean ;
112+
90113 let git : SimpleGit ;
91114
92115 let cwdSpy : MockInstance <
@@ -120,7 +143,12 @@ describe('runInCI', () => {
120143 break ;
121144
122145 case 'print-config' :
123- let content = await readFile ( fixturePaths . config , 'utf8' ) ;
146+ let content = await readFile (
147+ includeUploadConfig
148+ ? fixturePaths . config . portal
149+ : fixturePaths . config . base ,
150+ 'utf8' ,
151+ ) ;
124152 if ( nxMatch ) {
125153 // simulate effect of custom persist.outputDir per Nx project
126154 const config = JSON . parse ( content ) as CoreConfig ;
@@ -184,6 +212,8 @@ describe('runInCI', () => {
184212 const outputDir = path . join ( workDir , '.code-pushup' , '.ci' ) ;
185213
186214 beforeEach ( async ( ) => {
215+ includeUploadConfig = false ;
216+
187217 const originalExecuteProcess = utils . executeProcess ;
188218 executeProcessSpy = vi
189219 . spyOn ( utils , 'executeProcess' )
@@ -441,6 +471,79 @@ describe('runInCI', () => {
441471 expect ( logger . debug ) . toHaveBeenCalled ( ) ;
442472 } ) ;
443473
474+ it ( 'should use cached old report from portal when upload is configured' , async ( ) => {
475+ includeUploadConfig = true ;
476+
477+ const api : ProviderAPIClient = {
478+ maxCommentChars : 1_000_000 ,
479+ createComment : vi . fn ( ) . mockResolvedValue ( mockComment ) ,
480+ updateComment : vi . fn ( ) ,
481+ listComments : vi . fn ( ) . mockResolvedValue ( [ ] ) ,
482+ downloadReportArtifact : vi . fn ( ) ,
483+ } ;
484+
485+ await expect ( runInCI ( refs , api , options , git ) ) . resolves . toEqual ( {
486+ mode : 'standalone' ,
487+ commentId : mockComment . id ,
488+ newIssues : [ ] ,
489+ files : {
490+ current : {
491+ json : path . join ( outputDir , '.current/report.json' ) ,
492+ md : path . join ( outputDir , '.current/report.md' ) ,
493+ } ,
494+ previous : {
495+ json : path . join ( outputDir , '.previous/report.json' ) ,
496+ } ,
497+ comparison : {
498+ json : path . join ( outputDir , '.comparison/report-diff.json' ) ,
499+ md : path . join ( outputDir , '.comparison/report-diff.md' ) ,
500+ } ,
501+ } ,
502+ } satisfies RunResult ) ;
503+
504+ expect ( downloadFromPortal ) . toHaveBeenCalledWith ( {
505+ server : 'https://api.code-pushup.dunder-mifflin.org/graphql' ,
506+ apiKey : 'cp_abcdef0123456789' ,
507+ parameters : {
508+ organization : 'dunder-mifflin' ,
509+ project : 'website' ,
510+ } ,
511+ } ) ;
512+
513+ expect ( api . downloadReportArtifact ) . not . toHaveBeenCalled ( ) ;
514+
515+ expect ( utils . executeProcess ) . toHaveBeenCalledTimes ( 3 ) ;
516+ expect ( utils . executeProcess ) . toHaveBeenNthCalledWith ( 1 , {
517+ command : options . bin ,
518+ args : [ 'print-config' , expect . stringMatching ( / ^ - - o u t p u t = .* \. j s o n $ / ) ] ,
519+ cwd : workDir ,
520+ observer : expectedObserver ,
521+ } satisfies utils . ProcessConfig ) ;
522+ expect ( utils . executeProcess ) . toHaveBeenNthCalledWith ( 2 , {
523+ command : options . bin ,
524+ args : [ ] ,
525+ cwd : workDir ,
526+ observer : expectedObserver ,
527+ } satisfies utils . ProcessConfig ) ;
528+ expect ( utils . executeProcess ) . toHaveBeenNthCalledWith ( 3 , {
529+ command : options . bin ,
530+ args : [
531+ 'compare' ,
532+ `--before=${ path . join ( outputDir , '.previous/report.json' ) } ` ,
533+ `--after=${ path . join ( outputDir , '.current/report.json' ) } ` ,
534+ '--persist.format=json' ,
535+ '--persist.format=md' ,
536+ ] ,
537+ cwd : workDir ,
538+ observer : expectedObserver ,
539+ } satisfies utils . ProcessConfig ) ;
540+
541+ expect ( logger . error ) . not . toHaveBeenCalled ( ) ;
542+ expect ( logger . warn ) . not . toHaveBeenCalled ( ) ;
543+ expect ( logger . info ) . toHaveBeenCalled ( ) ;
544+ expect ( logger . debug ) . toHaveBeenCalled ( ) ;
545+ } ) ;
546+
444547 it ( 'should skip comment if disabled' , async ( ) => {
445548 const api : ProviderAPIClient = {
446549 maxCommentChars : 1_000_000 ,
0 commit comments