Use version ranges instead of version constraint for simplicity

This commit is contained in:
Henry Mercer 2020-06-01 20:04:00 +01:00
Родитель 577ce95cb1
Коммит 7b9e540332
3 изменённых файлов: 27 добавлений и 41 удалений

Просмотреть файл

@ -36,14 +36,11 @@ const DEFAULT_DISTRIBUTION_OWNER_NAME = "github";
const DEFAULT_DISTRIBUTION_REPOSITORY_NAME = "codeql-cli-binaries";
/**
* Version constraint for the CLI.
* Range of versions of the CLI that are compatible with the extension.
*
* This applies to both extension-managed and CLI distributions.
*/
export const DEFAULT_DISTRIBUTION_VERSION_CONSTRAINT: VersionConstraint = {
description: "2.*.*",
isVersionCompatible: (v: semver.SemVer) => semver.satisfies(v, "2.x")
};
export const DEFAULT_DISTRIBUTION_VERSION_RANGE: semver.Range = new semver.Range("2.x");
export interface DistributionProvider {
getCodeQlPathWithoutVersionCheck(): Promise<string | undefined>;
@ -51,16 +48,16 @@ export interface DistributionProvider {
}
export class DistributionManager implements DistributionProvider {
constructor(extensionContext: ExtensionContext, config: DistributionConfig, versionConstraint: VersionConstraint) {
constructor(extensionContext: ExtensionContext, config: DistributionConfig, versionRange: semver.Range) {
this._config = config;
this._extensionSpecificDistributionManager = new ExtensionSpecificDistributionManager(extensionContext, config, versionConstraint);
this._extensionSpecificDistributionManager = new ExtensionSpecificDistributionManager(extensionContext, config, versionRange);
this._onDidChangeDistribution = config.onDidChangeDistributionConfiguration;
this._updateCheckRateLimiter = new InvocationRateLimiter(
extensionContext,
"extensionSpecificDistributionUpdateCheck",
() => this._extensionSpecificDistributionManager.checkForUpdatesToDistribution()
);
this._versionConstraint = versionConstraint;
this._versionRange = versionRange;
}
/**
@ -74,19 +71,19 @@ export class DistributionManager implements DistributionProvider {
};
}
const version = await getCodeQlCliVersion(codeQlPath, logger);
if (version !== undefined && !this._versionConstraint.isVersionCompatible(version)) {
return {
codeQlPath,
kind: FindDistributionResultKind.IncompatibleDistribution,
version,
};
}
if (version === undefined) {
return {
codeQlPath,
kind: FindDistributionResultKind.UnknownCompatibilityDistribution,
};
}
if (!semver.satisfies(version, this._versionRange)) {
return {
codeQlPath,
kind: FindDistributionResultKind.IncompatibleDistribution,
version,
};
}
return {
codeQlPath,
kind: FindDistributionResultKind.CompatibleDistribution,
@ -197,14 +194,14 @@ export class DistributionManager implements DistributionProvider {
private readonly _extensionSpecificDistributionManager: ExtensionSpecificDistributionManager;
private readonly _updateCheckRateLimiter: InvocationRateLimiter<DistributionUpdateCheckResult>;
private readonly _onDidChangeDistribution: Event<void> | undefined;
private readonly _versionConstraint: VersionConstraint;
private readonly _versionRange: semver.Range;
}
class ExtensionSpecificDistributionManager {
constructor(extensionContext: ExtensionContext, config: DistributionConfig, versionConstraint: VersionConstraint) {
constructor(extensionContext: ExtensionContext, config: DistributionConfig, versionRange: semver.Range) {
this._extensionContext = extensionContext;
this._config = config;
this._versionConstraint = versionConstraint;
this._versionRange = versionRange;
}
public async getCodeQlPathWithoutVersionCheck(): Promise<string | undefined> {
@ -325,7 +322,7 @@ class ExtensionSpecificDistributionManager {
}
private async getLatestRelease(): Promise<Release> {
const release = await this.createReleasesApiConsumer().getLatestRelease(this._versionConstraint, this._config.includePrerelease);
const release = await this.createReleasesApiConsumer().getLatestRelease(this._versionRange, this._config.includePrerelease);
// FIXME: Look for platform-specific codeql distribution if available
release.assets = release.assets.filter(asset => asset.name === 'codeql.zip');
if (release.assets.length === 0) {
@ -373,7 +370,7 @@ class ExtensionSpecificDistributionManager {
private readonly _config: DistributionConfig;
private readonly _extensionContext: ExtensionContext;
private readonly _versionConstraint: VersionConstraint;
private readonly _versionRange: semver.Range;
private static readonly _currentDistributionFolderBaseName = "distribution";
private static readonly _currentDistributionFolderIndexStateKey = "distributionFolderIndex";
@ -394,7 +391,7 @@ export class ReleasesApiConsumer {
this._repoName = repoName;
}
public async getLatestRelease(versionConstraint: VersionConstraint, includePrerelease = false): Promise<Release> {
public async getLatestRelease(versionRange: semver.Range, includePrerelease = false): Promise<Release> {
const apiPath = `/repos/${this._ownerName}/${this._repoName}/releases`;
const allReleases: GithubRelease[] = await (await this.makeApiCall(apiPath)).json();
const compatibleReleases = allReleases.filter(release => {
@ -403,7 +400,7 @@ export class ReleasesApiConsumer {
}
const version = semver.parse(release.tag_name);
return version !== null && versionConstraint.isVersionCompatible(version);
return version !== null && semver.satisfies(version, versionRange);
});
// Tag names must all be parsable to semvers due to the previous filtering step.
const latestRelease = compatibleReleases.sort((a, b) => {
@ -739,11 +736,6 @@ export interface GithubReleaseAsset {
size: number;
}
interface VersionConstraint {
description: string;
isVersionCompatible(version: semver.SemVer): boolean;
}
export class GithubApiError extends Error {
constructor(public status: number, public body: string) {
super(`API call failed with status code ${status}, body: ${body}`);

Просмотреть файл

@ -8,7 +8,7 @@ import * as languageSupport from './languageSupport';
import { DatabaseManager } from './databases';
import { DatabaseUI } from './databases-ui';
import { TemplateQueryDefinitionProvider, TemplateQueryReferenceProvider } from './definitions';
import { DEFAULT_DISTRIBUTION_VERSION_CONSTRAINT, DistributionManager, DistributionUpdateCheckResultKind, FindDistributionResult, FindDistributionResultKind, GithubApiError, GithubRateLimitedError } from './distribution';
import { DEFAULT_DISTRIBUTION_VERSION_RANGE, DistributionManager, DistributionUpdateCheckResultKind, FindDistributionResult, FindDistributionResultKind, GithubApiError, GithubRateLimitedError } from './distribution';
import * as helpers from './helpers';
import { assertNever } from './helpers-pure';
import { spawnIdeServer } from './ide-server';
@ -83,7 +83,7 @@ export async function activate(ctx: ExtensionContext): Promise<void> {
const distributionConfigListener = new DistributionConfigListener();
ctx.subscriptions.push(distributionConfigListener);
const distributionManager = new DistributionManager(ctx, distributionConfigListener, DEFAULT_DISTRIBUTION_VERSION_CONSTRAINT);
const distributionManager = new DistributionManager(ctx, distributionConfigListener, DEFAULT_DISTRIBUTION_VERSION_RANGE);
const shouldUpdateOnNextActivationKey = "shouldUpdateOnNextActivation";

Просмотреть файл

@ -51,10 +51,7 @@ describe("Releases API consumer", () => {
"tag_name": "v3.1.2-pre"
},
];
const unconstrainedVersionConstraint = {
description: "*",
isVersionCompatible: () => true
};
const unconstrainedVersionRange = new semver.Range("*");
it("picking latest release: is based on version", async () => {
class MockReleasesApiConsumer extends ReleasesApiConsumer {
@ -68,11 +65,11 @@ describe("Releases API consumer", () => {
const consumer = new MockReleasesApiConsumer(owner, repo);
const latestRelease = await consumer.getLatestRelease(unconstrainedVersionConstraint);
const latestRelease = await consumer.getLatestRelease(unconstrainedVersionRange);
expect(latestRelease.id).to.equal(2);
});
it("picking latest release: obeys version constraints", async () => {
it("picking latest release: version satisfies version range", async () => {
class MockReleasesApiConsumer extends ReleasesApiConsumer {
protected async makeApiCall(apiPath: string): Promise<fetch.Response> {
if (apiPath === `/repos/${owner}/${repo}/releases`) {
@ -84,10 +81,7 @@ describe("Releases API consumer", () => {
const consumer = new MockReleasesApiConsumer(owner, repo);
const latestRelease = await consumer.getLatestRelease({
description: "2.*.*",
isVersionCompatible: version => semver.satisfies(version, "2.x")
});
const latestRelease = await consumer.getLatestRelease(new semver.Range("2.*.*"));
expect(latestRelease.id).to.equal(1);
});
@ -103,7 +97,7 @@ describe("Releases API consumer", () => {
const consumer = new MockReleasesApiConsumer(owner, repo);
const latestRelease = await consumer.getLatestRelease(unconstrainedVersionConstraint, true);
const latestRelease = await consumer.getLatestRelease(unconstrainedVersionRange, true);
expect(latestRelease.id).to.equal(4);
});
@ -141,7 +135,7 @@ describe("Releases API consumer", () => {
const consumer = new MockReleasesApiConsumer(owner, repo);
const assets = (await consumer.getLatestRelease(unconstrainedVersionConstraint)).assets;
const assets = (await consumer.getLatestRelease(unconstrainedVersionRange)).assets;
expect(assets.length).to.equal(expectedAssets.length);
expectedAssets.map((expectedAsset, index) => {