Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions extensions/ql-vscode/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@

## [UNRELEASED]

- Replace certain control codes (`U+0000` - `U+001F`) with their corresponding control labels (`U+2400` - `U+241F`) in the results view. [#963](https://github.com/github/vscode-codeql/pull/963)

## 1.5.6 - 07 October 2021

- Add progress messages to LGTM download option. This makes the two-step process (selecting a project, then selecting a language) more clear. [#960](https://github.com/github/vscode-codeql/pull/960)
- Remove line about selecting a language from the dropdown when downloading database from LGTM. This makes the download progress visible when the popup is not expanded. [#957](https://github.com/github/vscode-codeql/pull/957)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this should have been deleted.

- Fix a bug where copying the version information fails when a CodeQL CLI cannot be found. [#958](https://github.com/github/vscode-codeql/pull/958)
- Avoid a race condition when deleting databases that can cause occasional errors. [#959](https://github.com/github/vscode-codeql/pull/959)
- Update CodeQL logos. [#965](https://github.com/github/vscode-codeql/pull/965)
- Fixed a bug where copying the version information fails when a CodeQL CLI cannot be found. [#958](https://github.com/github/vscode-codeql/pull/958)
- Make project slug for GitHub repositories case-insensitive when adding a CodeQL database from LGTM. [#961](https://github.com/github/vscode-codeql/pull/961)

## 1.5.5 - 08 September 2021

Expand Down
2 changes: 1 addition & 1 deletion extensions/ql-vscode/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion extensions/ql-vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "CodeQL for Visual Studio Code",
"author": "GitHub",
"private": true,
"version": "1.5.6",
"version": "1.5.7",
"publisher": "GitHub",
"license": "MIT",
"icon": "media/VS-marketplace-CodeQL-icon.png",
Expand Down
56 changes: 44 additions & 12 deletions extensions/ql-vscode/src/databaseFetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,16 @@ export async function promptImportLgtmDatabase(
return;
}

export async function retrieveCanonicalRepoName(lgtmUrl: string) {
const givenRepoName = extractProjectSlug(lgtmUrl);
const response = await checkForFailingResponse(await fetch(`https://api.github.com/repos/${givenRepoName}`), 'Failed to locate the repository on github');
const repo = await response.json();
if (!repo || !repo.full_name) {
return;
}
return repo.full_name;
}

/**
* Imports a database from a local archive.
*
Expand Down Expand Up @@ -285,7 +295,7 @@ async function fetchAndUnzip(
step: 1,
});

const response = await checkForFailingResponse(await fetch(databaseUrl));
const response = await checkForFailingResponse(await fetch(databaseUrl), 'Error downloading database');
const archiveFileStream = fs.createWriteStream(archivePath);

const contentLength = response.headers.get('content-length');
Expand All @@ -304,7 +314,7 @@ async function fetchAndUnzip(
await fs.remove(archivePath);
}

async function checkForFailingResponse(response: Response): Promise<Response | never> {
async function checkForFailingResponse(response: Response, errorMessage: string): Promise<Response | never> {
if (response.ok) {
return response;
}
Expand All @@ -318,7 +328,7 @@ async function checkForFailingResponse(response: Response): Promise<Response | n
} catch (e) {
msg = text;
}
throw new Error(`Error downloading database.\n\nReason: ${msg}`);
throw new Error(`${errorMessage}.\n\nReason: ${msg}`);
}

function isFile(databaseUrl: string) {
Expand Down Expand Up @@ -408,24 +418,36 @@ function convertRawLgtmSlug(maybeSlug: string): string | undefined {
}
return;
}

function extractProjectSlug(lgtmUrl: string): string | undefined {
// Only matches the '/g/' provider (github)
const re = new RegExp('https://lgtm.com/projects/g/(.*[^/])');
const match = lgtmUrl.match(re);
if (!match) {
return;
}
return match[1];
}

// exported for testing
export async function convertToDatabaseUrl(
lgtmUrl: string,
progress: ProgressCallback) {
try {
lgtmUrl = convertRawLgtmSlug(lgtmUrl) || lgtmUrl;

const uri = Uri.parse(lgtmUrl, true);
const paths = ['api', 'v1.0'].concat(
uri.path.split('/').filter((segment) => segment)
).slice(0, 6);
const projectUrl = `https://lgtm.com/${paths.join('/')}`;
const projectResponse = await fetch(projectUrl);
const projectJson = await projectResponse.json();
let projectJson = await downloadLgtmProjectMetadata(lgtmUrl);

if (projectJson.code === 404) {
throw new Error();
// fallback check for github repos with same name but different case
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also mention that this will fail for all non-github providers.

let canonicalName = await retrieveCanonicalRepoName(lgtmUrl);
if (!canonicalName) {
throw new Error('Repository not found.');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Include the lgtmUrl in the error message.

}
canonicalName = convertRawLgtmSlug(`g/${canonicalName}`);
projectJson = await downloadLgtmProjectMetadata(canonicalName);
if (projectJson.code === 404) {
throw new Error('Failed to download project from LGTM.');
}
}

const language = await promptForLanguage(projectJson, progress);
Expand All @@ -445,6 +467,16 @@ export async function convertToDatabaseUrl(
}
}

async function downloadLgtmProjectMetadata(lgtmUrl: string): Promise<any> {
const uri = Uri.parse(lgtmUrl, true);
const paths = ['api', 'v1.0'].concat(
uri.path.split('/').filter((segment) => segment)
).slice(0, 6);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why 0, 6? Could you add a comment to explain?

const projectUrl = `https://lgtm.com/${paths.join('/')}`;
const projectResponse = await fetch(projectUrl);
return projectResponse.json();
}

async function promptForLanguage(
projectJson: any,
progress: ProgressCallback
Expand Down
12 changes: 6 additions & 6 deletions extensions/ql-vscode/src/view/RawTableValue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ interface Props {
}

export default function RawTableValue(props: Props): JSX.Element {
const v = props.value;
const rawValue = props.value;
if (
typeof v === 'string'
|| typeof v === 'number'
|| typeof v === 'boolean'
typeof rawValue === 'string'
|| typeof rawValue === 'number'
|| typeof rawValue === 'boolean'
) {
return <span>{v.toString()}</span>;
return <span>{renderLocation(undefined, rawValue.toString())}</span>;
}

return renderLocation(v.url, v.label, props.databaseUri);
return renderLocation(rawValue.url, rawValue.label, props.databaseUri);
}
43 changes: 32 additions & 11 deletions extensions/ql-vscode/src/view/result-table-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ export const oddRowClassName = 'vscode-codeql__result-table-row--odd';
export const pathRowClassName = 'vscode-codeql__result-table-row--path';
export const selectedRowClassName = 'vscode-codeql__result-table-row--selected';

const CONTROL_CODE = '\u001F'.codePointAt(0)!;
const CONTROL_LABEL = '\u2400'.codePointAt(0)!;

export function jumpToLocationHandler(
loc: ResolvableLocationValue,
databaseUri: string,
Expand Down Expand Up @@ -67,24 +70,42 @@ export function openFile(filePath: string): void {
});
}

function convertedNonprintableChars(label: string) {
// If the label was empty, use a placeholder instead, so the link is still clickable.
if (!label) {
return '[empty string]';
} else if (label.match(/^\s+$/)) {
return `[whitespace: "${label}"]`;
} else {
/**
* If the label contains certain non-printable characters, loop through each
* character and replace it with the cooresponding unicode control label.
*/
const convertedLabelArray: any[] = [];
for (let i = 0; i < label.length; i++) {
const labelCheck = label.codePointAt(i)!;
if (labelCheck <= CONTROL_CODE) {
convertedLabelArray[i] = String.fromCodePoint(labelCheck + CONTROL_LABEL);
} else {
convertedLabelArray[i] = label.charAt(i);
}
}
return convertedLabelArray.join('');
}
}

/**
* Render a location as a link which when clicked displays the original location.
*/
export function renderLocation(
loc: UrlValue | undefined,
label: string | undefined,
databaseUri: string,
loc?: UrlValue,
label?: string,
databaseUri?: string,
title?: string,
callback?: () => void
): JSX.Element {

// If the label was empty, use a placeholder instead, so the link is still clickable.
let displayLabel = label;
if (!label) {
displayLabel = '[empty string]';
} else if (label.match(/^\s+$/)) {
displayLabel = `[whitespace: "${label}"]`;
}
const displayLabel = convertedNonprintableChars(label!);

if (loc === undefined) {
return <span>{displayLabel}</span>;
Expand All @@ -93,7 +114,7 @@ export function renderLocation(
}

const resolvableLoc = tryGetResolvableLocation(loc);
if (resolvableLoc !== undefined) {
if (databaseUri !== undefined && resolvableLoc !== undefined) {
return (
<a href="#"
className="vscode-codeql__result-table-location-link"
Expand Down