Skip to content

Commit

Permalink
Merge branch 'main' of github.com:ansible/vscode-ansible into fix/wel…
Browse files Browse the repository at this point in the history
…comePageTitle
  • Loading branch information
audgirka committed Oct 4, 2024
2 parents 893e990 + 5fc2955 commit 5b3cff6
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 40 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ jobs:
path: .

- name: Upload als test coverage data [1/4]
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v4.5.0
with:
name: als
files: ./*/coverage/als/lcov.info
Expand All @@ -360,7 +360,7 @@ jobs:
use_oidc: true # cspell:ignore oidc

- name: Upload unit test coverage data [2/4]
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v4.5.0
with:
name: unit
files: ./*/coverage/unit/lcov.info
Expand All @@ -370,7 +370,7 @@ jobs:
use_oidc: true # cspell:ignore oidc

- name: Upload ui test coverage data [3/4]
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v4.5.0
with:
name: unit
files: ./*/coverage/ui/lcov.info
Expand All @@ -380,7 +380,7 @@ jobs:
use_oidc: true # cspell:ignore oidc

- name: Upload e2e test coverage data [4/4]
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v4.5.0
with:
name: e2e
files: ./*/coverage/e2e/lcov.info
Expand Down
57 changes: 40 additions & 17 deletions src/features/lightspeed/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,29 +83,52 @@ class Errors {
? responseErrorData.message
: "unknown";
}

let detail: string = "";
if (typeof responseErrorData.message == "string") {
detail = responseErrorData.message ?? "";
} else if (Array.isArray(responseErrorData.message)) {
const messages = responseErrorData.message as [];
messages.forEach((value: string, index: number) => {
detail =
detail +
"(" +
(index + 1) +
") " +
value +
(index < messages.length - 1 ? " " : "");
});
}
const items = (err?.response?.data as Record<string, unknown>) ?? {};
const detail = Object.hasOwn(items, "detail")
? items["detail"]
: undefined;

// Clone the Error to preserve the original definition
return new Error(e.code, message, detail, e.check);
return new Error(
e.code,
message,
this.prettyPrintDetail(detail),
e.check,
);
}

return undefined;
}

public prettyPrintDetail(detail: unknown): string | undefined {
let pretty: string = "";
if (detail === undefined) {
return undefined;
} else if (typeof detail == "string") {
pretty = detail ?? "";
} else if (Array.isArray(detail)) {
const items = detail as [];
items.forEach((value: string, index: number) => {
pretty =
pretty +
"(" +
(index + 1) +
") " +
value +
(index < items.length - 1 ? " " : "");
});
} else if (detail instanceof Object && detail.constructor === Object) {
const items = detail as Record<string, unknown>;
const keys: string[] = Object.keys(detail);
keys.forEach((key, index) => {
pretty =
pretty +
`${key}: ${items[key]}` +
(index < keys.length - 1 ? " " : "");
});
}
return pretty;
}
}

export const ERRORS = new Errors();
Expand Down
23 changes: 14 additions & 9 deletions src/features/lightspeed/handleApiError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,38 @@ export function mapError(err: AxiosError): IError {
}

// If the error is unknown fallback to defaults
const detail = err.response?.data;
const items = (err?.response?.data as Record<string, unknown>) ?? {};
const detail = Object.hasOwn(items, "detail") ? items["detail"] : undefined;
const status: number | string = err?.response?.status ?? err?.code ?? 500;
if (err instanceof CanceledError) {
return ERRORS_CONNECTION_CANCELED_TIMEOUT;
}
if (status === 400) {
return ERRORS_BAD_REQUEST.withDetail(detail);
return ERRORS_BAD_REQUEST.withDetail(ERRORS.prettyPrintDetail(detail));
}
if (status === 401) {
return ERRORS_UNAUTHORIZED.withDetail(detail);
return ERRORS_UNAUTHORIZED.withDetail(ERRORS.prettyPrintDetail(detail));
}
if (status === 403) {
return ERRORS_UNAUTHORIZED.withDetail(detail);
return ERRORS_UNAUTHORIZED.withDetail(ERRORS.prettyPrintDetail(detail));
}
if (status === 404) {
return ERRORS_NOT_FOUND.withDetail(detail);
return ERRORS_NOT_FOUND.withDetail(ERRORS.prettyPrintDetail(detail));
}
if (status === 429) {
return ERRORS_TOO_MANY_REQUESTS.withDetail(detail);
return ERRORS_TOO_MANY_REQUESTS.withDetail(
ERRORS.prettyPrintDetail(detail),
);
}
if (status === 500) {
return ERRORS_UNKNOWN.withDetail(detail);
return ERRORS_UNKNOWN.withDetail(ERRORS.prettyPrintDetail(detail));
}
if (status === AxiosError.ECONNABORTED) {
return ERRORS_CONNECTION_TIMEOUT.withDetail(detail);
return ERRORS_CONNECTION_TIMEOUT.withDetail(
ERRORS.prettyPrintDetail(detail),
);
}

console.log(`Lightspeed request failed with unknown error ${err}`);
return ERRORS_UNKNOWN.withDetail(detail);
return ERRORS_UNKNOWN.withDetail(ERRORS.prettyPrintDetail(detail));
}
11 changes: 7 additions & 4 deletions src/features/lightspeed/playbookExplanation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,18 @@ export const playbookExplanation = async (extensionUri: vscode.Uri) => {
console.log(response);
if (isError(response)) {
const oneClickTrialProvider = getOneClickTrialProvider();
const my_error = response as IError;
if (!(await oneClickTrialProvider.showPopup(my_error))) {
vscode.window.showErrorMessage(my_error.message ?? UNKNOWN_ERROR);
if (!(await oneClickTrialProvider.showPopup(response))) {
const errorMessage: string = `${response.message ?? UNKNOWN_ERROR} ${response.detail ?? ""}`;
vscode.window.showErrorMessage(errorMessage);
currentPanel.setContent(
`<p><span class="codicon codicon-error"></span>The operation has failed:<p>${my_error.message}</p></p>`,
`<p><span class="codicon codicon-error"></span>The operation has failed:<p>${errorMessage}</p></p>`,
);
}
} else {
markdown = response.content;
if (markdown.length === 0) {
markdown = "### No explanation provided.";
}
const html_snippet = marked.parse(markdown) as string;
currentPanel.setContent(html_snippet, true);
}
Expand Down
8 changes: 4 additions & 4 deletions src/features/lightspeed/playbookGeneration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,8 @@ export async function showPlaybookGenerationPage(
if (isError(response)) {
const oneClickTrialProvider = getOneClickTrialProvider();
if (!(await oneClickTrialProvider.showPopup(response))) {
vscode.window.showErrorMessage(
response.message ?? UNKNOWN_ERROR,
);
const errorMessage: string = `${response.message ?? UNKNOWN_ERROR} ${response.detail ?? ""}`;
vscode.window.showErrorMessage(errorMessage);
}
} else {
panel.webview.postMessage({
Expand Down Expand Up @@ -198,7 +197,8 @@ export async function showPlaybookGenerationPage(
panel,
);
if (isError(response)) {
vscode.window.showErrorMessage(response.message ?? UNKNOWN_ERROR);
const errorMessage: string = `${response.message ?? UNKNOWN_ERROR} ${response.detail ?? ""}`;
vscode.window.showErrorMessage(errorMessage);
break;
}
playbook = response.playbook;
Expand Down
2 changes: 2 additions & 0 deletions src/interfaces/extensionSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,6 @@ export interface LightSpeedServiceSettings {
URL: string;
suggestions: { enabled: boolean; waitWindow: number };
model: string | undefined;
playbookGenerationCustomPrompt: string | undefined;
playbookExplanationCustomPrompt: string | undefined;
}
8 changes: 8 additions & 0 deletions src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ export class SettingsManager {
waitWindow: lightSpeedSettings.get("suggestions.waitWindow", 0),
},
model: lightSpeedSettings.get("modelIdOverride", undefined),
playbookGenerationCustomPrompt: lightSpeedSettings.get(
"playbookGenerationCustomPrompt",
undefined,
),
playbookExplanationCustomPrompt: lightSpeedSettings.get(
"playbookExplanationCustomPrompt",
undefined,
),
},
playbook: {
arguments: playbookSettings.get("arguments", ""),
Expand Down
1 change: 1 addition & 0 deletions src/webview/apps/lightspeed/playbookGeneration/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ window.addEventListener("message", async (event) => {
}
case "outline": {
setupPage(2);

outline.update(message.outline.outline);
savedPlaybook = message.outline.playbook;
generationId = message.outline.generationId;
Expand Down
10 changes: 10 additions & 0 deletions test/mockLightspeedServer/explanations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ export function explanations(
});
}

// Special case to replicate explanation being unavailable
if (playbook !== undefined && playbook.includes("No explanation available")) {
logger.info("Returning empty content. Explanation is not available");
return res.send({
content: "",
format,
explanationId,
});
}

// cSpell: disable
const content = `
## Playbook Overview and Structure
Expand Down
5 changes: 5 additions & 0 deletions test/testFixtures/lightspeed/playbook_explanation_none.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
- name:
hosts: all
tasks:
- name: No explanation available...
43 changes: 43 additions & 0 deletions test/ui-test/lightspeedUiTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,7 @@ export function lightspeedUIAssetsTest(): void {
expect(group, "Group 1 of the editor view should be undefined").to.be
.undefined;

await webView.switchBack();
await workbench.executeCommand("View: Close All Editor Groups");
} else {
this.skip();
Expand Down Expand Up @@ -745,6 +746,48 @@ export function lightspeedUIAssetsTest(): void {
}
});

it("Playbook explanation webview works as expected, no explanation", async function () {
if (process.env.TEST_LIGHTSPEED_URL) {
const folder = "lightspeed";
const file = "playbook_explanation_none.yml";
const filePath = getFixturePath(folder, file);

// Open file in the editor
await VSBrowser.instance.openResources(filePath);

// Open playbook explanation webview.
await workbench.executeCommand(
"Explain the playbook with Ansible Lightspeed",
);
await sleep(2000);

// Locate the playbook explanation webview
const webView = (await new EditorView().openEditor(
"Explanation",
1,
)) as WebView;
expect(webView, "webView should not be undefined").not.to.be.undefined;
await webView.switchToFrame(5000);
expect(
webView,
"webView should not be undefined after switching to its frame",
).not.to.be.undefined;

// Find the main div element of the webview and verify the expected text is found.
const mainDiv = await webView.findWebElement(
By.xpath("//div[contains(@class, 'playbookGeneration') ]"),
);
expect(mainDiv, "mainDiv should not be undefined").not.to.be.undefined;
const text = await mainDiv.getText();
expect(text.includes("No explanation provided")).to.be.true;

await webView.switchBack();
await workbench.executeCommand("View: Close All Editor Groups");
} else {
this.skip();
}
});

after(async function () {
if (process.env.TEST_LIGHTSPEED_URL) {
settingsEditor = await workbench.openSettings();
Expand Down
Loading

0 comments on commit 5b3cff6

Please sign in to comment.