@@ -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' ;
@@ -82,19 +83,24 @@ export async function activate(ctx: ExtensionContext): Promise<void> {
8283 const shouldUpdateOnNextActivationKey = "shouldUpdateOnNextActivation" ;
8384
8485 registerErrorStubs ( ctx , [ checkForUpdatesCommand ] , command => ( ) => {
85- Window . showErrorMessage ( `Can't execute ${ command } : waiting to finish loading CodeQL CLI.` ) ;
86+ helpers . showAndLogErrorMessage ( `Can't execute ${ command } : waiting to finish loading CodeQL CLI.` ) ;
8687 } ) ;
8788
88- async function installOrUpdateDistributionWithProgressTitle ( progressTitle : string , isSilentIfCannotUpdate : boolean ) : Promise < void > {
89+ interface ReportingConfig {
90+ shouldDisplayMessageWhenNoUpdates : boolean ;
91+ shouldErrorIfUpdateFails : boolean ;
92+ }
93+
94+ async function installOrUpdateDistributionWithProgressTitle ( progressTitle : string , reportingConfig : ReportingConfig ) : Promise < void > {
8995 const result = await distributionManager . checkForUpdatesToExtensionManagedDistribution ( ) ;
9096 switch ( result . kind ) {
9197 case DistributionUpdateCheckResultKind . AlreadyUpToDate :
92- if ( ! isSilentIfCannotUpdate ) {
98+ if ( reportingConfig . shouldDisplayMessageWhenNoUpdates ) {
9399 helpers . showAndLogInformationMessage ( "CodeQL CLI already up to date." ) ;
94100 }
95101 break ;
96102 case DistributionUpdateCheckResultKind . InvalidDistributionLocation :
97- if ( ! isSilentIfCannotUpdate ) {
103+ if ( reportingConfig . shouldDisplayMessageWhenNoUpdates ) {
98104 helpers . showAndLogErrorMessage ( "CodeQL CLI is installed externally so could not be updated." ) ;
99105 }
100106 break ;
@@ -124,34 +130,32 @@ export async function activate(ctx: ExtensionContext): Promise<void> {
124130 }
125131 }
126132
127- async function installOrUpdateDistribution ( isSilentIfCannotUpdate : boolean ) : Promise < void > {
133+ async function installOrUpdateDistribution ( reportingConfig : ReportingConfig ) : Promise < void > {
128134 if ( isInstallingOrUpdatingDistribution ) {
129135 throw new Error ( "Already installing or updating CodeQL CLI" ) ;
130136 }
131137 isInstallingOrUpdatingDistribution = true ;
138+ const codeQlInstalled = await distributionManager . getCodeQlPathWithoutVersionCheck ( ) !== undefined ;
139+ const willUpdateCodeQl = ctx . globalState . get ( shouldUpdateOnNextActivationKey ) ;
140+ const messageText = willUpdateCodeQl ? "Updating CodeQL CLI" :
141+ codeQlInstalled ? "Checking for updates to CodeQL CLI" : "Installing CodeQL CLI" ;
132142 try {
133- const codeQlInstalled = await distributionManager . getCodeQlPathWithoutVersionCheck ( ) !== undefined ;
134- const messageText = ctx . globalState . get ( shouldUpdateOnNextActivationKey ) ? "Updating CodeQL CLI" :
135- codeQlInstalled ? "Checking for updates to CodeQL CLI" : "Installing CodeQL CLI" ;
136- await installOrUpdateDistributionWithProgressTitle ( messageText , isSilentIfCannotUpdate ) ;
143+ await installOrUpdateDistributionWithProgressTitle ( messageText , reportingConfig ) ;
137144 } catch ( e ) {
138145 // Don't rethrow the exception, because if the config is changed, we want to be able to retry installing
139146 // or updating the distribution.
140- if ( e instanceof GithubApiError && ( e . status == 404 || e . status == 403 || e . status === 401 ) ) {
141- const errorMessageResponse = Window . showErrorMessage ( "Unable to download CodeQL CLI. See " +
142- "https://github.com/github/vscode-codeql/blob/master/extensions/ql-vscode/README.md for more details about how " +
143- "to obtain CodeQL CLI." , "Edit Settings" ) ;
144- // We're deliberately not `await`ing this promise, just
145- // asynchronously letting the user follow the convenience link
146- // if they want to.
147- errorMessageResponse . then ( response => {
148- if ( response !== undefined ) {
149- commands . executeCommand ( 'workbench.action.openSettingsJson' ) ;
150- }
151- } ) ;
152- } else {
153- helpers . showAndLogErrorMessage ( "Unable to download CodeQL CLI. " + e ) ;
147+ const alertFunction = ( codeQlInstalled && ! reportingConfig . shouldErrorIfUpdateFails ) ?
148+ helpers . showAndLogWarningMessage : helpers . showAndLogErrorMessage ;
149+ const taskDescription = ( willUpdateCodeQl ? "update" :
150+ codeQlInstalled ? "check for updates to" : "install" ) + " CodeQL CLI" ;
151+
152+ if ( e instanceof GithubRateLimitedError ) {
153+ alertFunction ( `Rate limited while trying to ${ taskDescription } . Please try again after ` +
154+ `your rate limit window resets at ${ e . rateLimitResetDate . toLocaleString ( ) } .` ) ;
155+ } else if ( e instanceof GithubApiError ) {
156+ alertFunction ( `Encountered GitHub API error while trying to ${ taskDescription } . ` + e ) ;
154157 }
158+ alertFunction ( `Unable to ${ taskDescription } . ` + e ) ;
155159 } finally {
156160 isInstallingOrUpdatingDistribution = false ;
157161 }
@@ -179,10 +183,8 @@ export async function activate(ctx: ExtensionContext): Promise<void> {
179183 return result ;
180184 }
181185
182- async function installOrUpdateThenTryActivate ( isSilentIfCannotUpdate : boolean ) : Promise < void > {
183- if ( ! isInstallingOrUpdatingDistribution ) {
184- await installOrUpdateDistribution ( isSilentIfCannotUpdate ) ;
185- }
186+ async function installOrUpdateThenTryActivate ( reportingConfig : ReportingConfig ) : Promise < void > {
187+ await installOrUpdateDistribution ( reportingConfig ) ;
186188
187189 // Display the warnings even if the extension has already activated.
188190 const distributionResult = await getDistributionDisplayingDistributionWarnings ( ) ;
@@ -192,18 +194,30 @@ export async function activate(ctx: ExtensionContext): Promise<void> {
192194 } else if ( distributionResult . kind === FindDistributionResultKind . NoDistribution ) {
193195 registerErrorStubs ( ctx , [ checkForUpdatesCommand ] , command => async ( ) => {
194196 const installActionName = "Install CodeQL CLI" ;
195- const chosenAction = await Window . showErrorMessage ( `Can't execute ${ command } : missing CodeQL CLI.` , installActionName ) ;
197+ const chosenAction = await helpers . showAndLogErrorMessage ( `Can't execute ${ command } : missing CodeQL CLI.` , installActionName ) ;
196198 if ( chosenAction === installActionName ) {
197- installOrUpdateThenTryActivate ( true ) ;
199+ installOrUpdateThenTryActivate ( {
200+ shouldDisplayMessageWhenNoUpdates : false ,
201+ shouldErrorIfUpdateFails : true
202+ } ) ;
198203 }
199204 } ) ;
200205 }
201206 }
202207
203- ctx . subscriptions . push ( distributionConfigListener . onDidChangeDistributionConfiguration ( ( ) => installOrUpdateThenTryActivate ( true ) ) ) ;
204- ctx . subscriptions . push ( commands . registerCommand ( checkForUpdatesCommand , ( ) => installOrUpdateThenTryActivate ( false ) ) ) ;
205-
206- await installOrUpdateThenTryActivate ( true ) ;
208+ ctx . subscriptions . push ( distributionConfigListener . onDidChangeDistributionConfiguration ( ( ) => installOrUpdateThenTryActivate ( {
209+ shouldDisplayMessageWhenNoUpdates : false ,
210+ shouldErrorIfUpdateFails : true
211+ } ) ) ) ;
212+ ctx . subscriptions . push ( commands . registerCommand ( checkForUpdatesCommand , ( ) => installOrUpdateThenTryActivate ( {
213+ shouldDisplayMessageWhenNoUpdates : true ,
214+ shouldErrorIfUpdateFails : true
215+ } ) ) ) ;
216+
217+ await installOrUpdateThenTryActivate ( {
218+ shouldDisplayMessageWhenNoUpdates : false ,
219+ shouldErrorIfUpdateFails : ! ! ctx . globalState . get ( shouldUpdateOnNextActivationKey )
220+ } ) ;
207221}
208222
209223async function activateWithInstalledDistribution ( ctx : ExtensionContext , distributionManager : DistributionManager ) {
0 commit comments