@@ -64,28 +64,47 @@ export class DistributionManager implements DistributionProvider {
6464 * Look up a CodeQL launcher binary.
6565 */
6666 public async getDistribution ( ) : Promise < FindDistributionResult > {
67- const codeQlPath = await this . getCodeQlPathWithoutVersionCheck ( ) ;
68- if ( codeQlPath === undefined ) {
67+ const distribution = await this . getDistributionWithoutVersionCheck ( ) ;
68+ if ( distribution === undefined ) {
6969 return {
7070 kind : FindDistributionResultKind . NoDistribution ,
7171 } ;
7272 }
73- const version = await getCodeQlCliVersion ( codeQlPath , logger ) ;
73+ const version = await getCodeQlCliVersion ( distribution . codeQlPath , logger ) ;
7474 if ( version === undefined ) {
7575 return {
76- codeQlPath ,
76+ distribution ,
7777 kind : FindDistributionResultKind . UnknownCompatibilityDistribution ,
7878 } ;
7979 }
80- if ( ! semver . satisfies ( version , this . _versionRange ) ) {
80+
81+ /**
82+ * Specifies whether prerelease versions of the CodeQL CLI should be accepted.
83+ *
84+ * Suppose a user sets the includePrerelease config option, obtains a prerelease, then decides
85+ * they no longer want a prerelease, so unsets the includePrerelease config option.
86+ * Unsetting the includePrerelease config option should trigger an update check, and this
87+ * update check should present them an update that returns them back to a non-prerelease
88+ * version.
89+ *
90+ * Therefore, we adopt the following:
91+ *
92+ * - If the user is managing their own CLI, they can use a prerelease without specifying the
93+ * includePrerelease option.
94+ * - If the user is using an extension-managed CLI, then prereleases are only accepted when the
95+ * includePrerelease config option is set.
96+ */
97+ const includePrerelease = distribution . kind !== DistributionKind . ExtensionManaged || this . _config . includePrerelease ;
98+
99+ if ( ! semver . satisfies ( version , this . _versionRange , { includePrerelease } ) ) {
81100 return {
82- codeQlPath ,
101+ distribution ,
83102 kind : FindDistributionResultKind . IncompatibleDistribution ,
84103 version,
85104 } ;
86105 }
87106 return {
88- codeQlPath ,
107+ distribution ,
89108 kind : FindDistributionResultKind . CompatibleDistribution ,
90109 version
91110 } ;
@@ -96,10 +115,18 @@ export class DistributionManager implements DistributionProvider {
96115 return result . kind !== FindDistributionResultKind . NoDistribution ;
97116 }
98117
118+ public async getCodeQlPathWithoutVersionCheck ( ) : Promise < string | undefined > {
119+ const distribution = await this . getDistributionWithoutVersionCheck ( ) ;
120+ if ( distribution === undefined ) {
121+ return undefined ;
122+ }
123+ return distribution . codeQlPath ;
124+ }
125+
99126 /**
100127 * Returns the path to a possibly-compatible CodeQL launcher binary, or undefined if a binary not be found.
101128 */
102- public async getCodeQlPathWithoutVersionCheck ( ) : Promise < string | undefined > {
129+ async getDistributionWithoutVersionCheck ( ) : Promise < Distribution | undefined > {
103130 // Check config setting, then extension specific distribution, then PATH.
104131 if ( this . _config . customCodeQlPath ) {
105132 if ( ! await fs . pathExists ( this . _config . customCodeQlPath ) ) {
@@ -117,19 +144,28 @@ export class DistributionManager implements DistributionProvider {
117144 ) {
118145 warnDeprecatedLauncher ( ) ;
119146 }
120- return this . _config . customCodeQlPath ;
147+ return {
148+ codeQlPath : this . _config . customCodeQlPath ,
149+ kind : DistributionKind . CustomPathConfig
150+ } ;
121151 }
122152
123153 const extensionSpecificCodeQlPath = await this . _extensionSpecificDistributionManager . getCodeQlPathWithoutVersionCheck ( ) ;
124154 if ( extensionSpecificCodeQlPath !== undefined ) {
125- return extensionSpecificCodeQlPath ;
155+ return {
156+ codeQlPath : extensionSpecificCodeQlPath ,
157+ kind : DistributionKind . ExtensionManaged
158+ } ;
126159 }
127160
128161 if ( process . env . PATH ) {
129162 for ( const searchDirectory of process . env . PATH . split ( path . delimiter ) ) {
130163 const expectedLauncherPath = await getExecutableFromDirectory ( searchDirectory ) ;
131164 if ( expectedLauncherPath ) {
132- return expectedLauncherPath ;
165+ return {
166+ codeQlPath : expectedLauncherPath ,
167+ kind : DistributionKind . PathEnvironmentVariable
168+ } ;
133169 }
134170 }
135171 logger . log ( "INFO: Could not find CodeQL on path." ) ;
@@ -146,9 +182,9 @@ export class DistributionManager implements DistributionProvider {
146182 */
147183 public async checkForUpdatesToExtensionManagedDistribution (
148184 minSecondsSinceLastUpdateCheck : number ) : Promise < DistributionUpdateCheckResult > {
149- const codeQlPath = await this . getCodeQlPathWithoutVersionCheck ( ) ;
185+ const distribution = await this . getDistributionWithoutVersionCheck ( ) ;
150186 const extensionManagedCodeQlPath = await this . _extensionSpecificDistributionManager . getCodeQlPathWithoutVersionCheck ( ) ;
151- if ( codeQlPath !== undefined && codeQlPath !== extensionManagedCodeQlPath ) {
187+ if ( distribution !== undefined && distribution . codeQlPath !== extensionManagedCodeQlPath ) {
152188 // A distribution is present but it isn't managed by the extension.
153189 return createInvalidLocationResult ( ) ;
154190 }
@@ -406,7 +442,7 @@ export class ReleasesApiConsumer {
406442 }
407443
408444 const version = semver . parse ( release . tag_name ) ;
409- if ( version === null || ! semver . satisfies ( version , versionRange ) ) {
445+ if ( version === null || ! semver . satisfies ( version , versionRange , { includePrerelease } ) ) {
410446 return false ;
411447 }
412448
@@ -534,6 +570,17 @@ function isRedirectStatusCode(statusCode: number): boolean {
534570 * Types and helper functions relating to those types.
535571 */
536572
573+ export enum DistributionKind {
574+ CustomPathConfig ,
575+ ExtensionManaged ,
576+ PathEnvironmentVariable
577+ }
578+
579+ export interface Distribution {
580+ codeQlPath : string ;
581+ kind : DistributionKind ;
582+ }
583+
537584export enum FindDistributionResultKind {
538585 CompatibleDistribution ,
539586 UnknownCompatibilityDistribution ,
@@ -548,18 +595,18 @@ export type FindDistributionResult =
548595 | NoDistributionResult ;
549596
550597interface CompatibleDistributionResult {
551- codeQlPath : string ;
598+ distribution : Distribution ;
552599 kind : FindDistributionResultKind . CompatibleDistribution ;
553600 version : semver . SemVer ;
554601}
555602
556603interface UnknownCompatibilityDistributionResult {
557- codeQlPath : string ;
604+ distribution : Distribution ;
558605 kind : FindDistributionResultKind . UnknownCompatibilityDistribution ;
559606}
560607
561608interface IncompatibleDistributionResult {
562- codeQlPath : string ;
609+ distribution : Distribution ;
563610 kind : FindDistributionResultKind . IncompatibleDistribution ;
564611 version : semver . SemVer ;
565612}
0 commit comments