Skip to content

Commit 8f5ddbd

Browse files
authored
Merge pull request #303 from aeisenberg/aeisenberg/deprecate
feat: Display warning when codeql.cmd is used
2 parents b689e55 + 7ce3dc2 commit 8f5ddbd

File tree

4 files changed

+153
-9
lines changed

4 files changed

+153
-9
lines changed

extensions/ql-vscode/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- Add new command in query history view to view the log file of a
66
query.
77
- Request user acknowledgment before updating the CodeQL binaries.
8+
- Warn when using the deprecated `codeql.cmd` launcher on windows.
89

910
## 1.1.0 - 17 March 2020
1011

extensions/ql-vscode/src/distribution.ts

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { ExtensionContext, Event } from "vscode";
88
import { DistributionConfig } from "./config";
99
import { InvocationRateLimiter, InvocationRateLimiterResultKind, ProgressUpdate, showAndLogErrorMessage } from "./helpers";
1010
import { logger } from "./logging";
11+
import * as helpers from "./helpers";
1112
import { getCodeQlCliVersion, tryParseVersionString, Version } from "./cli-version";
1213

1314
/**
@@ -111,6 +112,9 @@ export class DistributionManager implements DistributionProvider {
111112
"that a CodeQL executable exists at the specified path or remove the setting.");
112113
return undefined;
113114
}
115+
if (deprecatedCodeQlLauncherName() && this._config.customCodeQlPath.endsWith(deprecatedCodeQlLauncherName()!)) {
116+
warnDeprecatedLauncher();
117+
}
114118
return this._config.customCodeQlPath;
115119
}
116120

@@ -121,8 +125,8 @@ export class DistributionManager implements DistributionProvider {
121125

122126
if (process.env.PATH) {
123127
for (const searchDirectory of process.env.PATH.split(path.delimiter)) {
124-
const expectedLauncherPath = path.join(searchDirectory, codeQlLauncherName());
125-
if (await fs.pathExists(expectedLauncherPath)) {
128+
const expectedLauncherPath = await getExecutableFromDirectory(searchDirectory);
129+
if (expectedLauncherPath) {
126130
return expectedLauncherPath;
127131
}
128132
}
@@ -186,12 +190,11 @@ class ExtensionSpecificDistributionManager {
186190
public async getCodeQlPathWithoutVersionCheck(): Promise<string | undefined> {
187191
if (this.getInstalledRelease() !== undefined) {
188192
// An extension specific distribution has been installed.
189-
const expectedLauncherPath = path.join(this.getDistributionRootPath(), codeQlLauncherName());
190-
if (await fs.pathExists(expectedLauncherPath)) {
193+
const expectedLauncherPath = await getExecutableFromDirectory(this.getDistributionRootPath(), true);
194+
if (expectedLauncherPath) {
191195
return expectedLauncherPath;
192196
}
193-
logger.log(`WARNING: Expected to find a CodeQL CLI executable at ${expectedLauncherPath} but one was not found. ` +
194-
"Will try PATH.");
197+
195198
try {
196199
await this.removeDistribution();
197200
} catch (e) {
@@ -514,6 +517,10 @@ function codeQlLauncherName(): string {
514517
return (os.platform() === "win32") ? "codeql.exe" : "codeql";
515518
}
516519

520+
function deprecatedCodeQlLauncherName(): string | undefined {
521+
return (os.platform() === "win32") ? "codeql.cmd" : undefined;
522+
}
523+
517524
function isRedirectStatusCode(statusCode: number): boolean {
518525
return statusCode === 301 || statusCode === 302 || statusCode === 303 || statusCode === 307 || statusCode === 308;
519526
}
@@ -614,6 +621,31 @@ function createUpdateAvailableResult(updatedRelease: Release): UpdateAvailableRe
614621
};
615622
}
616623

624+
// Exported for testing
625+
export async function getExecutableFromDirectory(directory: string, warnWhenNotFound = false): Promise<string | undefined> {
626+
const expectedLauncherPath = path.join(directory, codeQlLauncherName());
627+
const deprecatedLauncherName = deprecatedCodeQlLauncherName();
628+
const alternateExpectedLauncherPath = deprecatedLauncherName ? path.join(directory, deprecatedLauncherName) : undefined;
629+
if (await fs.pathExists(expectedLauncherPath)) {
630+
return expectedLauncherPath;
631+
} else if (alternateExpectedLauncherPath && (await fs.pathExists(alternateExpectedLauncherPath))) {
632+
warnDeprecatedLauncher();
633+
return alternateExpectedLauncherPath;
634+
}
635+
if (warnWhenNotFound) {
636+
logger.log(`WARNING: Expected to find a CodeQL CLI executable at ${expectedLauncherPath} but one was not found. ` +
637+
"Will try PATH.");
638+
}
639+
return undefined;
640+
}
641+
642+
function warnDeprecatedLauncher() {
643+
helpers.showAndLogWarningMessage(
644+
`The "${deprecatedCodeQlLauncherName()!}" launcher has been deprecated and will be removed in a future version. ` +
645+
`Please use "${codeQlLauncherName()}" instead. It is recommended to update to the latest CodeQL binaries.`
646+
);
647+
}
648+
617649
/**
618650
* A release on GitHub.
619651
*/

extensions/ql-vscode/src/vscode-tests/no-workspace/distribution.test.ts

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
1-
import { expect } from "chai";
1+
import * as chai from "chai";
2+
import * as path from "path";
23
import * as fetch from "node-fetch";
4+
import 'chai/register-should';
5+
import * as sinonChai from 'sinon-chai';
6+
import * as sinon from 'sinon';
7+
import * as pq from "proxyquire";
38
import "mocha";
9+
410
import { Version } from "../../cli-version";
5-
import { GithubRelease, GithubReleaseAsset, ReleasesApiConsumer, versionCompare } from "../../distribution"
11+
import { GithubRelease, GithubReleaseAsset, ReleasesApiConsumer, versionCompare } from "../../distribution";
12+
13+
const proxyquire = pq.noPreserveCache();
14+
chai.use(sinonChai);
15+
const expect = chai.expect;
616

717
describe("Releases API consumer", () => {
818
const owner = "someowner";
@@ -176,3 +186,104 @@ describe("Release version ordering", () => {
176186
expect(versionCompare(createVersion(2, 1, 0, "alpha.1", "abcdef0"), createVersion(2, 1, 0, "alpha.1", "bcdef01"))).to.equal(0);
177187
});
178188
});
189+
190+
describe('Launcher path', () => {
191+
let sandbox: sinon.SinonSandbox;
192+
let warnSpy: sinon.SinonSpy;
193+
let logSpy: sinon.SinonSpy;
194+
let fsSpy: sinon.SinonSpy;
195+
let platformSpy: sinon.SinonSpy;
196+
197+
let getExecutableFromDirectory: Function;
198+
199+
let launcherThatExists = '';
200+
201+
beforeEach(() => {
202+
getExecutableFromDirectory = createModule().getExecutableFromDirectory;
203+
});
204+
205+
beforeEach(() => {
206+
sandbox.restore();
207+
});
208+
209+
it('should not warn with proper launcher name', async () => {
210+
launcherThatExists = 'codeql.exe';
211+
const result = await getExecutableFromDirectory('abc');
212+
expect(fsSpy).to.have.been.calledWith(`abc${path.sep}codeql.exe`);
213+
214+
// correct launcher has been found, so alternate one not looked for
215+
expect(fsSpy).not.to.have.been.calledWith(`abc${path.sep}codeql.cmd`);
216+
217+
// no warning message
218+
expect(warnSpy).not.to.have.been.calledWith(sinon.match.string);
219+
// No log message
220+
expect(logSpy).not.to.have.been.calledWith(sinon.match.string);
221+
expect(result).to.equal(`abc${path.sep}codeql.exe`);
222+
});
223+
224+
it('should warn when using a hard-coded deprecated launcher name', async () => {
225+
launcherThatExists = 'codeql.cmd';
226+
path.sep;
227+
const result = await getExecutableFromDirectory('abc');
228+
expect(fsSpy).to.have.been.calledWith(`abc${path.sep}codeql.exe`);
229+
expect(fsSpy).to.have.been.calledWith(`abc${path.sep}codeql.cmd`);
230+
231+
// Should have opened a warning message
232+
expect(warnSpy).to.have.been.calledWith(sinon.match.string);
233+
// No log message
234+
expect(logSpy).not.to.have.been.calledWith(sinon.match.string);
235+
expect(result).to.equal(`abc${path.sep}codeql.cmd`);
236+
});
237+
238+
it('should avoid warn when no launcher is found', async () => {
239+
launcherThatExists = 'xxx';
240+
const result = await getExecutableFromDirectory('abc', false);
241+
expect(fsSpy).to.have.been.calledWith(`abc${path.sep}codeql.exe`);
242+
expect(fsSpy).to.have.been.calledWith(`abc${path.sep}codeql.cmd`);
243+
244+
// no warning message
245+
expect(warnSpy).not.to.have.been.calledWith(sinon.match.string);
246+
// log message sent out
247+
expect(logSpy).not.to.have.been.calledWith(sinon.match.string);
248+
expect(result).to.equal(undefined);
249+
});
250+
251+
it('should warn when no launcher is found', async () => {
252+
launcherThatExists = 'xxx';
253+
const result = await getExecutableFromDirectory('abc', true);
254+
expect(fsSpy).to.have.been.calledWith(`abc${path.sep}codeql.exe`);
255+
expect(fsSpy).to.have.been.calledWith(`abc${path.sep}codeql.cmd`);
256+
257+
// no warning message
258+
expect(warnSpy).not.to.have.been.calledWith(sinon.match.string);
259+
// log message sent out
260+
expect(logSpy).to.have.been.calledWith(sinon.match.string);
261+
expect(result).to.equal(undefined);
262+
});
263+
264+
function createModule() {
265+
sandbox = sinon.createSandbox();
266+
warnSpy = sandbox.spy();
267+
logSpy = sandbox.spy();
268+
// pretend that only the .cmd file exists
269+
fsSpy = sandbox.stub().callsFake(arg => arg.endsWith(launcherThatExists) ? true : false);
270+
platformSpy = sandbox.stub().returns('win32');
271+
272+
return proxyquire('../../distribution', {
273+
'./helpers': {
274+
showAndLogWarningMessage: warnSpy
275+
},
276+
'./logging': {
277+
'logger': {
278+
log: logSpy
279+
}
280+
},
281+
'fs-extra': {
282+
pathExists: fsSpy
283+
},
284+
os: {
285+
platform: platformSpy
286+
}
287+
});
288+
}
289+
});

extensions/ql-vscode/test/pure-tests/logging.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'chai/register-should';
12
import * as chai from 'chai';
23
import * as fs from 'fs-extra';
34
import * as path from 'path';
@@ -8,7 +9,6 @@ import * as sinon from 'sinon';
89
import * as pq from 'proxyquire';
910

1011
const proxyquire = pq.noPreserveCache().noCallThru();
11-
chai.should();
1212
chai.use(sinonChai);
1313
const expect = chai.expect;
1414

0 commit comments

Comments
 (0)