@@ -26,6 +26,8 @@ import { createTimestampFile, showAndLogErrorMessage } from '../helpers';
2626import * as fs from 'fs-extra' ;
2727
2828export class VariantAnalysisManager extends DisposableObject implements VariantAnalysisViewManager < VariantAnalysisView > {
29+ private static readonly REPO_STATES_FILENAME = 'repo_states.json' ;
30+
2931 private readonly _onVariantAnalysisAdded = this . push ( new EventEmitter < VariantAnalysis > ( ) ) ;
3032 public readonly onVariantAnalysisAdded = this . _onVariantAnalysisAdded . event ;
3133 private readonly _onVariantAnalysisStatusUpdated = this . push ( new EventEmitter < VariantAnalysis > ( ) ) ;
@@ -40,6 +42,8 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
4042 private static readonly maxConcurrentDownloads = 3 ;
4143 private readonly queue = new PQueue ( { concurrency : VariantAnalysisManager . maxConcurrentDownloads } ) ;
4244
45+ private readonly repoStates = new Map < number , Record < number , VariantAnalysisScannedRepositoryState > > ( ) ;
46+
4347 constructor (
4448 private readonly ctx : ExtensionContext ,
4549 private readonly storagePath : string ,
@@ -60,6 +64,15 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
6064 this . _onVariantAnalysisRemoved . fire ( variantAnalysis ) ;
6165 } else {
6266 await this . setVariantAnalysis ( variantAnalysis ) ;
67+
68+ try {
69+ const repoStates = await fs . readJson ( this . getRepoStatesStoragePath ( variantAnalysis . id ) ) ;
70+ this . repoStates . set ( variantAnalysis . id , repoStates ) ;
71+ } catch ( e ) {
72+ // Ignore this error, we simply might not have downloaded anything yet
73+ this . repoStates . set ( variantAnalysis . id , { } ) ;
74+ }
75+
6376 if ( ! await isVariantAnalysisComplete ( variantAnalysis , this . makeResultDownloadChecker ( variantAnalysis ) ) ) {
6477 void commands . executeCommand ( 'codeQL.monitorVariantAnalysis' , variantAnalysis ) ;
6578 }
@@ -120,6 +133,10 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
120133 return this . variantAnalyses . get ( variantAnalysisId ) ;
121134 }
122135
136+ public async getRepoStates ( variantAnalysisId : number ) : Promise < VariantAnalysisScannedRepositoryState [ ] > {
137+ return Object . values ( this . repoStates . get ( variantAnalysisId ) ?? { } ) ;
138+ }
139+
123140 public get variantAnalysesSize ( ) : number {
124141 return this . variantAnalyses . size ;
125142 }
@@ -152,6 +169,8 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
152169
153170 await this . prepareStorageDirectory ( variantAnalysis . id ) ;
154171
172+ this . repoStates . set ( variantAnalysis . id , { } ) ;
173+
155174 this . _onVariantAnalysisAdded . fire ( variantAnalysis ) ;
156175 }
157176
@@ -166,6 +185,14 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
166185
167186 private async onRepoStateUpdated ( variantAnalysisId : number , repoState : VariantAnalysisScannedRepositoryState ) : Promise < void > {
168187 await this . getView ( variantAnalysisId ) ?. updateRepoState ( repoState ) ;
188+
189+ let repoStates = this . repoStates . get ( variantAnalysisId ) ;
190+ if ( ! repoStates ) {
191+ repoStates = { } ;
192+ this . repoStates . set ( variantAnalysisId , repoStates ) ;
193+ }
194+
195+ repoStates [ repoState . repositoryId ] = repoState ;
169196 }
170197
171198 public async monitorVariantAnalysis (
@@ -180,6 +207,10 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
180207 variantAnalysis : VariantAnalysis ,
181208 cancellationToken : CancellationToken
182209 ) : Promise < void > {
210+ if ( this . repoStates . get ( variantAnalysis . id ) ?. [ scannedRepo . repository . id ] ?. downloadStatus === VariantAnalysisScannedRepositoryDownloadStatus . Succeeded ) {
211+ return ;
212+ }
213+
183214 const repoState = {
184215 repositoryId : scannedRepo . repository . id ,
185216 downloadStatus : VariantAnalysisScannedRepositoryDownloadStatus . Pending ,
@@ -216,11 +247,19 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
216247 repoState . downloadStatus = VariantAnalysisScannedRepositoryDownloadStatus . InProgress ;
217248 await this . onRepoStateUpdated ( variantAnalysis . id , repoState ) ;
218249
219- await this . variantAnalysisResultsManager . download ( credentials , variantAnalysis . id , repoTask , this . getVariantAnalysisStorageLocation ( variantAnalysis . id ) ) ;
250+ try {
251+ await this . variantAnalysisResultsManager . download ( credentials , variantAnalysis . id , repoTask , this . getVariantAnalysisStorageLocation ( variantAnalysis . id ) ) ;
252+ } catch ( e ) {
253+ repoState . downloadStatus = VariantAnalysisScannedRepositoryDownloadStatus . Failed ;
254+ await this . onRepoStateUpdated ( variantAnalysis . id , repoState ) ;
255+ throw new Error ( `Could not download the results for variant analysis with id: ${ variantAnalysis . id } . Error: ${ getErrorMessage ( e ) } ` ) ;
256+ }
220257 }
221258
222259 repoState . downloadStatus = VariantAnalysisScannedRepositoryDownloadStatus . Succeeded ;
223260 await this . onRepoStateUpdated ( variantAnalysis . id , repoState ) ;
261+
262+ await fs . outputJson ( this . getRepoStatesStoragePath ( variantAnalysis . id ) , this . repoStates . get ( variantAnalysis . id ) ) ;
224263 }
225264
226265 public async enqueueDownload (
@@ -242,6 +281,13 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
242281 ) ;
243282 }
244283
284+ private getRepoStatesStoragePath ( variantAnalysisId : number ) : string {
285+ return path . join (
286+ this . getVariantAnalysisStorageLocation ( variantAnalysisId ) ,
287+ VariantAnalysisManager . REPO_STATES_FILENAME
288+ ) ;
289+ }
290+
245291 /**
246292 * Prepares a directory for storing results for a variant analysis.
247293 * This directory contains a timestamp file, which will be
0 commit comments