Skip to content

Commit 6ed5c2a

Browse files
committed
Merge remote-tracking branch 'origin/main' into koesie10/filter-vscode-output
2 parents c42cd90 + c71238c commit 6ed5c2a

15 files changed

Lines changed: 507 additions & 218 deletions

File tree

.github/workflows/release.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,23 @@ jobs:
9494
asset_name: ${{ format('vscode-codeql-{0}.vsix', steps.prepare-artifacts.outputs.ref_name) }}
9595
asset_content_type: application/zip
9696

97+
- name: Create sourcemap ZIP file
98+
run: |
99+
cd dist/vscode-codeql/out
100+
zip -r ../../vscode-codeql-sourcemaps.zip *.map
101+
102+
- name: Upload sourcemap ZIP file
103+
uses: actions/upload-release-asset@v1.0.1
104+
if: success()
105+
env:
106+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
107+
with:
108+
# Get the `upload_url` from the `create-release` step above.
109+
upload_url: ${{ steps.create-release.outputs.upload_url }}
110+
asset_path: dist/vscode-codeql-sourcemaps.zip
111+
asset_name: ${{ format('vscode-codeql-sourcemaps-{0}.zip', steps.prepare-artifacts.outputs.ref_name) }}
112+
asset_content_type: application/zip
113+
97114
###
98115
# Do Post release work: version bump and changelog PR
99116
# Only do this if we are running from a PR (ie- this is part of the release process)

CONTRIBUTING.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,13 @@ Pre-recorded scenarios are stored in `./src/mocks/scenarios`. However, it's poss
228228
1. Double-check the `CHANGELOG.md` contains all desired change comments and has the version to be released with date at the top.
229229
* Go through all recent PRs and make sure they are properly accounted for.
230230
* Make sure all changelog entries have links back to their PR(s) if appropriate.
231+
* For picking the new version number, we default to increasing the patch version number, but make our own judgement about whether a change is big enough to warrant a minor version bump. Common reasons for a minor bump could include:
232+
* Making substantial new features available to all users. This can include lifting a feature flag.
233+
* Breakage in compatibility with recent versions of the CLI.
234+
* Minimum required version of VS Code is increased.
235+
* New telemetry events are added.
236+
* Deprecation or removal of commands.
237+
* Accumulation of many changes, none of which are individually big enough to warrant a minor bump, but which together are. This does not include changes which are purely internal to the extension, such as refactoring, or which are only available behind a feature flag.
231238
1. Double-check that the node version we're using matches the one used for VS Code. If it doesn't, you will then need to update the node version in the following files:
232239
* `.nvmrc` - this will enable `nvm` to automatically switch to the correct node version when you're in the project folder
233240
* `.github/workflows/main.yml` - all the "node-version: <version>" settings
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
/**
2+
* This scripts helps finding the original source file and line number for a
3+
* given file and line number in the compiled extension. It currently only
4+
* works with released extensions.
5+
*
6+
* Usage: npx ts-node scripts/source-map.ts <version-number> <filename>:<line>:<column>
7+
* For example: npx ts-node scripts/source-map.ts v1.7.8 "/Users/user/.vscode/extensions/github.vscode-codeql-1.7.8/out/extension.js:131164:13"
8+
*
9+
* Alternative usage: npx ts-node scripts/source-map.ts <version-number> <multi-line-stacktrace>
10+
* For example: npx ts-node scripts/source-map.ts v1.7.8 'Error: Failed to find CodeQL distribution.
11+
* at CodeQLCliServer.getCodeQlPath (/Users/user/.vscode/extensions/github.vscode-codeql-1.7.8/out/extension.js:131164:13)
12+
* at CodeQLCliServer.launchProcess (/Users/user/.vscode/extensions/github.vscode-codeql-1.7.8/out/extension.js:131169:24)
13+
* at CodeQLCliServer.runCodeQlCliInternal (/Users/user/.vscode/extensions/github.vscode-codeql-1.7.8/out/extension.js:131194:24)
14+
* at CodeQLCliServer.runJsonCodeQlCliCommand (/Users/user/.vscode/extensions/github.vscode-codeql-1.7.8/out/extension.js:131330:20)
15+
* at CodeQLCliServer.resolveRam (/Users/user/.vscode/extensions/github.vscode-codeql-1.7.8/out/extension.js:131455:12)
16+
* at QueryServerClient2.startQueryServerImpl (/Users/user/.vscode/extensions/github.vscode-codeql-1.7.8/out/extension.js:138618:21)'
17+
*/
18+
19+
import { spawnSync } from "child_process";
20+
import { basename, resolve } from "path";
21+
import { pathExists, readJSON } from "fs-extra";
22+
import { RawSourceMap, SourceMapConsumer } from "source-map";
23+
import { Open } from "unzipper";
24+
25+
if (process.argv.length !== 4) {
26+
console.error(
27+
"Expected 2 arguments - the version number and the filename:line number",
28+
);
29+
}
30+
31+
const stackLineRegex =
32+
/at (?<name>.*)? \((?<file>.*):(?<line>\d+):(?<column>\d+)\)/gm;
33+
34+
const versionNumber = process.argv[2].startsWith("v")
35+
? process.argv[2]
36+
: `v${process.argv[2]}`;
37+
const stacktrace = process.argv[3];
38+
39+
async function extractSourceMap() {
40+
const releaseAssetsDirectory = resolve(
41+
__dirname,
42+
"..",
43+
"release-assets",
44+
versionNumber,
45+
);
46+
const sourceMapsDirectory = resolve(
47+
__dirname,
48+
"..",
49+
"artifacts",
50+
"source-maps",
51+
versionNumber,
52+
);
53+
54+
if (!(await pathExists(sourceMapsDirectory))) {
55+
console.log("Downloading source maps...");
56+
57+
const release = runGhJSON<Release>([
58+
"release",
59+
"view",
60+
versionNumber,
61+
"--json",
62+
"id,name,assets",
63+
]);
64+
65+
const sourcemapAsset = release.assets.find(
66+
(asset) => asset.name === `vscode-codeql-sourcemaps-${versionNumber}.zip`,
67+
);
68+
69+
if (sourcemapAsset) {
70+
// This downloads a ZIP file of the source maps
71+
runGh([
72+
"release",
73+
"download",
74+
versionNumber,
75+
"--pattern",
76+
sourcemapAsset.name,
77+
"--dir",
78+
releaseAssetsDirectory,
79+
]);
80+
81+
const file = await Open.file(
82+
resolve(releaseAssetsDirectory, sourcemapAsset.name),
83+
);
84+
await file.extract({ path: sourceMapsDirectory });
85+
} else {
86+
const workflowRuns = runGhJSON<WorkflowRunListItem[]>([
87+
"run",
88+
"list",
89+
"--workflow",
90+
"release.yml",
91+
"--branch",
92+
versionNumber,
93+
"--json",
94+
"databaseId,number",
95+
]);
96+
97+
if (workflowRuns.length !== 1) {
98+
throw new Error(
99+
`Expected exactly one workflow run for ${versionNumber}, got ${workflowRuns.length}`,
100+
);
101+
}
102+
103+
const workflowRun = workflowRuns[0];
104+
105+
runGh([
106+
"run",
107+
"download",
108+
workflowRun.databaseId.toString(),
109+
"--name",
110+
"vscode-codeql-sourcemaps",
111+
"--dir",
112+
sourceMapsDirectory,
113+
]);
114+
}
115+
}
116+
117+
if (stacktrace.includes("at")) {
118+
const rawSourceMaps = new Map<string, RawSourceMap>();
119+
120+
const mappedStacktrace = await replaceAsync(
121+
stacktrace,
122+
stackLineRegex,
123+
async (match, name, file, line, column) => {
124+
if (!rawSourceMaps.has(file)) {
125+
const rawSourceMap: RawSourceMap = await readJSON(
126+
resolve(sourceMapsDirectory, `${basename(file)}.map`),
127+
);
128+
rawSourceMaps.set(file, rawSourceMap);
129+
}
130+
131+
const originalPosition = await SourceMapConsumer.with(
132+
rawSourceMaps.get(file) as RawSourceMap,
133+
null,
134+
async function (consumer) {
135+
return consumer.originalPositionFor({
136+
line: parseInt(line, 10),
137+
column: parseInt(column, 10),
138+
});
139+
},
140+
);
141+
142+
if (!originalPosition.source) {
143+
return match;
144+
}
145+
146+
const originalFilename = resolve(file, "..", originalPosition.source);
147+
148+
return `at ${originalPosition.name ?? name} (${originalFilename}:${
149+
originalPosition.line
150+
}:${originalPosition.column})`;
151+
},
152+
);
153+
154+
console.log(mappedStacktrace);
155+
} else {
156+
// This means it's just a filename:line:column
157+
const [filename, line, column] = stacktrace.split(":", 3);
158+
159+
const fileBasename = basename(filename);
160+
161+
const sourcemapName = `${fileBasename}.map`;
162+
const sourcemapPath = resolve(sourceMapsDirectory, sourcemapName);
163+
164+
if (!(await pathExists(sourcemapPath))) {
165+
throw new Error(`No source map found for ${fileBasename}`);
166+
}
167+
168+
const rawSourceMap: RawSourceMap = await readJSON(sourcemapPath);
169+
170+
const originalPosition = await SourceMapConsumer.with(
171+
rawSourceMap,
172+
null,
173+
async function (consumer) {
174+
return consumer.originalPositionFor({
175+
line: parseInt(line, 10),
176+
column: parseInt(column, 10),
177+
});
178+
},
179+
);
180+
181+
if (!originalPosition.source) {
182+
throw new Error(`No source found for ${stacktrace}`);
183+
}
184+
185+
const originalFilename = resolve(filename, "..", originalPosition.source);
186+
187+
console.log(
188+
`${originalFilename}:${originalPosition.line}:${originalPosition.column}`,
189+
);
190+
}
191+
}
192+
193+
extractSourceMap().catch((e: unknown) => {
194+
console.error(e);
195+
process.exit(2);
196+
});
197+
198+
function runGh(args: readonly string[]): string {
199+
const gh = spawnSync("gh", args);
200+
if (gh.status !== 0) {
201+
throw new Error(
202+
`Failed to get the source map for ${versionNumber}: ${gh.stderr}`,
203+
);
204+
}
205+
return gh.stdout.toString("utf-8");
206+
}
207+
208+
function runGhJSON<T>(args: readonly string[]): T {
209+
return JSON.parse(runGh(args));
210+
}
211+
212+
type ReleaseAsset = {
213+
id: string;
214+
name: string;
215+
};
216+
217+
type Release = {
218+
id: string;
219+
name: string;
220+
assets: ReleaseAsset[];
221+
};
222+
223+
type WorkflowRunListItem = {
224+
databaseId: number;
225+
number: number;
226+
};
227+
228+
async function replaceAsync(
229+
str: string,
230+
regex: RegExp,
231+
replacer: (substring: string, ...args: any[]) => Promise<string>,
232+
) {
233+
const promises: Array<Promise<string>> = [];
234+
str.replace(regex, (match, ...args) => {
235+
const promise = replacer(match, ...args);
236+
promises.push(promise);
237+
return match;
238+
});
239+
const data = await Promise.all(promises);
240+
return str.replace(regex, () => data.shift() as string);
241+
}

extensions/ql-vscode/src/config.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,6 @@ export class Setting {
5656
.getConfiguration(this.parent.qualifiedName)
5757
.update(this.name, value, target);
5858
}
59-
60-
inspect<T>(): InspectionResult<T> | undefined {
61-
if (this.parent === undefined) {
62-
throw new Error("Cannot update the value of a root setting.");
63-
}
64-
return workspace
65-
.getConfiguration(this.parent.qualifiedName)
66-
.inspect(this.name);
67-
}
6859
}
6960

7061
export interface InspectionResult<T> {

extensions/ql-vscode/supported_cli_versions.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[
2-
"v2.12.1",
2+
"v2.12.2",
33
"v2.11.6",
44
"v2.7.6",
55
"v2.8.5",

extensions/ql-vscode/test/vscode-tests/cli-integration/jest.setup.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,20 @@ import { dirname } from "path";
88
import fetch from "node-fetch";
99
import { DB_URL, dbLoc, setStoragePath, storagePath } from "./global.helper";
1010
import * as tmp from "tmp";
11-
import { getTestSetting } from "../test-config";
1211
import { CUSTOM_CODEQL_PATH_SETTING } from "../../../src/config";
13-
import { extensions, workspace } from "vscode";
14-
15-
import baseJestSetup from "../jest.setup";
16-
17-
export default baseJestSetup;
12+
import { ConfigurationTarget, env, extensions, workspace } from "vscode";
13+
import { beforeEachAction } from "../test-config";
1814

1915
// create an extension storage location
2016
let removeStorage: tmp.DirResult["removeCallback"] | undefined;
2117

2218
beforeAll(async () => {
2319
// Set the CLI version here before activation to ensure we don't accidentally try to download a cli
24-
await getTestSetting(CUSTOM_CODEQL_PATH_SETTING)?.setInitialTestValue(
20+
await beforeEachAction();
21+
await CUSTOM_CODEQL_PATH_SETTING.updateValue(
2522
process.env.CLI_PATH,
23+
ConfigurationTarget.Workspace,
2624
);
27-
await getTestSetting(CUSTOM_CODEQL_PATH_SETTING)?.setup();
2825

2926
// ensure the test database is downloaded
3027
mkdirpSync(dirname(dbLoc));
@@ -78,6 +75,17 @@ beforeAll(async () => {
7875
await extensions.getExtension("GitHub.vscode-codeql")?.activate();
7976
});
8077

78+
beforeEach(async () => {
79+
jest.spyOn(env, "openExternal").mockResolvedValue(false);
80+
81+
await beforeEachAction();
82+
83+
await CUSTOM_CODEQL_PATH_SETTING.updateValue(
84+
process.env.CLI_PATH,
85+
ConfigurationTarget.Workspace,
86+
);
87+
});
88+
8189
// ensure extension is cleaned up.
8290
afterAll(async () => {
8391
// ensure temp directory is cleaned up.

extensions/ql-vscode/test/vscode-tests/cli-integration/remote-queries/variant-analysis-submission-integration.test.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { resolve } from "path";
33
import {
44
authentication,
55
commands,
6+
ConfigurationTarget,
67
extensions,
78
QuickPickItem,
89
TextDocument,
@@ -12,7 +13,10 @@ import {
1213

1314
import { CodeQLExtensionInterface } from "../../../../src/extension";
1415
import { MockGitHubApiServer } from "../../../../src/mocks/mock-gh-api-server";
15-
import { mockConfiguration } from "../../utils/configuration-helpers";
16+
import {
17+
CANARY_FEATURES,
18+
setRemoteControllerRepo,
19+
} from "../../../../src/config";
1620

1721
jest.setTimeout(30_000);
1822

@@ -36,17 +40,8 @@ describe("Variant Analysis Submission Integration", () => {
3640
let showErrorMessageSpy: jest.SpiedFunction<typeof window.showErrorMessage>;
3741

3842
beforeEach(async () => {
39-
mockConfiguration({
40-
values: {
41-
codeQL: {
42-
canary: true,
43-
},
44-
"codeQL.variantAnalysis": {
45-
liveResults: true,
46-
controllerRepo: "github/vscode-codeql",
47-
},
48-
},
49-
});
43+
await CANARY_FEATURES.updateValue(true, ConfigurationTarget.Global);
44+
await setRemoteControllerRepo("github/vscode-codeql");
5045

5146
jest.spyOn(authentication, "getSession").mockResolvedValue({
5247
id: "test",

0 commit comments

Comments
 (0)