@@ -4,7 +4,8 @@ import * as archiveFilesystemProvider from './archive-filesystem-provider';
44import { DistributionConfigListener , QueryServerConfigListener } from './config' ;
55import { DatabaseManager } from './databases' ;
66import { DatabaseUI } from './databases-ui' ;
7- import { DistributionUpdateCheckResultKind , DistributionManager , FindDistributionResult , FindDistributionResultKind , GithubApiError , DEFAULT_DISTRIBUTION_VERSION_CONSTRAINT } from './distribution' ;
7+ import { DistributionUpdateCheckResultKind , DistributionManager , FindDistributionResult , FindDistributionResultKind , GithubApiError ,
8+ DEFAULT_DISTRIBUTION_VERSION_CONSTRAINT , GithubRateLimitedError } from './distribution' ;
89import * as helpers from './helpers' ;
910import { spawnIdeServer } from './ide-server' ;
1011import { InterfaceManager , WebviewReveal } from './interface' ;
@@ -79,19 +80,24 @@ export async function activate(ctx: ExtensionContext): Promise<void> {
7980 const shouldUpdateOnNextActivationKey = "shouldUpdateOnNextActivation" ;
8081
8182 registerErrorStubs ( ctx , [ checkForUpdatesCommand ] , command => ( ) => {
82- Window . showErrorMessage ( `Can't execute ${ command } : waiting to finish loading CodeQL CLI.` ) ;
83+ helpers . showAndLogErrorMessage ( `Can't execute ${ command } : waiting to finish loading CodeQL CLI.` ) ;
8384 } ) ;
8485
85- async function installOrUpdateDistributionWithProgressTitle ( progressTitle : string , isSilentIfCannotUpdate : boolean ) : Promise < void > {
86+ interface ReportingConfig {
87+ shouldDisplayMessageWhenNoUpdates : boolean ;
88+ shouldErrorIfUpdateFails : boolean ;
89+ }
90+
91+ async function installOrUpdateDistributionWithProgressTitle ( progressTitle : string , reportingConfig : ReportingConfig ) : Promise < void > {
8692 const result = await distributionManager . checkForUpdatesToExtensionManagedDistribution ( ) ;
8793 switch ( result . kind ) {
8894 case DistributionUpdateCheckResultKind . AlreadyUpToDate :
89- if ( ! isSilentIfCannotUpdate ) {
95+ if ( reportingConfig . shouldDisplayMessageWhenNoUpdates ) {
9096 helpers . showAndLogInformationMessage ( "CodeQL CLI already up to date." ) ;
9197 }
9298 break ;
9399 case DistributionUpdateCheckResultKind . InvalidDistributionLocation :
94- if ( ! isSilentIfCannotUpdate ) {
100+ if ( reportingConfig . shouldDisplayMessageWhenNoUpdates ) {
95101 helpers . showAndLogErrorMessage ( "CodeQL CLI is installed externally so could not be updated." ) ;
96102 }
97103 break ;
@@ -121,34 +127,32 @@ export async function activate(ctx: ExtensionContext): Promise<void> {
121127 }
122128 }
123129
124- async function installOrUpdateDistribution ( isSilentIfCannotUpdate : boolean ) : Promise < void > {
130+ async function installOrUpdateDistribution ( reportingConfig : ReportingConfig ) : Promise < void > {
125131 if ( isInstallingOrUpdatingDistribution ) {
126132 throw new Error ( "Already installing or updating CodeQL CLI" ) ;
127133 }
128134 isInstallingOrUpdatingDistribution = true ;
135+ const codeQlInstalled = await distributionManager . getCodeQlPathWithoutVersionCheck ( ) !== undefined ;
136+ const willUpdateCodeQl = ctx . globalState . get ( shouldUpdateOnNextActivationKey ) ;
137+ const messageText = willUpdateCodeQl ? "Updating CodeQL CLI" :
138+ codeQlInstalled ? "Checking for updates to CodeQL CLI" : "Installing CodeQL CLI" ;
129139 try {
130- const codeQlInstalled = await distributionManager . getCodeQlPathWithoutVersionCheck ( ) !== undefined ;
131- const messageText = ctx . globalState . get ( shouldUpdateOnNextActivationKey ) ? "Updating CodeQL CLI" :
132- codeQlInstalled ? "Checking for updates to CodeQL CLI" : "Installing CodeQL CLI" ;
133- await installOrUpdateDistributionWithProgressTitle ( messageText , isSilentIfCannotUpdate ) ;
140+ await installOrUpdateDistributionWithProgressTitle ( messageText , reportingConfig ) ;
134141 } catch ( e ) {
135142 // Don't rethrow the exception, because if the config is changed, we want to be able to retry installing
136143 // or updating the distribution.
137- if ( e instanceof GithubApiError && ( e . status == 404 || e . status == 403 || e . status === 401 ) ) {
138- const errorMessageResponse = Window . showErrorMessage ( "Unable to download CodeQL CLI. See " +
139- "https://github.com/github/vscode-codeql/blob/master/extensions/ql-vscode/README.md for more details about how " +
140- "to obtain CodeQL CLI." , "Edit Settings" ) ;
141- // We're deliberately not `await`ing this promise, just
142- // asynchronously letting the user follow the convenience link
143- // if they want to.
144- errorMessageResponse . then ( response => {
145- if ( response !== undefined ) {
146- commands . executeCommand ( 'workbench.action.openSettingsJson' ) ;
147- }
148- } ) ;
149- } else {
150- helpers . showAndLogErrorMessage ( "Unable to download CodeQL CLI. " + e ) ;
144+ const alertFunction = ( codeQlInstalled && ! reportingConfig . shouldErrorIfUpdateFails ) ?
145+ helpers . showAndLogWarningMessage : helpers . showAndLogErrorMessage ;
146+ const taskDescription = ( willUpdateCodeQl ? "update" :
147+ codeQlInstalled ? "check for updates to" : "install" ) + " CodeQL CLI" ;
148+
149+ if ( e instanceof GithubRateLimitedError ) {
150+ alertFunction ( `Rate limited while trying to ${ taskDescription } . Please try again after ` +
151+ `your rate limit window resets at ${ e . rateLimitResetDate . toLocaleString ( ) } .` ) ;
152+ } else if ( e instanceof GithubApiError ) {
153+ alertFunction ( `Encountered GitHub API error while trying to ${ taskDescription } . ` + e ) ;
151154 }
155+ alertFunction ( `Unable to ${ taskDescription } . ` + e ) ;
152156 } finally {
153157 isInstallingOrUpdatingDistribution = false ;
154158 }
@@ -176,10 +180,8 @@ export async function activate(ctx: ExtensionContext): Promise<void> {
176180 return result ;
177181 }
178182
179- async function installOrUpdateThenTryActivate ( isSilentIfCannotUpdate : boolean ) : Promise < void > {
180- if ( ! isInstallingOrUpdatingDistribution ) {
181- await installOrUpdateDistribution ( isSilentIfCannotUpdate ) ;
182- }
183+ async function installOrUpdateThenTryActivate ( reportingConfig : ReportingConfig ) : Promise < void > {
184+ await installOrUpdateDistribution ( reportingConfig ) ;
183185
184186 // Display the warnings even if the extension has already activated.
185187 const distributionResult = await getDistributionDisplayingDistributionWarnings ( ) ;
@@ -189,18 +191,30 @@ export async function activate(ctx: ExtensionContext): Promise<void> {
189191 } else if ( distributionResult . kind === FindDistributionResultKind . NoDistribution ) {
190192 registerErrorStubs ( ctx , [ checkForUpdatesCommand ] , command => async ( ) => {
191193 const installActionName = "Install CodeQL CLI" ;
192- const chosenAction = await Window . showErrorMessage ( `Can't execute ${ command } : missing CodeQL CLI.` , installActionName ) ;
194+ const chosenAction = await helpers . showAndLogErrorMessage ( `Can't execute ${ command } : missing CodeQL CLI.` , installActionName ) ;
193195 if ( chosenAction === installActionName ) {
194- installOrUpdateThenTryActivate ( true ) ;
196+ installOrUpdateThenTryActivate ( {
197+ shouldDisplayMessageWhenNoUpdates : false ,
198+ shouldErrorIfUpdateFails : true
199+ } ) ;
195200 }
196201 } ) ;
197202 }
198203 }
199204
200- ctx . subscriptions . push ( distributionConfigListener . onDidChangeDistributionConfiguration ( ( ) => installOrUpdateThenTryActivate ( true ) ) ) ;
201- ctx . subscriptions . push ( commands . registerCommand ( checkForUpdatesCommand , ( ) => installOrUpdateThenTryActivate ( false ) ) ) ;
202-
203- await installOrUpdateThenTryActivate ( true ) ;
205+ ctx . subscriptions . push ( distributionConfigListener . onDidChangeDistributionConfiguration ( ( ) => installOrUpdateThenTryActivate ( {
206+ shouldDisplayMessageWhenNoUpdates : false ,
207+ shouldErrorIfUpdateFails : true
208+ } ) ) ) ;
209+ ctx . subscriptions . push ( commands . registerCommand ( checkForUpdatesCommand , ( ) => installOrUpdateThenTryActivate ( {
210+ shouldDisplayMessageWhenNoUpdates : true ,
211+ shouldErrorIfUpdateFails : true
212+ } ) ) ) ;
213+
214+ await installOrUpdateThenTryActivate ( {
215+ shouldDisplayMessageWhenNoUpdates : false ,
216+ shouldErrorIfUpdateFails : ! ! ctx . globalState . get ( shouldUpdateOnNextActivationKey )
217+ } ) ;
204218}
205219
206220async function activateWithInstalledDistribution ( ctx : ExtensionContext , distributionManager : DistributionManager ) {
0 commit comments