Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4673d9ca0 | ||
|
|
87f45a7739 | ||
|
|
0c89df9a80 | ||
|
|
ba8b32078d | ||
|
|
fa4dd087e5 | ||
|
|
ac74b967b3 | ||
|
|
c349c6a048 | ||
|
|
234b05994c | ||
|
|
af8f0231c0 | ||
|
|
84bd029749 | ||
|
|
7d2e4b6de4 | ||
|
|
23a0e03cef | ||
|
|
21c5ed01ad | ||
|
|
d2af550bcc | ||
|
|
cf36a52762 | ||
|
|
ac1a97efa0 | ||
|
|
8d5067f622 | ||
|
|
fe5f1c417d | ||
|
|
95438bb7e3 | ||
|
|
6d7d0ca41a | ||
|
|
3749e17769 | ||
|
|
ee49fb5070 | ||
|
|
de6c523bad | ||
|
|
6612c279ae | ||
|
|
2dfa0e8b52 | ||
|
|
0197306713 | ||
|
|
269165eaa3 | ||
|
|
14c736d72e | ||
|
|
b8898b939c | ||
|
|
45da1e0f1f | ||
|
|
88c990c6ae |
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@@ -139,7 +139,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
version: ['v2.6.3', 'v2.7.6', 'v2.8.5', 'v2.9.4', 'v2.10.3', 'nightly']
|
||||
version: ['v2.6.3', 'v2.7.6', 'v2.8.5', 'v2.9.4', 'v2.10.4', 'nightly']
|
||||
env:
|
||||
CLI_VERSION: ${{ matrix.version }}
|
||||
NIGHTLY_URL: ${{ needs.find-nightly.outputs.url }}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# CodeQL for Visual Studio Code: Changelog
|
||||
|
||||
## 1.6.12 - 1 September 2022
|
||||
|
||||
- Add ability for users to download databases directly from GitHub. [#1485](https://github.com/github/vscode-codeql/pull/1485)
|
||||
- Fix a race condition that could cause a failure to open the evaluator log when running a query. [#1490](https://github.com/github/vscode-codeql/pull/1490)
|
||||
- Fix an error when running a query with an older version of the CodeQL CLI. [#1490](https://github.com/github/vscode-codeql/pull/1490)
|
||||
|
||||
## 1.6.11 - 25 August 2022
|
||||
|
||||
No user facing changes.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as gulp from 'gulp';
|
||||
import { compileTypeScript, watchTypeScript, copyViewCss, cleanOutput, watchCss } from './typescript';
|
||||
import { compileTypeScript, watchTypeScript, cleanOutput } from './typescript';
|
||||
import { compileTextMateGrammar } from './textmate';
|
||||
import { copyTestData } from './tests';
|
||||
import { compileView, watchView } from './webpack';
|
||||
@@ -10,7 +10,7 @@ export const buildWithoutPackage =
|
||||
gulp.series(
|
||||
cleanOutput,
|
||||
gulp.parallel(
|
||||
compileTypeScript, compileTextMateGrammar, compileView, copyTestData, copyViewCss
|
||||
compileTypeScript, compileTextMateGrammar, compileView, copyTestData
|
||||
)
|
||||
);
|
||||
|
||||
@@ -23,6 +23,5 @@ export {
|
||||
copyTestData,
|
||||
injectAppInsightsKey,
|
||||
compileView,
|
||||
watchCss
|
||||
};
|
||||
export default gulp.series(buildWithoutPackage, injectAppInsightsKey, packageExtension);
|
||||
|
||||
@@ -39,13 +39,3 @@ export function compileTypeScript() {
|
||||
export function watchTypeScript() {
|
||||
gulp.watch('src/**/*.ts', compileTypeScript);
|
||||
}
|
||||
|
||||
export function watchCss() {
|
||||
gulp.watch('src/**/*.css', copyViewCss);
|
||||
}
|
||||
|
||||
/** Copy CSS files for the results view into the output directory. */
|
||||
export function copyViewCss() {
|
||||
return gulp.src('src/**/view/*.css')
|
||||
.pipe(gulp.dest('out'));
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import * as path from 'path';
|
||||
import * as webpack from 'webpack';
|
||||
import * as MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
||||
|
||||
export const config: webpack.Configuration = {
|
||||
mode: 'development',
|
||||
entry: {
|
||||
resultsView: './src/view/results.tsx',
|
||||
compareView: './src/compare/view/Compare.tsx',
|
||||
remoteQueriesView: './src/remote-queries/view/RemoteQueries.tsx',
|
||||
webview: './src/view/webview.tsx'
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, '..', 'out'),
|
||||
@@ -31,9 +30,7 @@ export const config: webpack.Configuration = {
|
||||
{
|
||||
test: /\.less$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'style-loader'
|
||||
},
|
||||
MiniCssExtractPlugin.loader,
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
@@ -53,17 +50,31 @@ export const config: webpack.Configuration = {
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'style-loader'
|
||||
},
|
||||
MiniCssExtractPlugin.loader,
|
||||
{
|
||||
loader: 'css-loader'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.(woff(2)?|ttf|eot)$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]',
|
||||
outputPath: 'fonts/',
|
||||
// We need this to make Webpack use the correct path for the fonts.
|
||||
// Without this, the CSS file will use `url([object Module])`
|
||||
esModule: false
|
||||
}
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
},
|
||||
performance: {
|
||||
hints: false
|
||||
}
|
||||
},
|
||||
plugins: [new MiniCssExtractPlugin()],
|
||||
};
|
||||
|
||||
352
extensions/ql-vscode/package-lock.json
generated
352
extensions/ql-vscode/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "vscode-codeql",
|
||||
"version": "1.6.11",
|
||||
"version": "1.6.12",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "vscode-codeql",
|
||||
"version": "1.6.11",
|
||||
"version": "1.6.12",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/plugin-retry": "^3.0.9",
|
||||
@@ -81,6 +81,7 @@
|
||||
"@types/unzipper": "~0.10.1",
|
||||
"@types/vscode": "^1.59.0",
|
||||
"@types/webpack": "^5.28.0",
|
||||
"@types/webpack-env": "^1.18.0",
|
||||
"@types/xml2js": "~0.4.4",
|
||||
"@typescript-eslint/eslint-plugin": "^4.26.0",
|
||||
"@typescript-eslint/parser": "^4.26.0",
|
||||
@@ -92,6 +93,7 @@
|
||||
"del": "^6.0.0",
|
||||
"eslint": "~6.8.0",
|
||||
"eslint-plugin-react": "~7.19.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"glob": "^7.1.4",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-replace": "^1.1.3",
|
||||
@@ -99,6 +101,7 @@
|
||||
"gulp-typescript": "^5.0.1",
|
||||
"husky": "~4.3.8",
|
||||
"lint-staged": "~10.2.2",
|
||||
"mini-css-extract-plugin": "^2.6.1",
|
||||
"mocha": "^10.0.0",
|
||||
"mocha-sinon": "~2.1.2",
|
||||
"npm-run-all": "^4.1.5",
|
||||
@@ -106,7 +109,6 @@
|
||||
"proxyquire": "~2.1.3",
|
||||
"sinon": "~13.0.1",
|
||||
"sinon-chai": "~3.5.0",
|
||||
"style-loader": "~3.3.1",
|
||||
"through2": "^4.0.2",
|
||||
"ts-loader": "^8.1.0",
|
||||
"ts-node": "^10.7.0",
|
||||
@@ -1880,6 +1882,12 @@
|
||||
"webpack": "^5"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/webpack-env": {
|
||||
"version": "1.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.0.tgz",
|
||||
"integrity": "sha512-56/MAlX5WMsPVbOg7tAxnYvNYMMWr/QJiIp6BxVSW3JJXUVzzOn64qW8TzQyMSqSUFM2+PVI4aUHcHOzIz/1tg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/webpack/node_modules/tapable": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
|
||||
@@ -2478,6 +2486,45 @@
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/ajv-formats": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
|
||||
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ajv": "^8.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ajv": "^8.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"ajv": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/ajv-formats/node_modules/ajv": {
|
||||
"version": "8.11.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
|
||||
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/ajv-formats/node_modules/json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ajv-keywords": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
||||
@@ -6205,6 +6252,70 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/file-loader": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz",
|
||||
"integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"loader-utils": "^2.0.0",
|
||||
"schema-utils": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.13.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"webpack": "^4.0.0 || ^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/file-loader/node_modules/json5": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
|
||||
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"json5": "lib/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/file-loader/node_modules/loader-utils": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
|
||||
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/file-loader/node_modules/schema-utils": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
|
||||
"integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.8",
|
||||
"ajv": "^6.12.5",
|
||||
"ajv-keywords": "^3.5.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.13.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
@@ -9191,6 +9302,78 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/mini-css-extract-plugin": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz",
|
||||
"integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"schema-utils": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.13.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"webpack": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mini-css-extract-plugin/node_modules/ajv": {
|
||||
"version": "8.11.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
|
||||
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
|
||||
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ajv": "^8.8.2"
|
||||
}
|
||||
},
|
||||
"node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/mini-css-extract-plugin/node_modules/schema-utils": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz",
|
||||
"integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"ajv": "^8.8.0",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"ajv-keywords": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.13.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
@@ -11314,6 +11497,15 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/require-from-string": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/require-main-filename": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
|
||||
@@ -12327,22 +12519,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/style-loader": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz",
|
||||
"integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 12.13.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"webpack": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/styled-components": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz",
|
||||
@@ -16142,6 +16318,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/webpack-env": {
|
||||
"version": "1.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.0.tgz",
|
||||
"integrity": "sha512-56/MAlX5WMsPVbOg7tAxnYvNYMMWr/QJiIp6BxVSW3JJXUVzzOn64qW8TzQyMSqSUFM2+PVI4aUHcHOzIz/1tg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/xml2js": {
|
||||
"version": "0.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.5.tgz",
|
||||
@@ -16589,6 +16771,35 @@
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"ajv-formats": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
|
||||
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "^8.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
"version": "8.11.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
|
||||
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"ajv-keywords": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
||||
@@ -19626,6 +19837,46 @@
|
||||
"flat-cache": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"file-loader": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz",
|
||||
"integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loader-utils": "^2.0.0",
|
||||
"schema-utils": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"json5": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
|
||||
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
|
||||
"dev": true
|
||||
},
|
||||
"loader-utils": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
|
||||
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^2.1.2"
|
||||
}
|
||||
},
|
||||
"schema-utils": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
|
||||
"integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.8",
|
||||
"ajv": "^6.12.5",
|
||||
"ajv-keywords": "^3.5.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
@@ -21980,6 +22231,56 @@
|
||||
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
|
||||
"dev": true
|
||||
},
|
||||
"mini-css-extract-plugin": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz",
|
||||
"integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"schema-utils": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
"version": "8.11.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
|
||||
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"ajv-keywords": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
|
||||
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.3"
|
||||
}
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"dev": true
|
||||
},
|
||||
"schema-utils": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz",
|
||||
"integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"ajv": "^8.8.0",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"ajv-keywords": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
@@ -23626,6 +23927,12 @@
|
||||
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
|
||||
"dev": true
|
||||
},
|
||||
"require-from-string": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
||||
"dev": true
|
||||
},
|
||||
"require-main-filename": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
|
||||
@@ -24439,13 +24746,6 @@
|
||||
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
|
||||
"dev": true
|
||||
},
|
||||
"style-loader": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz",
|
||||
"integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"styled-components": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"description": "CodeQL for Visual Studio Code",
|
||||
"author": "GitHub",
|
||||
"private": true,
|
||||
"version": "1.6.11",
|
||||
"version": "1.6.12",
|
||||
"publisher": "GitHub",
|
||||
"license": "MIT",
|
||||
"icon": "media/VS-marketplace-CodeQL-icon.png",
|
||||
@@ -288,7 +288,7 @@
|
||||
"default": "",
|
||||
"pattern": "^$|^(?:[a-zA-Z0-9]+-)*[a-zA-Z0-9]+/[a-zA-Z0-9-_]+$",
|
||||
"patternErrorMessage": "Please enter a valid GitHub repository",
|
||||
"markdownDescription": "[For internal use only] The name of the GitHub repository where you can view the progress and results of the \"Run Variant Analysis\" command. The repository should be of the form `<owner>/<repo>`)."
|
||||
"markdownDescription": "[For internal use only] The name of the GitHub repository in which the GitHub Actions workflow is run when using the \"Run Variant Analysis\" command. The repository should be of the form `<owner>/<repo>`)."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -664,7 +664,7 @@
|
||||
},
|
||||
{
|
||||
"command": "codeQLDatabases.chooseDatabaseGithub",
|
||||
"when": "config.codeQL.canary && view == codeQLDatabases",
|
||||
"when": "view == codeQLDatabases",
|
||||
"group": "navigation"
|
||||
},
|
||||
{
|
||||
@@ -926,10 +926,6 @@
|
||||
"command": "codeQL.viewCfg",
|
||||
"when": "resourceScheme == codeql-zip-archive && config.codeQL.canary"
|
||||
},
|
||||
{
|
||||
"command": "codeQL.chooseDatabaseGithub",
|
||||
"when": "config.codeQL.canary"
|
||||
},
|
||||
{
|
||||
"command": "codeQLDatabases.setCurrentDatabase",
|
||||
"when": "false"
|
||||
@@ -1175,7 +1171,7 @@
|
||||
},
|
||||
{
|
||||
"view": "codeQLDatabases",
|
||||
"contents": "Add a CodeQL database:\n[From a folder](command:codeQLDatabases.chooseDatabaseFolder)\n[From an archive](command:codeQLDatabases.chooseDatabaseArchive)\n[From a URL (as a zip file)](command:codeQLDatabases.chooseDatabaseInternet)\n[From LGTM](command:codeQLDatabases.chooseDatabaseLgtm)"
|
||||
"contents": "Add a CodeQL database:\n[From a folder](command:codeQLDatabases.chooseDatabaseFolder)\n[From an archive](command:codeQLDatabases.chooseDatabaseArchive)\n[From a URL (as a zip file)](command:codeQLDatabases.chooseDatabaseInternet)\n[From GitHub](command:codeQLDatabases.chooseDatabaseGithub)\n[From LGTM](command:codeQLDatabases.chooseDatabaseLgtm)"
|
||||
},
|
||||
{
|
||||
"view": "codeQLEvalLogViewer",
|
||||
@@ -1188,7 +1184,6 @@
|
||||
"watch": "npm-run-all -p watch:*",
|
||||
"watch:extension": "tsc --watch",
|
||||
"watch:webpack": "gulp watchView",
|
||||
"watch:css": "gulp watchCss",
|
||||
"test": "mocha --exit -r ts-node/register test/pure-tests/**/*.ts",
|
||||
"preintegration": "rm -rf ./out/vscode-tests && gulp",
|
||||
"integration": "node ./out/vscode-tests/run-integration-tests.js no-workspace,minimal-workspace",
|
||||
@@ -1199,8 +1194,8 @@
|
||||
"format-staged": "lint-staged"
|
||||
},
|
||||
"dependencies": {
|
||||
"@octokit/rest": "^18.5.6",
|
||||
"@octokit/plugin-retry": "^3.0.9",
|
||||
"@octokit/rest": "^18.5.6",
|
||||
"@primer/octicons-react": "^16.3.0",
|
||||
"@primer/react": "^35.0.0",
|
||||
"@vscode/codicons": "^0.0.31",
|
||||
@@ -1271,6 +1266,7 @@
|
||||
"@types/unzipper": "~0.10.1",
|
||||
"@types/vscode": "^1.59.0",
|
||||
"@types/webpack": "^5.28.0",
|
||||
"@types/webpack-env": "^1.18.0",
|
||||
"@types/xml2js": "~0.4.4",
|
||||
"@typescript-eslint/eslint-plugin": "^4.26.0",
|
||||
"@typescript-eslint/parser": "^4.26.0",
|
||||
@@ -1282,6 +1278,7 @@
|
||||
"del": "^6.0.0",
|
||||
"eslint": "~6.8.0",
|
||||
"eslint-plugin-react": "~7.19.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"glob": "^7.1.4",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-replace": "^1.1.3",
|
||||
@@ -1289,6 +1286,7 @@
|
||||
"gulp-typescript": "^5.0.1",
|
||||
"husky": "~4.3.8",
|
||||
"lint-staged": "~10.2.2",
|
||||
"mini-css-extract-plugin": "^2.6.1",
|
||||
"mocha": "^10.0.0",
|
||||
"mocha-sinon": "~2.1.2",
|
||||
"npm-run-all": "^4.1.5",
|
||||
@@ -1296,7 +1294,6 @@
|
||||
"proxyquire": "~2.1.3",
|
||||
"sinon": "~13.0.1",
|
||||
"sinon-chai": "~3.5.0",
|
||||
"style-loader": "~3.3.1",
|
||||
"through2": "^4.0.2",
|
||||
"ts-loader": "^8.1.0",
|
||||
"ts-node": "^10.7.0",
|
||||
|
||||
118
extensions/ql-vscode/src/abstract-interface-manager.ts
Normal file
118
extensions/ql-vscode/src/abstract-interface-manager.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import {
|
||||
WebviewPanel,
|
||||
ExtensionContext,
|
||||
window as Window,
|
||||
ViewColumn,
|
||||
Uri,
|
||||
WebviewPanelOptions,
|
||||
WebviewOptions
|
||||
} from 'vscode';
|
||||
import * as path from 'path';
|
||||
|
||||
import { DisposableObject } from './pure/disposable-object';
|
||||
import { tmpDir } from './helpers';
|
||||
import { getHtmlForWebview, WebviewMessage, WebviewView } from './interface-utils';
|
||||
|
||||
export type InterfacePanelConfig = {
|
||||
viewId: string;
|
||||
title: string;
|
||||
viewColumn: ViewColumn;
|
||||
view: WebviewView;
|
||||
preserveFocus?: boolean;
|
||||
additionalOptions?: WebviewPanelOptions & WebviewOptions;
|
||||
}
|
||||
|
||||
export abstract class AbstractInterfaceManager<ToMessage extends WebviewMessage, FromMessage extends WebviewMessage> extends DisposableObject {
|
||||
protected panel: WebviewPanel | undefined;
|
||||
protected panelLoaded = false;
|
||||
protected panelLoadedCallBacks: (() => void)[] = [];
|
||||
|
||||
constructor(
|
||||
protected readonly ctx: ExtensionContext
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected get isShowingPanel() {
|
||||
return !!this.panel;
|
||||
}
|
||||
|
||||
protected getPanel(): WebviewPanel {
|
||||
if (this.panel == undefined) {
|
||||
const { ctx } = this;
|
||||
|
||||
const config = this.getPanelConfig();
|
||||
|
||||
this.panel = Window.createWebviewPanel(
|
||||
config.viewId,
|
||||
config.title,
|
||||
{ viewColumn: ViewColumn.Active, preserveFocus: true },
|
||||
{
|
||||
enableScripts: true,
|
||||
enableFindWidget: true,
|
||||
retainContextWhenHidden: true,
|
||||
...config.additionalOptions,
|
||||
localResourceRoots: [
|
||||
...(config.additionalOptions?.localResourceRoots ?? []),
|
||||
Uri.file(tmpDir.name),
|
||||
Uri.file(path.join(ctx.extensionPath, 'out'))
|
||||
],
|
||||
}
|
||||
);
|
||||
this.push(
|
||||
this.panel.onDidDispose(
|
||||
() => {
|
||||
this.panel = undefined;
|
||||
this.panelLoaded = false;
|
||||
this.onPanelDispose();
|
||||
},
|
||||
null,
|
||||
ctx.subscriptions
|
||||
)
|
||||
);
|
||||
|
||||
this.panel.webview.html = getHtmlForWebview(
|
||||
ctx,
|
||||
this.panel.webview,
|
||||
config.view,
|
||||
{
|
||||
allowInlineStyles: true,
|
||||
}
|
||||
);
|
||||
this.push(
|
||||
this.panel.webview.onDidReceiveMessage(
|
||||
async (e) => this.onMessage(e),
|
||||
undefined,
|
||||
ctx.subscriptions
|
||||
)
|
||||
);
|
||||
}
|
||||
return this.panel;
|
||||
}
|
||||
|
||||
protected abstract getPanelConfig(): InterfacePanelConfig;
|
||||
|
||||
protected abstract onPanelDispose(): void;
|
||||
|
||||
protected abstract onMessage(msg: FromMessage): Promise<void>;
|
||||
|
||||
protected waitForPanelLoaded(): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
if (this.panelLoaded) {
|
||||
resolve();
|
||||
} else {
|
||||
this.panelLoadedCallBacks.push(resolve);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected onWebViewLoaded(): void {
|
||||
this.panelLoaded = true;
|
||||
this.panelLoadedCallBacks.forEach((cb) => cb());
|
||||
this.panelLoadedCallBacks = [];
|
||||
}
|
||||
|
||||
protected postMessage(msg: ToMessage): Thenable<boolean> {
|
||||
return this.getPanel().webview.postMessage(msg);
|
||||
}
|
||||
}
|
||||
@@ -76,16 +76,27 @@ export class Credentials {
|
||||
}));
|
||||
}
|
||||
|
||||
async getOctokit(): Promise<Octokit.Octokit> {
|
||||
/**
|
||||
* Creates or returns an instance of Octokit.
|
||||
*
|
||||
* @param requireAuthentication Whether the Octokit instance needs to be authenticated as user.
|
||||
* @returns An instance of Octokit.
|
||||
*/
|
||||
async getOctokit(requireAuthentication = true): Promise<Octokit.Octokit> {
|
||||
if (this.octokit) {
|
||||
return this.octokit;
|
||||
}
|
||||
|
||||
this.octokit = await this.createOctokit(true);
|
||||
// octokit shouldn't be undefined, since we've set "createIfNone: true".
|
||||
// The following block is mainly here to prevent a compiler error.
|
||||
this.octokit = await this.createOctokit(requireAuthentication);
|
||||
|
||||
if (!this.octokit) {
|
||||
throw new Error('Did not initialize Octokit.');
|
||||
if (requireAuthentication) {
|
||||
throw new Error('Did not initialize Octokit.');
|
||||
}
|
||||
|
||||
// We don't want to set this in this.octokit because that would prevent
|
||||
// authenticating when requireCredentials is true.
|
||||
return new Octokit.Octokit({ retry });
|
||||
}
|
||||
return this.octokit;
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ export class CodeQLCliServer implements Disposable {
|
||||
/**
|
||||
* Restart the server when the current command terminates
|
||||
*/
|
||||
private restartCliServer(): void {
|
||||
restartCliServer(): void {
|
||||
const callback = (): void => {
|
||||
try {
|
||||
this.killProcessIfRunning();
|
||||
@@ -683,7 +683,7 @@ export class CodeQLCliServer implements Disposable {
|
||||
const subcommandArgs = [
|
||||
'--format=text',
|
||||
`--end-summary=${endSummaryPath}`,
|
||||
'--sourcemap',
|
||||
...(await this.cliConstraints.supportsSourceMap() ? ['--sourcemap'] : []),
|
||||
inputPath,
|
||||
outputPath
|
||||
];
|
||||
@@ -1322,6 +1322,11 @@ export class CliVersionConstraint {
|
||||
*/
|
||||
public static CLI_VERSION_WITH_PER_QUERY_EVAL_LOG = new SemVer('2.9.0');
|
||||
|
||||
/**
|
||||
* CLI version that supports the `--sourcemap` option for log generation.
|
||||
*/
|
||||
public static CLI_VERSION_WITH_SOURCEMAP = new SemVer('2.10.3');
|
||||
|
||||
constructor(private readonly cli: CodeQLCliServer) {
|
||||
/**/
|
||||
}
|
||||
@@ -1389,4 +1394,8 @@ export class CliVersionConstraint {
|
||||
async supportsPerQueryEvalLog() {
|
||||
return this.isVersionAtLeast(CliVersionConstraint.CLI_VERSION_WITH_PER_QUERY_EVAL_LOG);
|
||||
}
|
||||
|
||||
async supportsSourceMap() {
|
||||
return this.isVersionAtLeast(CliVersionConstraint.CLI_VERSION_WITH_SOURCEMAP);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
import { DisposableObject } from '../pure/disposable-object';
|
||||
import {
|
||||
WebviewPanel,
|
||||
ExtensionContext,
|
||||
window as Window,
|
||||
ViewColumn,
|
||||
Uri,
|
||||
} from 'vscode';
|
||||
import * as path from 'path';
|
||||
|
||||
import { tmpDir } from '../helpers';
|
||||
import {
|
||||
FromCompareViewMessage,
|
||||
ToCompareViewMessage,
|
||||
@@ -17,26 +11,24 @@ import {
|
||||
import { Logger } from '../logging';
|
||||
import { CodeQLCliServer } from '../cli';
|
||||
import { DatabaseManager } from '../databases';
|
||||
import { getHtmlForWebview, jumpToLocation } from '../interface-utils';
|
||||
import { jumpToLocation } from '../interface-utils';
|
||||
import { transformBqrsResultSet, RawResultSet, BQRSInfo } from '../pure/bqrs-cli-types';
|
||||
import resultsDiff from './resultsDiff';
|
||||
import { CompletedLocalQueryInfo } from '../query-results';
|
||||
import { getErrorMessage } from '../pure/helpers-pure';
|
||||
import { HistoryItemLabelProvider } from '../history-item-label-provider';
|
||||
import { AbstractInterfaceManager, InterfacePanelConfig } from '../abstract-interface-manager';
|
||||
|
||||
interface ComparePair {
|
||||
from: CompletedLocalQueryInfo;
|
||||
to: CompletedLocalQueryInfo;
|
||||
}
|
||||
|
||||
export class CompareInterfaceManager extends DisposableObject {
|
||||
export class CompareInterfaceManager extends AbstractInterfaceManager<ToCompareViewMessage, FromCompareViewMessage> {
|
||||
private comparePair: ComparePair | undefined;
|
||||
private panel: WebviewPanel | undefined;
|
||||
private panelLoaded = false;
|
||||
private panelLoadedCallBacks: (() => void)[] = [];
|
||||
|
||||
constructor(
|
||||
private ctx: ExtensionContext,
|
||||
ctx: ExtensionContext,
|
||||
private databaseManager: DatabaseManager,
|
||||
private cliServer: CodeQLCliServer,
|
||||
private logger: Logger,
|
||||
@@ -45,7 +37,7 @@ export class CompareInterfaceManager extends DisposableObject {
|
||||
item: CompletedLocalQueryInfo
|
||||
) => Promise<void>
|
||||
) {
|
||||
super();
|
||||
super(ctx);
|
||||
}
|
||||
|
||||
async showResults(
|
||||
@@ -103,73 +95,24 @@ export class CompareInterfaceManager extends DisposableObject {
|
||||
}
|
||||
}
|
||||
|
||||
getPanel(): WebviewPanel {
|
||||
if (this.panel == undefined) {
|
||||
const { ctx } = this;
|
||||
const panel = (this.panel = Window.createWebviewPanel(
|
||||
'compareView',
|
||||
'Compare CodeQL Query Results',
|
||||
{ viewColumn: ViewColumn.Active, preserveFocus: true },
|
||||
{
|
||||
enableScripts: true,
|
||||
enableFindWidget: true,
|
||||
retainContextWhenHidden: true,
|
||||
localResourceRoots: [
|
||||
Uri.file(tmpDir.name),
|
||||
Uri.file(path.join(this.ctx.extensionPath, 'out')),
|
||||
],
|
||||
}
|
||||
));
|
||||
this.push(this.panel.onDidDispose(
|
||||
() => {
|
||||
this.panel = undefined;
|
||||
this.comparePair = undefined;
|
||||
},
|
||||
null,
|
||||
ctx.subscriptions
|
||||
));
|
||||
|
||||
const scriptPathOnDisk = Uri.file(
|
||||
ctx.asAbsolutePath('out/compareView.js')
|
||||
);
|
||||
|
||||
const stylesheetPathOnDisk = Uri.file(
|
||||
ctx.asAbsolutePath('out/view/resultsView.css')
|
||||
);
|
||||
|
||||
panel.webview.html = getHtmlForWebview(
|
||||
panel.webview,
|
||||
scriptPathOnDisk,
|
||||
[stylesheetPathOnDisk],
|
||||
false
|
||||
);
|
||||
this.push(panel.webview.onDidReceiveMessage(
|
||||
async (e) => this.handleMsgFromView(e),
|
||||
undefined,
|
||||
ctx.subscriptions
|
||||
));
|
||||
}
|
||||
return this.panel;
|
||||
protected getPanelConfig(): InterfacePanelConfig {
|
||||
return {
|
||||
viewId: 'compareView',
|
||||
title: 'Compare CodeQL Query Results',
|
||||
viewColumn: ViewColumn.Active,
|
||||
preserveFocus: true,
|
||||
view: 'compare',
|
||||
};
|
||||
}
|
||||
|
||||
private waitForPanelLoaded(): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
if (this.panelLoaded) {
|
||||
resolve();
|
||||
} else {
|
||||
this.panelLoadedCallBacks.push(resolve);
|
||||
}
|
||||
});
|
||||
protected onPanelDispose(): void {
|
||||
this.comparePair = undefined;
|
||||
}
|
||||
|
||||
private async handleMsgFromView(
|
||||
msg: FromCompareViewMessage
|
||||
): Promise<void> {
|
||||
protected async onMessage(msg: FromCompareViewMessage): Promise<void> {
|
||||
switch (msg.t) {
|
||||
case 'compareViewLoaded':
|
||||
this.panelLoaded = true;
|
||||
this.panelLoadedCallBacks.forEach((cb) => cb());
|
||||
this.panelLoadedCallBacks = [];
|
||||
this.onWebViewLoaded();
|
||||
break;
|
||||
|
||||
case 'changeCompare':
|
||||
@@ -186,10 +129,6 @@ export class CompareInterfaceManager extends DisposableObject {
|
||||
}
|
||||
}
|
||||
|
||||
private postMessage(msg: ToCompareViewMessage): Thenable<boolean> {
|
||||
return this.getPanel().webview.postMessage(msg);
|
||||
}
|
||||
|
||||
private async findCommonResultSetNames(
|
||||
from: CompletedLocalQueryInfo,
|
||||
to: CompletedLocalQueryInfo,
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true
|
||||
},
|
||||
extends: [
|
||||
"plugin:react/recommended"
|
||||
],
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"target": "es6",
|
||||
"outDir": "out",
|
||||
"lib": ["ES2021", "dom"],
|
||||
"jsx": "react",
|
||||
"sourceMap": true,
|
||||
"rootDir": "..",
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"experimentalDecorators": true
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import {
|
||||
import { CodeQLCliServer } from './cli';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import * as Octokit from '@octokit/rest';
|
||||
import { retry } from '@octokit/plugin-retry';
|
||||
|
||||
import { DatabaseManager, DatabaseItem } from './databases';
|
||||
import {
|
||||
@@ -76,7 +78,7 @@ export async function promptImportInternetDatabase(
|
||||
export async function promptImportGithubDatabase(
|
||||
databaseManager: DatabaseManager,
|
||||
storagePath: string,
|
||||
credentials: Credentials,
|
||||
credentials: Credentials | undefined,
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken,
|
||||
cli?: CodeQLCliServer
|
||||
@@ -99,14 +101,15 @@ export async function promptImportGithubDatabase(
|
||||
throw new Error(`Invalid GitHub repository: ${githubRepo}`);
|
||||
}
|
||||
|
||||
const result = await convertGithubNwoToDatabaseUrl(githubRepo, credentials, progress);
|
||||
const octokit = credentials ? await credentials.getOctokit(true) : new Octokit.Octokit({ retry });
|
||||
|
||||
const result = await convertGithubNwoToDatabaseUrl(githubRepo, octokit, progress);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { databaseUrl, name, owner } = result;
|
||||
|
||||
const octokit = await credentials.getOctokit();
|
||||
/**
|
||||
* The 'token' property of the token object returned by `octokit.auth()`.
|
||||
* The object is undocumented, but looks something like this:
|
||||
@@ -118,14 +121,9 @@ export async function promptImportGithubDatabase(
|
||||
* We only need the actual token string.
|
||||
*/
|
||||
const octokitToken = (await octokit.auth() as { token: string })?.token;
|
||||
if (!octokitToken) {
|
||||
// Just print a generic error message for now. Ideally we could show more debugging info, like the
|
||||
// octokit object, but that would expose a user token.
|
||||
throw new Error('Unable to get GitHub token.');
|
||||
}
|
||||
const item = await databaseArchiveFetcher(
|
||||
databaseUrl,
|
||||
{ 'Accept': 'application/zip', 'Authorization': `Bearer ${octokitToken}` },
|
||||
{ 'Accept': 'application/zip', 'Authorization': octokitToken ? `Bearer ${octokitToken}` : '' },
|
||||
databaseManager,
|
||||
storagePath,
|
||||
`${owner}/${name}`,
|
||||
@@ -523,7 +521,7 @@ function convertGitHubUrlToNwo(githubUrl: string): string | undefined {
|
||||
|
||||
export async function convertGithubNwoToDatabaseUrl(
|
||||
githubRepo: string,
|
||||
credentials: Credentials,
|
||||
octokit: Octokit.Octokit,
|
||||
progress: ProgressCallback): Promise<{
|
||||
databaseUrl: string,
|
||||
owner: string,
|
||||
@@ -533,7 +531,6 @@ export async function convertGithubNwoToDatabaseUrl(
|
||||
const nwo = convertGitHubUrlToNwo(githubRepo) || githubRepo;
|
||||
const [owner, repo] = nwo.split('/');
|
||||
|
||||
const octokit = await credentials.getOctokit();
|
||||
const response = await octokit.request('GET /repos/:owner/:repo/code-scanning/codeql/databases', { owner, repo });
|
||||
|
||||
const languages = response.data.map((db: any) => db.language);
|
||||
|
||||
@@ -40,6 +40,7 @@ import {
|
||||
import { CancellationToken } from 'vscode';
|
||||
import { asyncFilter, getErrorMessage } from './pure/helpers-pure';
|
||||
import { Credentials } from './authentication';
|
||||
import { isCanary } from './config';
|
||||
|
||||
type ThemableIconPath = { light: string; dark: string } | string;
|
||||
|
||||
@@ -301,7 +302,7 @@ export class DatabaseUI extends DisposableObject {
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken
|
||||
) => {
|
||||
const credentials = await this.getCredentials();
|
||||
const credentials = isCanary() ? await this.getCredentials() : undefined;
|
||||
await this.handleChooseDatabaseGithub(credentials, progress, token);
|
||||
},
|
||||
{
|
||||
@@ -480,7 +481,7 @@ export class DatabaseUI extends DisposableObject {
|
||||
};
|
||||
|
||||
handleChooseDatabaseGithub = async (
|
||||
credentials: Credentials,
|
||||
credentials: Credentials | undefined,
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken
|
||||
): Promise<DatabaseItem | undefined> => {
|
||||
|
||||
@@ -938,6 +938,8 @@ async function activateWithInstalledDistribution(
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken
|
||||
) => {
|
||||
// We restart the CLI server too, to ensure they are the same version
|
||||
cliServer.restartCliServer();
|
||||
await qs.restartQueryServer(progress, token);
|
||||
void showAndLogInformationMessage('CodeQL Query Server restarted.', {
|
||||
outputLogger: queryServerLogger,
|
||||
@@ -970,7 +972,7 @@ async function activateWithInstalledDistribution(
|
||||
progress: ProgressCallback,
|
||||
token: CancellationToken
|
||||
) => {
|
||||
const credentials = await Credentials.initialize(ctx);
|
||||
const credentials = isCanary() ? await Credentials.initialize(ctx) : undefined;
|
||||
await databaseUI.handleChooseDatabaseGithub(credentials, progress, token);
|
||||
},
|
||||
{
|
||||
@@ -1018,19 +1020,16 @@ async function activateWithInstalledDistribution(
|
||||
}
|
||||
};
|
||||
|
||||
// The "authenticateToGitHub" command is internal-only.
|
||||
ctx.subscriptions.push(
|
||||
commandRunner('codeQL.authenticateToGitHub', async () => {
|
||||
if (isCanary()) {
|
||||
/**
|
||||
* Credentials for authenticating to GitHub.
|
||||
* These are used when making API calls.
|
||||
*/
|
||||
const credentials = await Credentials.initialize(ctx);
|
||||
const octokit = await credentials.getOctokit();
|
||||
const userInfo = await octokit.users.getAuthenticated();
|
||||
void showAndLogInformationMessage(`Authenticated to GitHub as user: ${userInfo.data.login}`);
|
||||
}
|
||||
/**
|
||||
* Credentials for authenticating to GitHub.
|
||||
* These are used when making API calls.
|
||||
*/
|
||||
const credentials = await Credentials.initialize(ctx);
|
||||
const octokit = await credentials.getOctokit();
|
||||
const userInfo = await octokit.users.getAuthenticated();
|
||||
void showAndLogInformationMessage(`Authenticated to GitHub as user: ${userInfo.data.login}`);
|
||||
}));
|
||||
|
||||
ctx.subscriptions.push(
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
Uri,
|
||||
Location,
|
||||
Range,
|
||||
ExtensionContext,
|
||||
WebviewPanel,
|
||||
Webview,
|
||||
workspace,
|
||||
@@ -111,16 +112,36 @@ export function tryResolveLocation(
|
||||
}
|
||||
}
|
||||
|
||||
export type WebviewView = 'results' | 'compare' | 'remote-queries';
|
||||
|
||||
export interface WebviewMessage {
|
||||
t: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML to populate the given webview.
|
||||
* Uses a content security policy that only loads the given script.
|
||||
*/
|
||||
export function getHtmlForWebview(
|
||||
ctx: ExtensionContext,
|
||||
webview: Webview,
|
||||
scriptUriOnDisk: Uri,
|
||||
stylesheetUrisOnDisk: Uri[],
|
||||
allowInlineStyles: boolean
|
||||
view: WebviewView,
|
||||
{
|
||||
allowInlineStyles,
|
||||
}: {
|
||||
allowInlineStyles?: boolean;
|
||||
} = {
|
||||
allowInlineStyles: false,
|
||||
}
|
||||
): string {
|
||||
const scriptUriOnDisk = Uri.file(
|
||||
ctx.asAbsolutePath('out/webview.js')
|
||||
);
|
||||
|
||||
const stylesheetUrisOnDisk = [
|
||||
Uri.file(ctx.asAbsolutePath('out/webview.css'))
|
||||
];
|
||||
|
||||
// Convert the on-disk URIs into webview URIs.
|
||||
const scriptWebviewUri = webview.asWebviewUri(scriptUriOnDisk);
|
||||
const stylesheetWebviewUris = stylesheetUrisOnDisk.map(stylesheetUriOnDisk =>
|
||||
@@ -155,7 +176,7 @@ export function getHtmlForWebview(
|
||||
${stylesheetsHtmlLines.join(` ${os.EOL}`)}
|
||||
</head>
|
||||
<body>
|
||||
<div id=root>
|
||||
<div id=root data-view="${view}">
|
||||
</div>
|
||||
<script nonce="${nonce}" src="${scriptWebviewUri}">
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import * as path from 'path';
|
||||
import * as Sarif from 'sarif';
|
||||
import { DisposableObject } from './pure/disposable-object';
|
||||
import * as vscode from 'vscode';
|
||||
import {
|
||||
Diagnostic,
|
||||
@@ -14,7 +12,7 @@ import {
|
||||
import * as cli from './cli';
|
||||
import { CodeQLCliServer } from './cli';
|
||||
import { DatabaseEventKind, DatabaseItem, DatabaseManager } from './databases';
|
||||
import { showAndLogErrorMessage, tmpDir } from './helpers';
|
||||
import { showAndLogErrorMessage } from './helpers';
|
||||
import { assertNever, getErrorMessage, getErrorStack } from './pure/helpers-pure';
|
||||
import {
|
||||
FromResultsViewMsg,
|
||||
@@ -40,13 +38,13 @@ import {
|
||||
WebviewReveal,
|
||||
fileUriToWebviewUri,
|
||||
tryResolveLocation,
|
||||
getHtmlForWebview,
|
||||
shownLocationDecoration,
|
||||
shownLocationLineDecoration,
|
||||
jumpToLocation,
|
||||
} from './interface-utils';
|
||||
import { getDefaultResultSetName, ParsedResultSets } from './pure/interface-types';
|
||||
import { RawResultSet, transformBqrsResultSet, ResultSetSchema } from './pure/bqrs-cli-types';
|
||||
import { AbstractInterfaceManager, InterfacePanelConfig } from './abstract-interface-manager';
|
||||
import { PAGE_SIZE } from './config';
|
||||
import { CompletedLocalQueryInfo } from './query-results';
|
||||
import { HistoryItemLabelProvider } from './history-item-label-provider';
|
||||
@@ -122,12 +120,9 @@ function numInterpretedPages(interpretation: Interpretation | undefined): number
|
||||
return Math.ceil(n / pageSize);
|
||||
}
|
||||
|
||||
export class InterfaceManager extends DisposableObject {
|
||||
export class InterfaceManager extends AbstractInterfaceManager<IntoResultsViewMsg, FromResultsViewMsg> {
|
||||
private _displayedQuery?: CompletedLocalQueryInfo;
|
||||
private _interpretation?: Interpretation;
|
||||
private _panel: vscode.WebviewPanel | undefined;
|
||||
private _panelLoaded = false;
|
||||
private _panelLoadedCallBacks: (() => void)[] = [];
|
||||
|
||||
private readonly _diagnosticCollection = languages.createDiagnosticCollection(
|
||||
'codeql-query-results'
|
||||
@@ -140,7 +135,7 @@ export class InterfaceManager extends DisposableObject {
|
||||
public logger: Logger,
|
||||
private labelProvider: HistoryItemLabelProvider
|
||||
) {
|
||||
super();
|
||||
super(ctx);
|
||||
this.push(this._diagnosticCollection);
|
||||
this.push(
|
||||
vscode.window.onDidChangeTextEditorSelection(
|
||||
@@ -165,7 +160,7 @@ export class InterfaceManager extends DisposableObject {
|
||||
this.databaseManager.onDidChangeDatabaseItem(({ kind }) => {
|
||||
if (kind === DatabaseEventKind.Remove) {
|
||||
this._diagnosticCollection.clear();
|
||||
if (this.isShowingPanel()) {
|
||||
if (this.isShowingPanel) {
|
||||
void this.postMessage({
|
||||
t: 'untoggleShowProblems'
|
||||
});
|
||||
@@ -179,59 +174,81 @@ export class InterfaceManager extends DisposableObject {
|
||||
await this.postMessage({ t: 'navigatePath', direction });
|
||||
}
|
||||
|
||||
private isShowingPanel() {
|
||||
return !!this._panel;
|
||||
protected getPanelConfig(): InterfacePanelConfig {
|
||||
return {
|
||||
viewId: 'resultsView',
|
||||
title: 'CodeQL Query Results',
|
||||
viewColumn: this.chooseColumnForWebview(),
|
||||
preserveFocus: true,
|
||||
view: 'results',
|
||||
};
|
||||
}
|
||||
|
||||
// Returns the webview panel, creating it if it doesn't already
|
||||
// exist.
|
||||
getPanel(): vscode.WebviewPanel {
|
||||
if (this._panel == undefined) {
|
||||
const { ctx } = this;
|
||||
const webViewColumn = this.chooseColumnForWebview();
|
||||
const panel = (this._panel = Window.createWebviewPanel(
|
||||
'resultsView', // internal name
|
||||
'CodeQL Query Results', // user-visible name
|
||||
{ viewColumn: webViewColumn, preserveFocus: true },
|
||||
{
|
||||
enableScripts: true,
|
||||
enableFindWidget: true,
|
||||
retainContextWhenHidden: true,
|
||||
localResourceRoots: [
|
||||
vscode.Uri.file(tmpDir.name),
|
||||
vscode.Uri.file(path.join(this.ctx.extensionPath, 'out'))
|
||||
]
|
||||
}
|
||||
));
|
||||
protected onPanelDispose(): void {
|
||||
this._displayedQuery = undefined;
|
||||
}
|
||||
|
||||
this.push(this._panel.onDidDispose(
|
||||
() => {
|
||||
this._panel = undefined;
|
||||
this._displayedQuery = undefined;
|
||||
this._panelLoaded = false;
|
||||
},
|
||||
null,
|
||||
ctx.subscriptions
|
||||
));
|
||||
const scriptPathOnDisk = vscode.Uri.file(
|
||||
ctx.asAbsolutePath('out/resultsView.js')
|
||||
);
|
||||
const stylesheetPathOnDisk = vscode.Uri.file(
|
||||
ctx.asAbsolutePath('out/view/resultsView.css')
|
||||
);
|
||||
panel.webview.html = getHtmlForWebview(
|
||||
panel.webview,
|
||||
scriptPathOnDisk,
|
||||
[stylesheetPathOnDisk],
|
||||
false
|
||||
);
|
||||
this.push(panel.webview.onDidReceiveMessage(
|
||||
async (e) => this.handleMsgFromView(e),
|
||||
undefined,
|
||||
ctx.subscriptions
|
||||
));
|
||||
protected async onMessage(msg: FromResultsViewMsg): Promise<void> {
|
||||
try {
|
||||
switch (msg.t) {
|
||||
case 'resultViewLoaded':
|
||||
this.onWebViewLoaded();
|
||||
break;
|
||||
case 'viewSourceFile': {
|
||||
await jumpToLocation(msg, this.databaseManager, this.logger);
|
||||
break;
|
||||
}
|
||||
case 'toggleDiagnostics': {
|
||||
if (msg.visible) {
|
||||
const databaseItem = this.databaseManager.findDatabaseItem(
|
||||
Uri.parse(msg.databaseUri)
|
||||
);
|
||||
if (databaseItem !== undefined) {
|
||||
await this.showResultsAsDiagnostics(
|
||||
msg.origResultsPaths,
|
||||
msg.metadata,
|
||||
databaseItem
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// TODO: Only clear diagnostics on the same database.
|
||||
this._diagnosticCollection.clear();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'changeSort':
|
||||
await this.changeRawSortState(msg.resultSetName, msg.sortState);
|
||||
break;
|
||||
case 'changeInterpretedSort':
|
||||
await this.changeInterpretedSortState(msg.sortState);
|
||||
break;
|
||||
case 'changePage':
|
||||
if (msg.selectedTable === ALERTS_TABLE_NAME || msg.selectedTable === GRAPH_TABLE_NAME) {
|
||||
await this.showPageOfInterpretedResults(msg.pageNumber);
|
||||
}
|
||||
else {
|
||||
await this.showPageOfRawResults(
|
||||
msg.selectedTable,
|
||||
msg.pageNumber,
|
||||
// When we are in an unsorted state, we guarantee that
|
||||
// sortedResultsInfo doesn't have an entry for the current
|
||||
// result set. Use this to determine whether or not we use
|
||||
// the sorted bqrs file.
|
||||
!!this._displayedQuery?.completedQuery.sortedResultsInfo[msg.selectedTable]
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'openFile':
|
||||
await this.openFile(msg.filePath);
|
||||
break;
|
||||
default:
|
||||
assertNever(msg);
|
||||
}
|
||||
} catch (e) {
|
||||
void showAndLogErrorMessage(getErrorMessage(e), {
|
||||
fullMessage: getErrorStack(e)
|
||||
});
|
||||
}
|
||||
return this._panel;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,85 +313,6 @@ export class InterfaceManager extends DisposableObject {
|
||||
await this.showPageOfRawResults(resultSetName, 0, true);
|
||||
}
|
||||
|
||||
private async handleMsgFromView(msg: FromResultsViewMsg): Promise<void> {
|
||||
try {
|
||||
switch (msg.t) {
|
||||
case 'viewSourceFile': {
|
||||
await jumpToLocation(msg, this.databaseManager, this.logger);
|
||||
break;
|
||||
}
|
||||
case 'toggleDiagnostics': {
|
||||
if (msg.visible) {
|
||||
const databaseItem = this.databaseManager.findDatabaseItem(
|
||||
Uri.parse(msg.databaseUri)
|
||||
);
|
||||
if (databaseItem !== undefined) {
|
||||
await this.showResultsAsDiagnostics(
|
||||
msg.origResultsPaths,
|
||||
msg.metadata,
|
||||
databaseItem
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// TODO: Only clear diagnostics on the same database.
|
||||
this._diagnosticCollection.clear();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'resultViewLoaded':
|
||||
this._panelLoaded = true;
|
||||
this._panelLoadedCallBacks.forEach((cb) => cb());
|
||||
this._panelLoadedCallBacks = [];
|
||||
break;
|
||||
case 'changeSort':
|
||||
await this.changeRawSortState(msg.resultSetName, msg.sortState);
|
||||
break;
|
||||
case 'changeInterpretedSort':
|
||||
await this.changeInterpretedSortState(msg.sortState);
|
||||
break;
|
||||
case 'changePage':
|
||||
if (msg.selectedTable === ALERTS_TABLE_NAME || msg.selectedTable === GRAPH_TABLE_NAME) {
|
||||
await this.showPageOfInterpretedResults(msg.pageNumber);
|
||||
}
|
||||
else {
|
||||
await this.showPageOfRawResults(
|
||||
msg.selectedTable,
|
||||
msg.pageNumber,
|
||||
// When we are in an unsorted state, we guarantee that
|
||||
// sortedResultsInfo doesn't have an entry for the current
|
||||
// result set. Use this to determine whether or not we use
|
||||
// the sorted bqrs file.
|
||||
!!this._displayedQuery?.completedQuery.sortedResultsInfo[msg.selectedTable]
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'openFile':
|
||||
await this.openFile(msg.filePath);
|
||||
break;
|
||||
default:
|
||||
assertNever(msg);
|
||||
}
|
||||
} catch (e) {
|
||||
void showAndLogErrorMessage(getErrorMessage(e), {
|
||||
fullMessage: getErrorStack(e)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
postMessage(msg: IntoResultsViewMsg): Thenable<boolean> {
|
||||
return this.getPanel().webview.postMessage(msg);
|
||||
}
|
||||
|
||||
private waitForPanelLoaded(): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
if (this._panelLoaded) {
|
||||
resolve();
|
||||
} else {
|
||||
this._panelLoadedCallBacks.push(resolve);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show query results in webview panel.
|
||||
* @param fullQuery Evaluation info for the executed query.
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import {
|
||||
WebviewPanel,
|
||||
ExtensionContext,
|
||||
window as Window,
|
||||
ViewColumn,
|
||||
Uri,
|
||||
workspace,
|
||||
commands
|
||||
commands,
|
||||
} from 'vscode';
|
||||
import * as path from 'path';
|
||||
|
||||
@@ -16,7 +15,6 @@ import {
|
||||
RemoteQueryDownloadAllAnalysesResultsMessage
|
||||
} from '../pure/interface-types';
|
||||
import { Logger } from '../logging';
|
||||
import { getHtmlForWebview } from '../interface-utils';
|
||||
import { assertNever } from '../pure/helpers-pure';
|
||||
import {
|
||||
AnalysisSummary,
|
||||
@@ -34,18 +32,17 @@ import { SHOW_QUERY_TEXT_MSG } from '../query-history';
|
||||
import { AnalysesResultsManager } from './analyses-results-manager';
|
||||
import { AnalysisResults } from './shared/analysis-result';
|
||||
import { humanizeUnit } from '../pure/time';
|
||||
import { AbstractInterfaceManager, InterfacePanelConfig } from '../abstract-interface-manager';
|
||||
|
||||
export class RemoteQueriesInterfaceManager {
|
||||
private panel: WebviewPanel | undefined;
|
||||
private panelLoaded = false;
|
||||
export class RemoteQueriesInterfaceManager extends AbstractInterfaceManager<ToRemoteQueriesMessage, FromRemoteQueriesMessage> {
|
||||
private currentQueryId: string | undefined;
|
||||
private panelLoadedCallBacks: (() => void)[] = [];
|
||||
|
||||
constructor(
|
||||
private readonly ctx: ExtensionContext,
|
||||
ctx: ExtensionContext,
|
||||
private readonly logger: Logger,
|
||||
private readonly analysesResultsManager: AnalysesResultsManager
|
||||
) {
|
||||
super(ctx);
|
||||
this.panelLoadedCallBacks.push(() => {
|
||||
void logger.log('Variant analysis results view loaded');
|
||||
});
|
||||
@@ -103,112 +100,29 @@ export class RemoteQueriesInterfaceManager {
|
||||
};
|
||||
}
|
||||
|
||||
getPanel(): WebviewPanel {
|
||||
if (this.panel == undefined) {
|
||||
const { ctx } = this;
|
||||
const panel = (this.panel = Window.createWebviewPanel(
|
||||
'remoteQueriesView',
|
||||
'CodeQL Query Results',
|
||||
{ viewColumn: ViewColumn.Active, preserveFocus: true },
|
||||
{
|
||||
enableScripts: true,
|
||||
enableFindWidget: true,
|
||||
retainContextWhenHidden: true,
|
||||
localResourceRoots: [
|
||||
Uri.file(this.analysesResultsManager.storagePath),
|
||||
Uri.file(path.join(this.ctx.extensionPath, 'out')),
|
||||
Uri.file(path.join(this.ctx.extensionPath, 'node_modules/@vscode/codicons/dist')),
|
||||
],
|
||||
}
|
||||
));
|
||||
this.panel.onDidDispose(
|
||||
() => {
|
||||
this.panel = undefined;
|
||||
this.currentQueryId = undefined;
|
||||
this.panelLoaded = false;
|
||||
},
|
||||
null,
|
||||
ctx.subscriptions
|
||||
);
|
||||
|
||||
const scriptPathOnDisk = Uri.file(
|
||||
ctx.asAbsolutePath('out/remoteQueriesView.js')
|
||||
);
|
||||
|
||||
const baseStylesheetUriOnDisk = Uri.file(
|
||||
ctx.asAbsolutePath('out/remote-queries/view/baseStyles.css')
|
||||
);
|
||||
|
||||
const stylesheetPathOnDisk = Uri.file(
|
||||
ctx.asAbsolutePath('out/remote-queries/view/remoteQueries.css')
|
||||
);
|
||||
|
||||
// Allows use of the VS Code "codicons" icon set.
|
||||
// See https://github.com/microsoft/vscode-codicons
|
||||
const codiconsPathOnDisk = Uri.file(
|
||||
ctx.asAbsolutePath('node_modules/@vscode/codicons/dist/codicon.css')
|
||||
);
|
||||
|
||||
panel.webview.html = getHtmlForWebview(
|
||||
panel.webview,
|
||||
scriptPathOnDisk,
|
||||
[baseStylesheetUriOnDisk, stylesheetPathOnDisk, codiconsPathOnDisk],
|
||||
true
|
||||
);
|
||||
ctx.subscriptions.push(
|
||||
panel.webview.onDidReceiveMessage(
|
||||
async (e) => this.handleMsgFromView(e),
|
||||
undefined,
|
||||
ctx.subscriptions
|
||||
)
|
||||
);
|
||||
}
|
||||
return this.panel;
|
||||
}
|
||||
|
||||
private waitForPanelLoaded(): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
if (this.panelLoaded) {
|
||||
resolve();
|
||||
} else {
|
||||
this.panelLoadedCallBacks.push(resolve);
|
||||
protected getPanelConfig(): InterfacePanelConfig {
|
||||
return {
|
||||
viewId: 'remoteQueriesView',
|
||||
title: 'CodeQL Query Results',
|
||||
viewColumn: ViewColumn.Active,
|
||||
preserveFocus: true,
|
||||
view: 'remote-queries',
|
||||
additionalOptions: {
|
||||
localResourceRoots: [
|
||||
Uri.file(this.analysesResultsManager.storagePath)
|
||||
]
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
private async openFile(filePath: string) {
|
||||
try {
|
||||
const textDocument = await workspace.openTextDocument(filePath);
|
||||
await Window.showTextDocument(textDocument, ViewColumn.One);
|
||||
} catch (error) {
|
||||
void showAndLogWarningMessage(`Could not open file: ${filePath}`);
|
||||
}
|
||||
protected onPanelDispose(): void {
|
||||
this.currentQueryId = undefined;
|
||||
}
|
||||
|
||||
private async openVirtualFile(text: string) {
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
queryText: encodeURIComponent(SHOW_QUERY_TEXT_MSG + text)
|
||||
});
|
||||
const uri = Uri.parse(
|
||||
`remote-query:query-text.ql?${params.toString()}`,
|
||||
true
|
||||
);
|
||||
const doc = await workspace.openTextDocument(uri);
|
||||
await Window.showTextDocument(doc, { preview: false });
|
||||
} catch (error) {
|
||||
void showAndLogWarningMessage('Could not open query text');
|
||||
}
|
||||
}
|
||||
|
||||
private async handleMsgFromView(
|
||||
msg: FromRemoteQueriesMessage
|
||||
): Promise<void> {
|
||||
protected async onMessage(msg: FromRemoteQueriesMessage): Promise<void> {
|
||||
switch (msg.t) {
|
||||
case 'remoteQueryLoaded':
|
||||
this.panelLoaded = true;
|
||||
this.panelLoadedCallBacks.forEach((cb) => cb());
|
||||
this.panelLoadedCallBacks = [];
|
||||
this.onWebViewLoaded();
|
||||
break;
|
||||
case 'remoteQueryError':
|
||||
void this.logger.log(
|
||||
@@ -238,6 +152,31 @@ export class RemoteQueriesInterfaceManager {
|
||||
}
|
||||
}
|
||||
|
||||
private async openFile(filePath: string) {
|
||||
try {
|
||||
const textDocument = await workspace.openTextDocument(filePath);
|
||||
await Window.showTextDocument(textDocument, ViewColumn.One);
|
||||
} catch (error) {
|
||||
void showAndLogWarningMessage(`Could not open file: ${filePath}`);
|
||||
}
|
||||
}
|
||||
|
||||
private async openVirtualFile(text: string) {
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
queryText: encodeURIComponent(SHOW_QUERY_TEXT_MSG + text)
|
||||
});
|
||||
const uri = Uri.parse(
|
||||
`remote-query:query-text.ql?${params.toString()}`,
|
||||
true
|
||||
);
|
||||
const doc = await workspace.openTextDocument(uri);
|
||||
await Window.showTextDocument(doc, { preview: false });
|
||||
} catch (error) {
|
||||
void showAndLogWarningMessage('Could not open query text');
|
||||
}
|
||||
}
|
||||
|
||||
private async downloadAnalysisResults(msg: RemoteQueryDownloadAnalysisResultsMessage): Promise<void> {
|
||||
const queryId = this.currentQueryId;
|
||||
await this.analysesResultsManager.downloadAnalysisResults(
|
||||
@@ -262,10 +201,6 @@ export class RemoteQueriesInterfaceManager {
|
||||
}
|
||||
}
|
||||
|
||||
private postMessage(msg: ToRemoteQueriesMessage): Thenable<boolean> {
|
||||
return this.getPanel().webview.postMessage(msg);
|
||||
}
|
||||
|
||||
private getDuration(startTime: number, endTime: number): string {
|
||||
const diffInMs = startTime - endTime;
|
||||
return humanizeUnit(diffInMs);
|
||||
|
||||
@@ -75,6 +75,8 @@ export class RemoteQueriesManager extends DisposableObject {
|
||||
this.onRemoteQueryAdded = this.remoteQueryAddedEventEmitter.event;
|
||||
this.onRemoteQueryRemoved = this.remoteQueryRemovedEventEmitter.event;
|
||||
this.onRemoteQueryStatusUpdate = this.remoteQueryStatusUpdateEventEmitter.event;
|
||||
|
||||
this.push(this.interfaceManager);
|
||||
}
|
||||
|
||||
public async rehydrateRemoteQuery(queryId: string, query: RemoteQuery, status: QueryStatus) {
|
||||
|
||||
@@ -217,7 +217,7 @@ export async function runRemoteQuery(
|
||||
if (!controllerRepo || !REPO_REGEX.test(controllerRepo)) {
|
||||
void logger.log(controllerRepo ? 'Invalid controller repository name.' : 'No controller repository defined.');
|
||||
controllerRepo = await window.showInputBox({
|
||||
title: 'Controller repository in which to display progress and results of variant analysis',
|
||||
title: 'Controller repository in which to run the GitHub Actions workflow for this variant analysis',
|
||||
placeHolder: '<owner>/<repo>',
|
||||
prompt: 'Enter the name of a GitHub repository in the format <owner>/<repo>',
|
||||
ignoreFocusOut: true,
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true
|
||||
},
|
||||
extends: [
|
||||
"plugin:react/recommended"
|
||||
],
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"target": "es6",
|
||||
"outDir": "out",
|
||||
"lib": ["ES2021", "dom"],
|
||||
"jsx": "react",
|
||||
"sourceMap": true,
|
||||
"rootDir": "..",
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"experimentalDecorators": true
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -36,7 +36,7 @@ import { compileDatabaseUpgradeSequence, hasNondestructiveUpgradeCapabilities, u
|
||||
import { ensureMetadataIsComplete } from './query-results';
|
||||
import { SELECT_QUERY_NAME } from './contextual/locationFinder';
|
||||
import { DecodedBqrsChunk } from './pure/bqrs-cli-types';
|
||||
import { getErrorMessage } from './pure/helpers-pure';
|
||||
import { asError, getErrorMessage } from './pure/helpers-pure';
|
||||
import { generateSummarySymbolsFile } from './log-insights/summary-parser';
|
||||
|
||||
/**
|
||||
@@ -207,7 +207,10 @@ export class QueryEvaluationInfo {
|
||||
logPath: this.evalLogPath,
|
||||
});
|
||||
if (await this.hasEvalLog()) {
|
||||
this.displayHumanReadableLogSummary(queryInfo, qs);
|
||||
queryInfo.evalLogLocation = this.evalLogPath;
|
||||
queryInfo.evalLogSummaryLocation = await this.generateHumanReadableLogSummary(qs);
|
||||
void this.logEndSummary(queryInfo.evalLogSummaryLocation, qs); // Logged asynchrnously
|
||||
|
||||
if (config.isCanary()) { // Generate JSON summary for viewer.
|
||||
await qs.cliServer.generateJsonLogSummary(this.evalLogPath, this.jsonEvalLogSummaryPath);
|
||||
queryInfo.jsonEvalLogSummaryLocation = this.jsonEvalLogSummaryPath;
|
||||
@@ -340,25 +343,40 @@ export class QueryEvaluationInfo {
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the appropriate CLI command to generate a human-readable log summary
|
||||
* and logs to the Query Server console and query log file.
|
||||
* Calls the appropriate CLI command to generate a human-readable log summary.
|
||||
* @param qs The query server client.
|
||||
* @returns The path to the log summary, or `undefined` if the summary could not be generated.
|
||||
*/
|
||||
displayHumanReadableLogSummary(queryInfo: LocalQueryInfo, qs: qsClient.QueryServerClient): void {
|
||||
queryInfo.evalLogLocation = this.evalLogPath;
|
||||
void qs.cliServer.generateLogSummary(this.evalLogPath, this.evalLogSummaryPath, this.evalLogEndSummaryPath)
|
||||
.then(() => {
|
||||
queryInfo.evalLogSummaryLocation = this.evalLogSummaryPath;
|
||||
fs.readFile(this.evalLogEndSummaryPath, (err, buffer) => {
|
||||
if (err) {
|
||||
throw new Error(`Could not read structured evaluator log end of summary file at ${this.evalLogEndSummaryPath}.`);
|
||||
}
|
||||
void qs.logger.log(' --- Evaluator Log Summary --- ', { additionalLogLocation: this.logPath });
|
||||
void qs.logger.log(buffer.toString(), { additionalLogLocation: this.logPath });
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
void showAndLogWarningMessage(`Failed to generate human-readable structured evaluator log summary. Reason: ${err.message}`);
|
||||
});
|
||||
private async generateHumanReadableLogSummary(qs: qsClient.QueryServerClient): Promise<string | undefined> {
|
||||
try {
|
||||
await qs.cliServer.generateLogSummary(this.evalLogPath, this.evalLogSummaryPath, this.evalLogEndSummaryPath);
|
||||
return this.evalLogSummaryPath;
|
||||
|
||||
} catch (e) {
|
||||
const err = asError(e);
|
||||
void showAndLogWarningMessage(`Failed to generate human-readable structured evaluator log summary. Reason: ${err.message}`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the end summary to the Output window and log file.
|
||||
* @param logSummaryPath Path to the human-readable log summary
|
||||
* @param qs The query server client.
|
||||
*/
|
||||
private async logEndSummary(logSummaryPath: string | undefined, qs: qsClient.QueryServerClient): Promise<void> {
|
||||
if (logSummaryPath === undefined) {
|
||||
// Failed to generate the log, so we don't expect an end summary either.
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const endSummaryContent = await fs.readFile(this.evalLogEndSummaryPath, 'utf-8');
|
||||
void qs.logger.log(' --- Evaluator Log Summary --- ', { additionalLogLocation: this.logPath });
|
||||
void qs.logger.log(endSummaryContent, { additionalLogLocation: this.logPath });
|
||||
} catch (e) {
|
||||
void showAndLogWarningMessage(`Could not read structured evaluator log end of summary file at ${this.evalLogEndSummaryPath}.`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import * as React from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import * as Rdom from 'react-dom';
|
||||
|
||||
import {
|
||||
ToCompareViewMessage,
|
||||
SetComparisonsMessage,
|
||||
} from '../../pure/interface-types';
|
||||
import CompareSelector from './CompareSelector';
|
||||
import { vscode } from '../../view/vscode-api';
|
||||
import { vscode } from '../vscode-api';
|
||||
import CompareTable from './CompareTable';
|
||||
|
||||
import '../results/resultsView.css';
|
||||
|
||||
const emptyComparison: SetComparisonsMessage = {
|
||||
t: 'setComparisons',
|
||||
stats: {},
|
||||
@@ -75,10 +76,3 @@ export function Compare(_: Record<string, never>): JSX.Element {
|
||||
return <div>Error!</div>;
|
||||
}
|
||||
}
|
||||
|
||||
Rdom.render(
|
||||
<Compare />,
|
||||
document.getElementById('root'),
|
||||
// Post a message to the extension when fully loaded.
|
||||
() => vscode.postMessage({ t: 'compareViewLoaded' })
|
||||
);
|
||||
@@ -1,11 +1,11 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { SetComparisonsMessage } from '../../pure/interface-types';
|
||||
import RawTableHeader from '../../view/RawTableHeader';
|
||||
import { className } from '../../view/result-table-utils';
|
||||
import RawTableHeader from '../results/RawTableHeader';
|
||||
import { className } from '../results/result-table-utils';
|
||||
import { ResultRow } from '../../pure/bqrs-cli-types';
|
||||
import RawTableRow from '../../view/RawTableRow';
|
||||
import { vscode } from '../../view/vscode-api';
|
||||
import RawTableRow from '../results/RawTableRow';
|
||||
import { vscode } from '../vscode-api';
|
||||
|
||||
interface Props {
|
||||
comparison: SetComparisonsMessage;
|
||||
10
extensions/ql-vscode/src/view/compare/index.tsx
Normal file
10
extensions/ql-vscode/src/view/compare/index.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import * as React from 'react';
|
||||
import { WebviewDefinition } from '../webview-interface';
|
||||
import { Compare } from './Compare';
|
||||
|
||||
const definition: WebviewDefinition = {
|
||||
component: <Compare />,
|
||||
loadedMessage: 'compareViewLoaded'
|
||||
};
|
||||
|
||||
export default definition;
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { AnalysisAlert } from '../shared/analysis-result';
|
||||
import { AnalysisAlert } from '../../remote-queries/shared/analysis-result';
|
||||
import CodePaths from './CodePaths';
|
||||
import FileCodeSnippet from './FileCodeSnippet';
|
||||
|
||||
@@ -4,7 +4,7 @@ import { VSCodeDropdown, VSCodeLink, VSCodeOption, VSCodeTag } from '@vscode/web
|
||||
import * as React from 'react';
|
||||
import { ChangeEvent, useRef, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { CodeFlow, AnalysisMessage, ResultSeverity } from '../shared/analysis-result';
|
||||
import { CodeFlow, AnalysisMessage, ResultSeverity } from '../../remote-queries/shared/analysis-result';
|
||||
import FileCodeSnippet from './FileCodeSnippet';
|
||||
import SectionTitle from './SectionTitle';
|
||||
import VerticalSpace from './VerticalSpace';
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { CodeSnippet, FileLink, HighlightedRegion, AnalysisMessage, ResultSeverity } from '../shared/analysis-result';
|
||||
import { CodeSnippet, FileLink, HighlightedRegion, AnalysisMessage, ResultSeverity } from '../../remote-queries/shared/analysis-result';
|
||||
import VerticalSpace from './VerticalSpace';
|
||||
import { createRemoteFileRef } from '../../pure/location-link-utils';
|
||||
import { parseHighlightedLine, shouldHighlightLine } from '../../pure/sarif-utils';
|
||||
@@ -1,18 +1,17 @@
|
||||
import * as React from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import * as Rdom from 'react-dom';
|
||||
import { Flash, ThemeProvider } from '@primer/react';
|
||||
import { ToRemoteQueriesMessage } from '../../pure/interface-types';
|
||||
import { AnalysisSummary, RemoteQueryResult } from '../shared/remote-query-result';
|
||||
import { MAX_RAW_RESULTS } from '../shared/result-limits';
|
||||
import { vscode } from '../../view/vscode-api';
|
||||
import { AnalysisSummary, RemoteQueryResult } from '../../remote-queries/shared/remote-query-result';
|
||||
import { MAX_RAW_RESULTS } from '../../remote-queries/shared/result-limits';
|
||||
import { vscode } from '../vscode-api';
|
||||
import { VSCodeBadge, VSCodeButton } from '@vscode/webview-ui-toolkit/react';
|
||||
import SectionTitle from './SectionTitle';
|
||||
import VerticalSpace from './VerticalSpace';
|
||||
import HorizontalSpace from './HorizontalSpace';
|
||||
import ViewTitle from './ViewTitle';
|
||||
import DownloadButton from './DownloadButton';
|
||||
import { AnalysisResults, getAnalysisResultCount } from '../shared/analysis-result';
|
||||
import { AnalysisResults, getAnalysisResultCount } from '../../remote-queries/shared/analysis-result';
|
||||
import DownloadSpinner from './DownloadSpinner';
|
||||
import CollapsibleItem from './CollapsibleItem';
|
||||
import { AlertIcon, CodeSquareIcon, FileCodeIcon, RepoIcon, TerminalIcon } from '@primer/octicons-react';
|
||||
@@ -24,6 +23,9 @@ import SortRepoFilter, { Sort, sorter } from './SortRepoFilter';
|
||||
import LastUpdated from './LastUpdated';
|
||||
import RepoListCopyButton from './RepoListCopyButton';
|
||||
|
||||
import './baseStyles.css';
|
||||
import './remoteQueries.css';
|
||||
|
||||
const numOfReposInContractedMode = 10;
|
||||
|
||||
const emptyQueryResult: RemoteQueryResult = {
|
||||
@@ -440,10 +442,3 @@ export function RemoteQueries(): JSX.Element {
|
||||
return <div>There was an error displaying the view.</div>;
|
||||
}
|
||||
}
|
||||
|
||||
Rdom.render(
|
||||
<RemoteQueries />,
|
||||
document.getElementById('root'),
|
||||
// Post a message to the extension when fully loaded.
|
||||
() => vscode.postMessage({ t: 'remoteQueryLoaded' })
|
||||
);
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import { vscode } from '../../view/vscode-api';
|
||||
import { RemoteQueryResult } from '../shared/remote-query-result';
|
||||
import { vscode } from '../vscode-api';
|
||||
import { RemoteQueryResult } from '../../remote-queries/shared/remote-query-result';
|
||||
import { CopyIcon } from '@primer/octicons-react';
|
||||
import { IconButton } from '@primer/react';
|
||||
|
||||
10
extensions/ql-vscode/src/view/remote-queries/index.tsx
Normal file
10
extensions/ql-vscode/src/view/remote-queries/index.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import * as React from 'react';
|
||||
import { WebviewDefinition } from '../webview-interface';
|
||||
import { RemoteQueries } from './RemoteQueries';
|
||||
|
||||
const definition: WebviewDefinition = {
|
||||
component: <RemoteQueries />,
|
||||
loadedMessage: 'remoteQueryLoaded'
|
||||
};
|
||||
|
||||
export default definition;
|
||||
@@ -1,9 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { vscode } from './vscode-api';
|
||||
import { RawResultsSortState, SortDirection } from '../pure/interface-types';
|
||||
import { vscode } from '../vscode-api';
|
||||
import { RawResultsSortState, SortDirection } from '../../pure/interface-types';
|
||||
import { nextSortDirection } from './result-table-utils';
|
||||
import { Column } from '../pure/bqrs-cli-types';
|
||||
import { Column } from '../../pure/bqrs-cli-types';
|
||||
|
||||
interface Props {
|
||||
readonly columns: readonly Column[];
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { ResultRow } from '../pure/bqrs-cli-types';
|
||||
import { ResultRow } from '../../pure/bqrs-cli-types';
|
||||
import { zebraStripe } from './result-table-utils';
|
||||
import RawTableValue from './RawTableValue';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { renderLocation } from './result-table-utils';
|
||||
import { CellValue } from '../pure/bqrs-cli-types';
|
||||
import { CellValue } from '../../pure/bqrs-cli-types';
|
||||
|
||||
interface Props {
|
||||
value: CellValue;
|
||||
@@ -1,19 +1,19 @@
|
||||
import * as path from 'path';
|
||||
import * as React from 'react';
|
||||
import * as Sarif from 'sarif';
|
||||
import * as Keys from '../pure/result-keys';
|
||||
import * as Keys from '../../pure/result-keys';
|
||||
import * as octicons from './octicons';
|
||||
import { className, renderLocation, ResultTableProps, zebraStripe, selectableZebraStripe, jumpToLocation, nextSortDirection, emptyQueryResultsMessage } from './result-table-utils';
|
||||
import { onNavigation, NavigationEvent } from './results';
|
||||
import { InterpretedResultSet, SarifInterpretationData } from '../pure/interface-types';
|
||||
import { InterpretedResultSet, SarifInterpretationData } from '../../pure/interface-types';
|
||||
import {
|
||||
parseSarifPlainTextMessage,
|
||||
parseSarifLocation,
|
||||
isNoLocation
|
||||
} from '../pure/sarif-utils';
|
||||
import { InterpretedResultsSortColumn, SortDirection, InterpretedResultsSortState } from '../pure/interface-types';
|
||||
import { vscode } from './vscode-api';
|
||||
import { isWholeFileLoc, isLineColumnLoc } from '../pure/bqrs-utils';
|
||||
} from '../../pure/sarif-utils';
|
||||
import { InterpretedResultsSortColumn, SortDirection, InterpretedResultsSortState } from '../../pure/interface-types';
|
||||
import { vscode } from '../vscode-api';
|
||||
import { isWholeFileLoc, isLineColumnLoc } from '../../pure/bqrs-utils';
|
||||
|
||||
export type PathTableProps = ResultTableProps & { resultSet: InterpretedResultSet<SarifInterpretationData> };
|
||||
export interface PathTableState {
|
||||
@@ -1,10 +1,10 @@
|
||||
import * as React from 'react';
|
||||
import * as d3 from 'd3';
|
||||
import { ResultTableProps } from './result-table-utils';
|
||||
import { InterpretedResultSet, GraphInterpretationData } from '../pure/interface-types';
|
||||
import { InterpretedResultSet, GraphInterpretationData } from '../../pure/interface-types';
|
||||
import { graphviz } from 'd3-graphviz';
|
||||
import { jumpToLocation } from './result-table-utils';
|
||||
import { tryGetLocationFromString } from '../pure/bqrs-utils';
|
||||
import { tryGetLocationFromString } from '../../pure/bqrs-utils';
|
||||
export type GraphProps = ResultTableProps & { resultSet: InterpretedResultSet<GraphInterpretationData> };
|
||||
|
||||
const graphClassName = 'vscode-codeql__result-tables-graph';
|
||||
10
extensions/ql-vscode/src/view/results/index.tsx
Normal file
10
extensions/ql-vscode/src/view/results/index.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import * as React from 'react';
|
||||
import { WebviewDefinition } from '../webview-interface';
|
||||
import { ResultsApp } from './results';
|
||||
|
||||
const definition: WebviewDefinition = {
|
||||
component: <ResultsApp />,
|
||||
loadedMessage: 'resultViewLoaded'
|
||||
};
|
||||
|
||||
export default definition;
|
||||
@@ -1,10 +1,10 @@
|
||||
import * as React from 'react';
|
||||
import { ResultTableProps, className, emptyQueryResultsMessage } from './result-table-utils';
|
||||
import { RAW_RESULTS_LIMIT, RawResultsSortState } from '../pure/interface-types';
|
||||
import { RawTableResultSet } from '../pure/interface-types';
|
||||
import { RAW_RESULTS_LIMIT, RawResultsSortState } from '../../pure/interface-types';
|
||||
import { RawTableResultSet } from '../../pure/interface-types';
|
||||
import RawTableHeader from './RawTableHeader';
|
||||
import RawTableRow from './RawTableRow';
|
||||
import { ResultRow } from '../pure/bqrs-cli-types';
|
||||
import { ResultRow } from '../../pure/bqrs-cli-types';
|
||||
|
||||
export type RawTableProps = ResultTableProps & {
|
||||
resultSet: RawTableResultSet;
|
||||
@@ -1,11 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import { UrlValue, ResolvableLocationValue } from '../pure/bqrs-cli-types';
|
||||
import { isStringLoc, tryGetResolvableLocation } from '../pure/bqrs-utils';
|
||||
import { RawResultsSortState, QueryMetadata, SortDirection } from '../pure/interface-types';
|
||||
import { assertNever } from '../pure/helpers-pure';
|
||||
import { ResultSet } from '../pure/interface-types';
|
||||
import { vscode } from './vscode-api';
|
||||
import { convertNonPrintableChars } from '../text-utils';
|
||||
import { UrlValue, ResolvableLocationValue } from '../../pure/bqrs-cli-types';
|
||||
import { isStringLoc, tryGetResolvableLocation } from '../../pure/bqrs-utils';
|
||||
import { RawResultsSortState, QueryMetadata, SortDirection } from '../../pure/interface-types';
|
||||
import { assertNever } from '../../pure/helpers-pure';
|
||||
import { ResultSet } from '../../pure/interface-types';
|
||||
import { vscode } from '../vscode-api';
|
||||
import { convertNonPrintableChars } from '../../text-utils';
|
||||
|
||||
export interface ResultTableProps {
|
||||
resultSet: ResultSet;
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
getDefaultResultSetName,
|
||||
ParsedResultSets,
|
||||
IntoResultsViewMsg,
|
||||
} from '../pure/interface-types';
|
||||
} from '../../pure/interface-types';
|
||||
import { PathTable } from './alert-table';
|
||||
import { Graph } from './graph';
|
||||
import { RawTable } from './raw-results-table';
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
alertExtrasClassName,
|
||||
openFile
|
||||
} from './result-table-utils';
|
||||
import { vscode } from './vscode-api';
|
||||
import { vscode } from '../vscode-api';
|
||||
|
||||
|
||||
const FILE_PATH_REGEX = /^(?:.+[\\/])*(.+)$/;
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import * as Rdom from 'react-dom';
|
||||
import { assertNever } from '../pure/helpers-pure';
|
||||
import { assertNever } from '../../pure/helpers-pure';
|
||||
import {
|
||||
DatabaseInfo,
|
||||
Interpretation,
|
||||
@@ -13,11 +12,12 @@ import {
|
||||
ALERTS_TABLE_NAME,
|
||||
GRAPH_TABLE_NAME,
|
||||
ParsedResultSets,
|
||||
} from '../pure/interface-types';
|
||||
} from '../../pure/interface-types';
|
||||
import { EventHandlers as EventHandlerList } from './event-handler-list';
|
||||
import { ResultTables } from './result-tables';
|
||||
import { ResultSet } from '../pure/interface-types';
|
||||
import { vscode } from './vscode-api';
|
||||
import { ResultSet } from '../../pure/interface-types';
|
||||
|
||||
import './resultsView.css';
|
||||
|
||||
/**
|
||||
* results.tsx
|
||||
@@ -72,7 +72,7 @@ export const onNavigation = new EventHandlerList<NavigationEvent>();
|
||||
/**
|
||||
* A minimal state container for displaying results.
|
||||
*/
|
||||
class App extends React.Component<Record<string, never>, ResultsViewState> {
|
||||
export class ResultsApp extends React.Component<Record<string, never>, ResultsViewState> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@@ -302,7 +302,6 @@ class App extends React.Component<Record<string, never>, ResultsViewState> {
|
||||
componentDidMount(): void {
|
||||
this.vscodeMessageHandler = this.vscodeMessageHandler.bind(this);
|
||||
window.addEventListener('message', this.vscodeMessageHandler);
|
||||
vscode.postMessage({ t: 'resultViewLoaded' });
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
@@ -319,5 +318,3 @@ class App extends React.Component<Record<string, never>, ResultsViewState> {
|
||||
: console.error(`Invalid event origin ${origin}`);
|
||||
}
|
||||
}
|
||||
|
||||
Rdom.render(<App />, document.getElementById('root'));
|
||||
4
extensions/ql-vscode/src/view/webview-interface.ts
Normal file
4
extensions/ql-vscode/src/view/webview-interface.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export type WebviewDefinition = {
|
||||
component: JSX.Element,
|
||||
loadedMessage: 'compareViewLoaded' | 'remoteQueryLoaded' | 'resultViewLoaded';
|
||||
}
|
||||
36
extensions/ql-vscode/src/view/webview.tsx
Normal file
36
extensions/ql-vscode/src/view/webview.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { vscode } from './vscode-api';
|
||||
|
||||
import { WebviewDefinition } from './webview-interface';
|
||||
|
||||
// Allow all views to use Codicons
|
||||
import '@vscode/codicons/dist/codicon.css';
|
||||
|
||||
const render = () => {
|
||||
const element = document.getElementById('root');
|
||||
|
||||
if (!element) {
|
||||
console.error('Could not find element with id "root"');
|
||||
return;
|
||||
}
|
||||
|
||||
const viewName = element.dataset.view;
|
||||
if (!viewName) {
|
||||
console.error('Could not find view name in data-view attribute');
|
||||
return;
|
||||
}
|
||||
|
||||
// It's a lot harder to use dynamic imports since those don't import the CSS
|
||||
// and require a less strict CSP policy
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const view: WebviewDefinition = require(`./${viewName}/index.tsx`).default;
|
||||
|
||||
ReactDOM.render(
|
||||
view.component,
|
||||
document.getElementById('root'),
|
||||
// Post a message to the extension when fully loaded.
|
||||
() => vscode.postMessage({ t: view.loadedMessage })
|
||||
);
|
||||
};
|
||||
|
||||
render();
|
||||
@@ -44,7 +44,7 @@ const _10MB = _1MB * 10;
|
||||
|
||||
// CLI version to test. Hard code the latest as default. And be sure
|
||||
// to update the env if it is not otherwise set.
|
||||
const CLI_VERSION = process.env.CLI_VERSION || 'v2.10.3';
|
||||
const CLI_VERSION = process.env.CLI_VERSION || 'v2.10.4';
|
||||
process.env.CLI_VERSION = CLI_VERSION;
|
||||
|
||||
// Base dir where CLIs will be downloaded into
|
||||
|
||||
@@ -6,15 +6,14 @@ import { expect } from 'chai';
|
||||
import { window } from 'vscode';
|
||||
|
||||
import {
|
||||
convertGithubNwoToDatabaseUrl,
|
||||
convertLgtmUrlToDatabaseUrl,
|
||||
looksLikeLgtmUrl,
|
||||
findDirWithFile,
|
||||
looksLikeGithubRepo,
|
||||
} from '../../databaseFetcher';
|
||||
import { ProgressCallback } from '../../commandRunner';
|
||||
import * as pq from 'proxyquire';
|
||||
|
||||
const proxyquire = pq.noPreserveCache();
|
||||
import * as Octokit from '@octokit/rest';
|
||||
|
||||
describe('databaseFetcher', function() {
|
||||
// These tests make API calls and may need extra time to complete.
|
||||
@@ -25,20 +24,16 @@ describe('databaseFetcher', function() {
|
||||
let quickPickSpy: sinon.SinonStub;
|
||||
let progressSpy: ProgressCallback;
|
||||
let mockRequest: sinon.SinonStub;
|
||||
let mod: any;
|
||||
|
||||
const credentials = getMockCredentials(0);
|
||||
let octokit: Octokit.Octokit;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
quickPickSpy = sandbox.stub(window, 'showQuickPick');
|
||||
progressSpy = sandbox.spy();
|
||||
mockRequest = sandbox.stub();
|
||||
mod = proxyquire('../../databaseFetcher', {
|
||||
'./authentication': {
|
||||
Credentials: credentials,
|
||||
},
|
||||
});
|
||||
octokit = ({
|
||||
request: mockRequest,
|
||||
}) as unknown as Octokit.Octokit;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -90,11 +85,17 @@ describe('databaseFetcher', function() {
|
||||
mockRequest.resolves(mockApiResponse);
|
||||
quickPickSpy.resolves('javascript');
|
||||
const githubRepo = 'github/codeql';
|
||||
const { databaseUrl, name, owner } = await mod.convertGithubNwoToDatabaseUrl(
|
||||
const result = await convertGithubNwoToDatabaseUrl(
|
||||
githubRepo,
|
||||
credentials,
|
||||
octokit,
|
||||
progressSpy
|
||||
);
|
||||
expect(result).not.to.be.undefined;
|
||||
if (result === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { databaseUrl, name, owner } = result;
|
||||
|
||||
expect(databaseUrl).to.equal(
|
||||
'https://api.github.com/repos/github/codeql/code-scanning/codeql/databases/javascript'
|
||||
@@ -119,7 +120,7 @@ describe('databaseFetcher', function() {
|
||||
mockRequest.resolves(mockApiResponse);
|
||||
const githubRepo = 'foo/bar-not-real';
|
||||
await expect(
|
||||
mod.convertGithubNwoToDatabaseUrl(githubRepo, credentials, progressSpy)
|
||||
convertGithubNwoToDatabaseUrl(githubRepo, octokit, progressSpy)
|
||||
).to.be.rejectedWith(/Unable to get database/);
|
||||
expect(progressSpy).to.have.callCount(0);
|
||||
});
|
||||
@@ -133,19 +134,10 @@ describe('databaseFetcher', function() {
|
||||
mockRequest.resolves(mockApiResponse);
|
||||
const githubRepo = 'foo/bar-with-no-dbs';
|
||||
await expect(
|
||||
mod.convertGithubNwoToDatabaseUrl(githubRepo, credentials, progressSpy)
|
||||
convertGithubNwoToDatabaseUrl(githubRepo, octokit, progressSpy)
|
||||
).to.be.rejectedWith(/Unable to get database/);
|
||||
expect(progressSpy).to.have.been.calledOnce;
|
||||
});
|
||||
|
||||
function getMockCredentials(response: any) {
|
||||
mockRequest = sinon.stub().resolves(response);
|
||||
return {
|
||||
getOctokit: () => ({
|
||||
request: mockRequest,
|
||||
}),
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
describe('convertLgtmUrlToDatabaseUrl', () => {
|
||||
|
||||
Reference in New Issue
Block a user