Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
7248fb0
add awaits for authn/ccloudProvider.ts
shouples Oct 3, 2025
95b84f1
add void operator for notification
shouples Oct 3, 2025
88ff4e3
void logError
shouples Oct 3, 2025
c7c9b1a
void logError calls
shouples Oct 3, 2025
a5ea615
void notification calls, await view refreshes
shouples Oct 3, 2025
afb40d7
void notifications
shouples Oct 3, 2025
284c318
void logError and notification
shouples Oct 3, 2025
b4f16ac
void logError
shouples Oct 3, 2025
664c870
void logError and notifications
shouples Oct 3, 2025
a688414
void notifications and logError
shouples Oct 3, 2025
f0cf193
fix promise map; void notifications and logError calls
shouples Oct 3, 2025
c56f456
void logError and notifications
shouples Oct 3, 2025
ec3db79
void logError calls
shouples Oct 3, 2025
56e0b57
void logError and notification
shouples Oct 3, 2025
1104d6a
void logError
shouples Oct 3, 2025
e087ac9
void notification
shouples Oct 3, 2025
bc6bbbe
void notifications
shouples Oct 3, 2025
a542834
await assert.rejects
shouples Oct 3, 2025
c482a6f
void notifications and Sentry client closing
shouples Oct 3, 2025
adab236
await view resets
shouples Oct 3, 2025
bec22bb
await view refresh
shouples Oct 3, 2025
1ab8cd4
await LD client identify call
shouples Oct 3, 2025
b1dcaf3
await setting context value
shouples Oct 3, 2025
343d808
void logError and notification
shouples Oct 3, 2025
2677c07
await getting LD client
shouples Oct 3, 2025
9349731
void logError and closing client
shouples Oct 3, 2025
6f82447
void notification
shouples Oct 3, 2025
a566c59
void logError
shouples Oct 3, 2025
9d1ac00
void logError
shouples Oct 3, 2025
e5aea2e
await onDidChangeActiveTextEditorHandler
shouples Oct 3, 2025
680ad11
void logError calls
shouples Oct 3, 2025
27ae87d
await toggling column and setting view mode
shouples Oct 3, 2025
b4a9844
void logError and notification
shouples Oct 3, 2025
f0f0e34
void logError; await setTrace
shouples Oct 3, 2025
79a8577
await test disposal
shouples Oct 3, 2025
6426765
void logError and notifications
shouples Oct 3, 2025
4f920f1
await loader reset in test
shouples Oct 3, 2025
4b18d79
await assert.rejects
shouples Oct 3, 2025
bf77e83
void logError
shouples Oct 3, 2025
d0bcae6
void logError
shouples Oct 3, 2025
fd392d4
void notification
shouples Oct 3, 2025
03c1b02
void notifications
shouples Oct 3, 2025
bf29f4f
void logError and notifications
shouples Oct 3, 2025
6a32a6b
await acquire in test
shouples Oct 3, 2025
247eeff
await validateDocument
shouples Oct 3, 2025
ab385ff
await hasCCloudAuthSession context value setting in tests
shouples Oct 3, 2025
ae41d29
void logError
shouples Oct 3, 2025
ee1f1ae
await handleConnectionUpdateEvent and announceConnectionState in tests
shouples Oct 3, 2025
514e893
void notifications
shouples Oct 3, 2025
98fcdd7
void logError; await getHandle
shouples Oct 3, 2025
a4fdeeb
void logError
shouples Oct 3, 2025
1705699
void logError
shouples Oct 3, 2025
7d9ff25
void event flush
shouples Oct 3, 2025
835535b
await assert.rejects
shouples Oct 3, 2025
7797a74
await button-clicking in test
shouples Oct 3, 2025
4454f5a
await assert.rejects
shouples Oct 3, 2025
3a95dce
void logError
shouples Oct 3, 2025
49896c4
void logError
shouples Oct 3, 2025
44897ce
await environmentChangedHandler in tests
shouples Oct 3, 2025
a004fd6
void logError
shouples Oct 3, 2025
e07e21d
await topicSearchSetHandler and ccloudConnectedHandler in tests
shouples Oct 3, 2025
9b7f22e
await submitSearch
shouples Oct 3, 2025
4578b27
await auto-await/-retry
shouples Oct 3, 2025
7faf124
set no-floating-promises to warn
shouples Oct 3, 2025
0a520d1
logError switcheroo: make exported function synchronous and log any e…
shouples Oct 3, 2025
fb4fc5c
revert all the `void logError`ing
shouples Oct 3, 2025
05d8770
no need to export inner async _logError that nobody should call
shouples Oct 3, 2025
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 eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export default [
"@typescript-eslint/no-explicit-any": "off",
// replacement of ESLint's no-redeclare with support for function overload
"@typescript-eslint/no-redeclare": "error",
// require awaiting or .then() chaining for promises
"@typescript-eslint/no-floating-promises": "warn",
// ignore line endings between Windows and Unix
"prettier/prettier": ["error", { endOfLine: "auto" }],
},
Expand All @@ -50,6 +52,10 @@ export default [
...globals.browser,
...globals.node,
},
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
{
Expand Down
10 changes: 7 additions & 3 deletions src/authn/ccloudProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,11 @@ export class ConfluentCloudAuthProvider
userInfo,
session: undefined,
});
(await getLaunchDarklyClient())?.identify({ key: userInfo.id });

const launchDarklyClient = await getLaunchDarklyClient();
if (launchDarklyClient) {
await launchDarklyClient.identify({ key: userInfo.id });
}

void vscode.window.showInformationMessage(
`Successfully signed in to Confluent Cloud as ${ccloudStatus.user?.username}`,
Expand Down Expand Up @@ -603,7 +607,7 @@ export class ConfluentCloudAuthProvider
// if we had a session before, we need to remove it, as well as inform the Accounts action to
// show the sign-in badge again
if (this._session) {
this.handleSessionRemoved();
await this.handleSessionRemoved();
} else {
logger.debug(
"No auth session, and no cached _session (for this extension instance) found to remove; not taking any action",
Expand All @@ -613,7 +617,7 @@ export class ConfluentCloudAuthProvider
// SCENARIO 2: user signed in / auth session was added
// add a new auth session to the Accounts action and populate this instance's cached session
// state
this.handleSessionCreated(session);
await this.handleSessionCreated(session);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/authz/schemaRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export function showNoSchemaAccessWarningNotification(): void {
return;
}

showWarningNotificationWithButtons(
void showWarningNotificationWithButtons(
"You do not have permission to access schema(s) for this topic. Messages will still appear, but may not be deserializeable.",
{ "Don't Show Again": async () => await SCHEMA_RBAC_WARNINGS_ENABLED.update(false, true) },
);
Expand Down
8 changes: 4 additions & 4 deletions src/commands/connections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export async function createNewDirectConnectionCommand() {
// use it to open the Direct Connection form (form will populate the fields with spec values)
openDirectConnectionForm(newSpec);
} catch (error) {
showErrorNotificationWithButtons("Error parsing spec file. See logs for details.");
void showErrorNotificationWithButtons("Error parsing spec file. See logs for details.");
logger.error(`Error parsing spec file: ${error}`);
return;
}
Expand Down Expand Up @@ -209,7 +209,7 @@ export async function editDirectConnectionCommand(item: ConnectionId | DirectEnv
logger.error("Direct connection not found, can't edit");
// possibly stale Resources view? this shouldn't happen
window.showErrorMessage("Connection not found.");
ResourceViewProvider.getInstance().refresh();
await ResourceViewProvider.getInstance().refresh();
return;
}

Expand All @@ -230,7 +230,7 @@ export async function exportDirectConnectionCommand(item: DirectEnvironment | Di
if (!spec) {
logger.error("Direct connection not found, can't share");
window.showErrorMessage("Connection not found.");
ResourceViewProvider.getInstance().refresh();
await ResourceViewProvider.getInstance().refresh();
return;
}

Expand Down Expand Up @@ -280,7 +280,7 @@ export async function exportDirectConnectionCommand(item: DirectEnvironment | Di
});
} catch (err) {
logger.error(`Failed to save file: ${err}`);
showErrorNotificationWithButtons("Unable to save connection spec file.");
void showErrorNotificationWithButtons("Unable to save connection spec file.");
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/commands/docker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export async function runWorkflowWithProgress(
} else {
errorMsg = error.message;
}
showErrorNotificationWithButtons(
void showErrorNotificationWithButtons(
`Error ${start ? "starting" : "stopping"} ${workflow.resourceKind}: ${errorMsg}`,
);
}
Expand Down
4 changes: 2 additions & 2 deletions src/commands/flinkArtifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,15 @@ export async function uploadArtifactCommand(
errorMessage = `${errorMessage} ${err.message}`;
}
logError(err, errorMessage);
showErrorNotificationWithButtons(errorMessage);
void showErrorNotificationWithButtons(errorMessage);
}
}

export async function deleteArtifactCommand(
selectedArtifact: FlinkArtifact | undefined,
): Promise<void> {
if (!selectedArtifact) {
showErrorNotificationWithButtons("No Flink artifact selected for deletion.");
void showErrorNotificationWithButtons("No Flink artifact selected for deletion.");
return;
}
const request: DeleteArtifactV1FlinkArtifactRequest = {
Expand Down
6 changes: 3 additions & 3 deletions src/commands/flinkUDFs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export async function deleteFlinkUDFCommand(selectedUdf: FlinkUdf): Promise<void
},
);

showInfoNotificationWithButtons(
void showInfoNotificationWithButtons(
`UDF "${selectedUdf.name}" deleted successfully from Confluent Cloud.`,
);
} catch (err) {
Expand All @@ -99,7 +99,7 @@ export async function deleteFlinkUDFCommand(selectedUdf: FlinkUdf): Promise<void
}
}
logError(err, errorMessage);
showErrorNotificationWithButtons(errorMessage);
void showErrorNotificationWithButtons(errorMessage);
}
}

Expand Down Expand Up @@ -204,7 +204,7 @@ export async function startGuidedUdfCreationCommand(selectedArtifact: FlinkArtif
errorMessage = `${errorMessage}: ${err.message}`;
logError(err, errorMessage);
}
showErrorNotificationWithButtons(errorMessage);
void showErrorNotificationWithButtons(errorMessage);
}
}
}
6 changes: 3 additions & 3 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export function createWrappedCommand(
// notification to the user
const disabledMessage: string | undefined = await checkForExtensionDisabledReason();
if (disabledMessage) {
showExtensionDisabledNotification(disabledMessage);
void showExtensionDisabledNotification(disabledMessage);
return;
}

Expand All @@ -55,9 +55,9 @@ export function createWrappedCommand(
if (e instanceof Error) {
// gather more (possibly-ResponseError) context and send to Sentry (only enabled in
// production builds)
logError(e, `${commandName}`, { extra: { command: commandName } });
logError(e, commandName, { extra: { command: commandName } });
// also show error notification to the user with default buttons
showErrorNotificationWithButtons(`Error invoking command "${commandName}": ${e}`);
void showErrorNotificationWithButtons(`Error invoking command "${commandName}": ${e}`);
}
}
};
Expand Down
16 changes: 7 additions & 9 deletions src/commands/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,7 @@ export async function openLatestSchemasCommand(topic: KafkaTopic) {
title: message,
},
async () => {
const promises = highestVersionedSchemas.map((schema) => {
openReadOnlySchemaDocument(schema);
});
Comment on lines -182 to -184
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This one was a little strange, until I realized we had no return within the {} block so there were no promises actually being awaited in the Promise.all below

const promises = highestVersionedSchemas.map((schema) => openReadOnlySchemaDocument(schema));
await Promise.all(promises);
},
);
Expand Down Expand Up @@ -263,7 +261,7 @@ export async function deleteSchemaVersionCommand(schema: Schema) {
const found = schemaGroup && schemaGroup.find((s) => s.id === schema.id) !== undefined;

if (!found) {
showErrorNotificationWithButtons("Schema not found in registry.", {
void showErrorNotificationWithButtons("Schema not found in registry.", {
"Refresh Schemas": () => vscode.commands.executeCommand("confluent.schemas.refresh"),
...DEFAULT_ERROR_NOTIFICATION_BUTTONS,
});
Expand All @@ -285,7 +283,7 @@ export async function deleteSchemaVersionCommand(schema: Schema) {
}
}

showErrorNotificationWithButtons("Schema not found in registry.", {
void showErrorNotificationWithButtons("Schema not found in registry.", {
"Refresh Schemas": () => vscode.commands.executeCommand("confluent.schemas.refresh"),
...DEFAULT_ERROR_NOTIFICATION_BUTTONS,
});
Expand Down Expand Up @@ -358,7 +356,7 @@ export async function deleteSchemaVersionCommand(schema: Schema) {
} catch (e) {
success = false;
logError(e, "Error deleting schema version", { extra: { error: {} } });
showErrorNotificationWithButtons(
void showErrorNotificationWithButtons(
`Error deleting schema version ${schema.version}: ${e instanceof Error ? e.message : String(e)}`,
);
}
Expand Down Expand Up @@ -396,7 +394,7 @@ export async function deleteSchemaSubjectCommand(subject: Subject) {
schemaGroup = await loader.getSchemasForSubject(subject.environmentId, subject.name);

if (!Array.isArray(schemaGroup) || schemaGroup.length === 0) {
showErrorNotificationWithButtons("Schema subject not found in registry.", {
void showErrorNotificationWithButtons("Schema subject not found in registry.", {
"Refresh Schemas": () => vscode.commands.executeCommand("confluent.schemas.refresh"),
...DEFAULT_ERROR_NOTIFICATION_BUTTONS,
});
Expand All @@ -414,7 +412,7 @@ export async function deleteSchemaSubjectCommand(subject: Subject) {
});
}
}
showErrorNotificationWithButtons("Schema subject not found in registry.", {
void showErrorNotificationWithButtons("Schema subject not found in registry.", {
"Refresh Schemas": () => vscode.commands.executeCommand("confluent.schemas.refresh"),
...DEFAULT_ERROR_NOTIFICATION_BUTTONS,
});
Expand Down Expand Up @@ -480,7 +478,7 @@ export async function deleteSchemaSubjectCommand(subject: Subject) {
} catch (e) {
success = false;
logError(e, "Error deleting schema subject", { extra: { error: {} } });
showErrorNotificationWithButtons(
void showErrorNotificationWithButtons(
`Error deleting schema subject ${subject.name}: ${e instanceof Error ? e.message : String(e)}`,
);
} finally {
Expand Down
8 changes: 5 additions & 3 deletions src/commands/topics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,9 @@ async function editTopicConfig(topic: KafkaTopic): Promise<void> {
const errorBody = await err.response.json();
formError = errorBody.message;
} else {
logError(err, "update topic config", { extra: { functionName: "validateOrUpdateConfig" } });
logError(err, "update topic config", {
extra: { functionName: "validateOrUpdateConfig" },
});
if (err instanceof Error && err.message) formError = err.message;
}
return { success: false, message: formError };
Expand Down Expand Up @@ -266,7 +268,7 @@ export async function produceMessagesFromDocument(topic: KafkaTopic) {
uriScheme: messageUri.scheme,
problemCount: diagnostics.length,
});
showErrorNotificationWithButtons(
void showErrorNotificationWithButtons(
"Unable to produce message(s): JSON schema validation failed.",
{
"Show Validation Errors": () => {
Expand Down Expand Up @@ -479,7 +481,7 @@ async function produceMessages(

// if we only have validation errors, no summary will be shown, but we should provide the
// "Show Validation Errors" button
showErrorNotificationWithButtons(
void showErrorNotificationWithButtons(
`Failed to produce ${errorResults.length.toLocaleString()}${ofTotal} message${plural} to topic "${topic.name}"${errorSummary ? `:\n${errorSummary}` : ""}`,
buttons,
);
Expand Down
6 changes: 4 additions & 2 deletions src/consume.ts
Original file line number Diff line number Diff line change
Expand Up @@ -535,8 +535,10 @@ function messageViewerStartPollingCommand(
}
default: {
reportable = { message: "Something went wrong." };
logError(error, "message viewer", { extra: { status: status.toString(), payload } });
showErrorNotificationWithButtons("Error response while consuming messages.");
logError(error, "message viewer", {
extra: { status: status.toString(), payload },
});
void showErrorNotificationWithButtons("Error response while consuming messages.");
break;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/docker/workflows/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export abstract class LocalResourceWorkflow {
errorMsg = error.response.statusText;
}
}
showErrorNotificationWithButtons(
void showErrorNotificationWithButtons(
`Failed to start ${this.resourceKind} container "${container.name}": ${errorMsg}`,
);
return;
Expand Down
2 changes: 1 addition & 1 deletion src/docker/workflows/confluent-local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export class ConfluentLocalWorkflow extends LocalResourceWorkflow {
containerEnvs,
);
if (!container) {
showErrorNotificationWithButtons(
void showErrorNotificationWithButtons(
`Failed to create ${this.resourceKind} container "${brokerConfig.containerName}".`,
);
success = false;
Expand Down
2 changes: 1 addition & 1 deletion src/docker/workflows/cp-schema-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export class ConfluentPlatformSchemaRegistryWorkflow extends LocalResourceWorkfl
kafkaNetworks,
);
if (!container) {
showErrorNotificationWithButtons(`Failed to create ${this.resourceKind} container.`);
void showErrorNotificationWithButtons(`Failed to create ${this.resourceKind} container.`);
return;
}
this.sendTelemetryEvent(UserEvent.LocalDockerAction, {
Expand Down
2 changes: 1 addition & 1 deletion src/errors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ describe("errors.ts extractResponseBody()", () => {

it("should throw if the error is not a ResponseError", async () => {
const error = new Error("test");
assert.rejects(
await assert.rejects(
async () => {
await extractResponseBody(error as any);
},
Expand Down
12 changes: 11 additions & 1 deletion src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,17 @@ export class CustomError extends Error {
* @param message Text to add in the logger.error() message and top-level Sentry error message
* @param sentryContext Optional Sentry context to include with the error
* */
export async function logError(
export function logError(
e: unknown,
message: string,
sentryContext: Partial<ScopeContext> = {},
): void {
_logError(e, message, sentryContext).catch((err) => {
logger.error(`Failed to log error: ${err}`, { originalError: String(e) });
});
}

async function _logError(
e: unknown,
message: string,
sentryContext: Partial<ScopeContext> = {},
Expand Down
23 changes: 14 additions & 9 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,17 +219,19 @@ async function _activateExtension(
];
logger.info("View providers initialized");
// explicitly "reset" the Topics & Schemas views so no resources linger during reactivation/update
topicViewProvider.reset();
schemasViewProvider.reset();
Comment on lines -222 to -223
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jlrobins do you think we should expand this behavior to the rest of the views, or remove this entirely?

I don't know if this is even necessary anymore since we still wipe workspace state on activation, but the only area this might cause issues is during extension version updates where the Topics and Schemas views may reset in the middle of use (from one extension version to another). I don't think we've tested that path for the Flink-related views though.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, good question, but at least not needing answering here in for this branch.

I think that it'd be safer to include to do for all views (but not needed in this branch).

await Promise.all([topicViewProvider.reset(), schemasViewProvider.reset()]);

// Register refresh commands for our refreshable resource view providers.
const refreshCommands: vscode.Disposable[] = [];
for (const instance of getRefreshableViewProviders()) {
refreshCommands.push(
registerCommandWithLogging(`confluent.${instance.kind}.refresh`, (): boolean => {
instance.refresh(true);
return true;
}),
registerCommandWithLogging(
`confluent.${instance.kind}.refresh`,
async (): Promise<boolean> => {
await instance.refresh(true);
return true;
},
),
Comment on lines 226 to +234
Copy link
Contributor Author

Choose a reason for hiding this comment

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

View-level refreshing still working as expected ✅

);
}

Expand Down Expand Up @@ -486,7 +488,7 @@ async function setupFeatureFlags(): Promise<void> {

const disabledMessage: string | undefined = await checkForExtensionDisabledReason();
if (disabledMessage) {
showExtensionDisabledNotification(disabledMessage);
void showExtensionDisabledNotification(disabledMessage);
throw new Error(disabledMessage);
}
}
Expand Down Expand Up @@ -553,7 +555,10 @@ async function setupAuthProvider(): Promise<vscode.Disposable[]> {
userInfo: undefined,
session: cloudSession,
});
(await getLaunchDarklyClient())?.identify({ key: cloudSession.account.id });
const launchDarklyClient = await getLaunchDarklyClient();
if (launchDarklyClient) {
await launchDarklyClient.identify({ key: cloudSession.account.id });
}
}

logger.info("Confluent Cloud auth provider registered");
Expand Down Expand Up @@ -587,7 +592,7 @@ export function deactivate() {
const msg = "Error disposing telemetry logger during extension deactivation";
logError(new Error(msg, { cause: e }), msg, { extra: {} });
}
closeSentryClient();
void closeSentryClient();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not trying to await or catch errors during disposal, cc @noeldevelops


disposeLaunchDarklyClient();
disableCCloudStatusPolling();
Expand Down
2 changes: 1 addition & 1 deletion src/extensionSettings/listener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export function createConfigChangeListener(): Disposable {
// user toggled the "Enable Chat Participant" experimental setting
const enabled: boolean = ENABLE_CHAT_PARTICIPANT.value;
logger.debug(`"${ENABLE_CHAT_PARTICIPANT.id}" setting changed`, { enabled });
setContextValue(ContextValues.chatParticipantEnabled, enabled);
await setContextValue(ContextValues.chatParticipantEnabled, enabled);
// telemetry for how often users opt in or out of the chat participant feature
logUsage(UserEvent.ExtensionSettingsChange, {
settingId: ENABLE_CHAT_PARTICIPANT.id,
Expand Down
Loading