From e69246771e8861fcb1b49d27a978863391d21abe Mon Sep 17 00:00:00 2001 From: Maxim Hayes Date: Fri, 3 Jan 2025 13:39:20 -0600 Subject: [PATCH 1/2] revert: amazon q standalone special handling Removes code that should no longer be necessary anymore. - Remove autoinstall Amazon Q if you were a CodeWhisperer user on 2.x versions of toolkit - The prompt to install Amazon Q will still appear, if you don't have it. It has been slightly reworded. - If Amazon Q is installed, then you uninstall, it you will not see the prompt again in toolkit (previously you could). - Remove settings migrations from codewhisperer settings - Remove amazon Q telemetry enabled setting being initialized by the value from toolkit. We are still getting hits in telemetry for people getting auto install (172 in last 2 months). However, they are mostly on old versions. Let's simplyify our codebase by removing support for these dated codepaths. --- ...-aa696d15-306f-4af5-aa4b-ab48c44f0a5e.json | 4 + .../src/amazonq/explorer/amazonQTreeNode.ts | 7 +- packages/core/src/codewhisperer/activation.ts | 3 - .../core/src/codewhisperer/util/authUtil.ts | 24 ------ .../util/codewhispererSettings.ts | 18 +---- packages/core/src/extensionNode.ts | 75 +++++++++---------- .../core/src/shared/telemetry/activation.ts | 1 - packages/core/src/shared/telemetry/util.ts | 12 +-- ...-1c5617ae-50c9-4de1-a191-a2d57dce5bd7.json | 4 + 9 files changed, 47 insertions(+), 101 deletions(-) create mode 100644 packages/amazonq/.changes/next-release/Removal-aa696d15-306f-4af5-aa4b-ab48c44f0a5e.json create mode 100644 packages/toolkit/.changes/next-release/Removal-1c5617ae-50c9-4de1-a191-a2d57dce5bd7.json diff --git a/packages/amazonq/.changes/next-release/Removal-aa696d15-306f-4af5-aa4b-ab48c44f0a5e.json b/packages/amazonq/.changes/next-release/Removal-aa696d15-306f-4af5-aa4b-ab48c44f0a5e.json new file mode 100644 index 00000000000..720817d707a --- /dev/null +++ b/packages/amazonq/.changes/next-release/Removal-aa696d15-306f-4af5-aa4b-ab48c44f0a5e.json @@ -0,0 +1,4 @@ +{ + "type": "Removal", + "description": "Settings: No longer migrate old CodeWhisperer settings or initialize telemetry setting from AWS Toolkit." +} diff --git a/packages/core/src/amazonq/explorer/amazonQTreeNode.ts b/packages/core/src/amazonq/explorer/amazonQTreeNode.ts index 4ea7970e84b..bbfd1bc1ff2 100644 --- a/packages/core/src/amazonq/explorer/amazonQTreeNode.ts +++ b/packages/core/src/amazonq/explorer/amazonQTreeNode.ts @@ -5,7 +5,7 @@ import * as vscode from 'vscode' import { ResourceTreeDataProvider, TreeNode } from '../../shared/treeview/resourceTreeDataProvider' -import { AuthState, isPreviousQUser } from '../../codewhisperer/util/authUtil' +import { AuthState } from '../../codewhisperer/util/authUtil' import { createLearnMoreNode, createInstallQNode, createDismissNode } from './amazonQChildrenNodes' import { Commands } from '../../shared/vscode/commands2' @@ -40,10 +40,7 @@ export class AmazonQNode implements TreeNode { } public getChildren() { - const children = [createInstallQNode(), createLearnMoreNode()] - if (!isPreviousQUser()) { - children.push(createDismissNode()) - } + const children = [createInstallQNode(), createLearnMoreNode(), createDismissNode()] return children } diff --git a/packages/core/src/codewhisperer/activation.ts b/packages/core/src/codewhisperer/activation.ts index 474d8d68121..4ea655fc4da 100644 --- a/packages/core/src/codewhisperer/activation.ts +++ b/packages/core/src/codewhisperer/activation.ts @@ -106,9 +106,6 @@ export async function activate(context: ExtContext): Promise { localize = nls.loadMessageBundle() const codewhispererSettings = CodeWhispererSettings.instance - // Import old CodeWhisperer settings into Amazon Q - await CodeWhispererSettings.instance.importSettings() - // initialize AuthUtil earlier to make sure it can listen to connection change events. const auth = AuthUtil.instance auth.initCodeWhispererHooks() diff --git a/packages/core/src/codewhisperer/util/authUtil.ts b/packages/core/src/codewhisperer/util/authUtil.ts index 53c33c2ed4e..461f262d34d 100644 --- a/packages/core/src/codewhisperer/util/authUtil.ts +++ b/packages/core/src/codewhisperer/util/authUtil.ts @@ -501,30 +501,6 @@ export class AuthUtil { } } -/** - * Returns true if an SSO connection with AmazonQ and CodeWhisperer scopes are found, - * even if the connection is expired. - * - * Note: This function will become irrelevant if/when the Amazon Q view tree is removed - * from the toolkit. - */ -export function isPreviousQUser() { - const auth = AuthUtil.instance - - if (!auth.isConnected() || !isSsoConnection(auth.conn)) { - return false - } - const missingScopes = - (auth.isEnterpriseSsoInUse() && !hasScopes(auth.conn, amazonQScopes)) || - !hasScopes(auth.conn, codeWhispererChatScopes) - - if (missingScopes) { - return false - } - - return true -} - export type FeatureAuthState = { [feature in Feature]: AuthState } export type Feature = (typeof Features)[keyof typeof Features] export type AuthState = (typeof AuthStates)[keyof typeof AuthStates] diff --git a/packages/core/src/codewhisperer/util/codewhispererSettings.ts b/packages/core/src/codewhisperer/util/codewhispererSettings.ts index 32ae9cd0307..2bf2f657867 100644 --- a/packages/core/src/codewhisperer/util/codewhispererSettings.ts +++ b/packages/core/src/codewhisperer/util/codewhispererSettings.ts @@ -2,7 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ -import { fromExtensionManifest, migrateSetting } from '../../shared/settings' +import { fromExtensionManifest } from '../../shared/settings' import { ArrayConstructor } from '../../shared/utilities/typeConstructors' const description = { @@ -17,22 +17,6 @@ const description = { } export class CodeWhispererSettings extends fromExtensionManifest('amazonQ', description) { - // TODO: Remove after a few releases - public async importSettings() { - await migrateSetting( - { key: 'aws.codeWhisperer.includeSuggestionsWithCodeReferences', type: Boolean }, - { key: 'amazonQ.showInlineCodeSuggestionsWithCodeReferences' } - ) - await migrateSetting( - { key: 'aws.codeWhisperer.importRecommendation', type: Boolean }, - { key: 'amazonQ.importRecommendationForInlineCodeSuggestions' } - ) - await migrateSetting( - { key: 'aws.codeWhisperer.shareCodeWhispererContentWithAWS', type: Boolean }, - { key: 'amazonQ.shareContentWithAWS' } - ) - } - public isSuggestionsWithCodeReferencesEnabled(): boolean { return this.get(`showInlineCodeSuggestionsWithCodeReferences`, false) } diff --git a/packages/core/src/extensionNode.ts b/packages/core/src/extensionNode.ts index 480e409f5d8..d0275f0274f 100644 --- a/packages/core/src/extensionNode.ts +++ b/packages/core/src/extensionNode.ts @@ -51,7 +51,7 @@ import { getTelemetryMetadataForConn } from './auth/connection' import { registerSubmitFeedback } from './feedback/vue/submitFeedback' import { activateCommon, deactivateCommon } from './extension' import { learnMoreAmazonQCommand, qExtensionPageCommand, dismissQTree } from './amazonq/explorer/amazonQChildrenNodes' -import { AuthUtil, codeWhispererCoreScopes, isPreviousQUser } from './codewhisperer/util/authUtil' +import { AuthUtil, codeWhispererCoreScopes } from './codewhisperer/util/authUtil' import { installAmazonQExtension } from './codewhisperer/commands/basicCommands' import { isExtensionInstalled, VSCODE_EXTENSION_ID } from './shared/utilities' import { ExtensionUse, getAuthFormIdsFromConnection, initializeCredentialsProviderManager } from './auth/utils' @@ -272,52 +272,47 @@ export async function deactivate() { async function handleAmazonQInstall() { const dismissedInstall = globals.globalState.get('aws.toolkit.amazonqInstall.dismissed') - if (isExtensionInstalled(VSCODE_EXTENSION_ID.amazonq) || dismissedInstall) { + if (dismissedInstall) { + return + } + + if (isExtensionInstalled(VSCODE_EXTENSION_ID.amazonq)) { + await globals.globalState.update('aws.toolkit.amazonqInstall.dismissed', true) return } await telemetry.toolkit_showNotification.run(async () => { - if (isPreviousQUser()) { - await installAmazonQExtension.execute() - telemetry.record({ id: 'amazonQStandaloneInstalled' }) - void vscode.window.showInformationMessage( - "Amazon Q is now its own extension.\n\nWe've auto-installed it for you with all the same features and settings from CodeWhisperer and Amazon Q chat." + telemetry.record({ id: 'amazonQStandaloneChange' }) + void vscode.window + .showInformationMessage( + 'Try Amazon Q, a generative AI assistant, with chat and code suggestions.', + 'Install', + 'Learn More' ) - await globals.globalState.update('aws.toolkit.amazonqInstall.dismissed', true) - } else { - telemetry.record({ id: 'amazonQStandaloneChange' }) - void vscode.window - .showInformationMessage( - 'Amazon Q has moved to its own extension.' + - '\nInstall it to use Amazon Q, a generative AI assistant, with chat and code suggestions.', - 'Install', - 'Learn More' - ) - .then(async (resp) => { - await telemetry.toolkit_invokeAction.run(async () => { - telemetry.record({ - source: ExtensionUse.instance.isFirstUse() - ? ExtStartUpSources.firstStartUp - : ExtStartUpSources.none, - }) - - if (resp === 'Learn More') { - // Clicking learn more will open the q extension page - telemetry.record({ action: 'learnMore' }) - await qExtensionPageCommand.execute() - return - } - - if (resp === 'Install') { - telemetry.record({ action: 'installAmazonQ' }) - await installAmazonQExtension.execute() - } else { - telemetry.record({ action: 'dismissQNotification' }) - } - await globals.globalState.update('aws.toolkit.amazonqInstall.dismissed', true) + .then(async (resp) => { + await telemetry.toolkit_invokeAction.run(async () => { + telemetry.record({ + source: ExtensionUse.instance.isFirstUse() + ? ExtStartUpSources.firstStartUp + : ExtStartUpSources.none, }) + + if (resp === 'Learn More') { + // Clicking learn more will open the q extension page + telemetry.record({ action: 'learnMore' }) + await qExtensionPageCommand.execute() + return + } + + if (resp === 'Install') { + telemetry.record({ action: 'installAmazonQ' }) + await installAmazonQExtension.execute() + } else { + telemetry.record({ action: 'dismissQNotification' }) + } + await globals.globalState.update('aws.toolkit.amazonqInstall.dismissed', true) }) - } + }) }) } diff --git a/packages/core/src/shared/telemetry/activation.ts b/packages/core/src/shared/telemetry/activation.ts index e9fa6b4c2b1..5b1ba3e5a56 100644 --- a/packages/core/src/shared/telemetry/activation.ts +++ b/packages/core/src/shared/telemetry/activation.ts @@ -40,7 +40,6 @@ export async function activate( productName: AWSProduct ) { const config = new TelemetryConfig(settings) - await config.initAmazonQSetting() // TODO: Remove after a few releases. DefaultTelemetryClient.productName = productName globals.telemetry = await DefaultTelemetryService.create(awsContext, getComputeRegion()) diff --git a/packages/core/src/shared/telemetry/util.ts b/packages/core/src/shared/telemetry/util.ts index 67a2d460dd8..a81dd8fc12d 100644 --- a/packages/core/src/shared/telemetry/util.ts +++ b/packages/core/src/shared/telemetry/util.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode' import { env, version } from 'vscode' import * as os from 'os' import { getLogger } from '../logger' -import { fromExtensionManifest, migrateSetting, Settings } from '../settings' +import { fromExtensionManifest, Settings } from '../settings' import { memoize, once } from '../utilities/functionUtils' import { isInDevEnv, @@ -65,16 +65,6 @@ export class TelemetryConfig { public isEnabled(): boolean { return (isAmazonQ() ? this.amazonQConfig : this.toolkitConfig).get(`telemetry`, true) } - - public async initAmazonQSetting() { - if (!isAmazonQ() || globals.globalState.tryGet('amazonq.telemetry.migrated', Boolean, false)) { - return - } - // aws.telemetry isn't deprecated, we are just initializing amazonQ.telemetry with its value. - // This is also why we need to check that we only try this migration once. - await migrateSetting({ key: 'aws.telemetry', type: Boolean }, { key: 'amazonQ.telemetry' }) - await globals.globalState.update('amazonq.telemetry.migrated', true) - } } export function convertLegacy(value: unknown): boolean { diff --git a/packages/toolkit/.changes/next-release/Removal-1c5617ae-50c9-4de1-a191-a2d57dce5bd7.json b/packages/toolkit/.changes/next-release/Removal-1c5617ae-50c9-4de1-a191-a2d57dce5bd7.json new file mode 100644 index 00000000000..d49140750c8 --- /dev/null +++ b/packages/toolkit/.changes/next-release/Removal-1c5617ae-50c9-4de1-a191-a2d57dce5bd7.json @@ -0,0 +1,4 @@ +{ + "type": "Removal", + "description": "Amazon Q: No longer autoinstall Amazon Q if the user had used CodeWhisperer in old Toolkit versions." +} From 611b286ea46651f8b641eae1971dd2c98222d1b6 Mon Sep 17 00:00:00 2001 From: Maxim Hayes Date: Fri, 3 Jan 2025 13:50:11 -0600 Subject: [PATCH 2/2] revert(toolkit): Q <--> Toolkit auth separation notification Removes the prompt shown in Toolkit that Amazon Q no longer shares connections with it. Some time has passed, active users should have been informed by now. We are still getting telemetry hits indicating that this is being used though. NOTE: Does not revert or remove any separation logic itself. We continue to have separate sessions and also remove any connections in either extension that are extra or don't match the required scopes for that extension. That logic helps us catch auth edge cases. --- packages/core/src/auth/auth.ts | 73 ------------------- packages/core/src/codecatalyst/activation.ts | 2 - packages/core/src/extensionNode.ts | 12 +-- packages/core/src/shared/globalState.ts | 2 - packages/core/src/test/techdebt.test.ts | 11 +-- ...-6703e62b-3835-402b-b187-b327c58f425b.json | 4 + 6 files changed, 7 insertions(+), 97 deletions(-) create mode 100644 packages/toolkit/.changes/next-release/Removal-6703e62b-3835-402b-b187-b327c58f425b.json diff --git a/packages/core/src/auth/auth.ts b/packages/core/src/auth/auth.ts index 3335f8ab333..5203735e05a 100644 --- a/packages/core/src/auth/auth.ts +++ b/packages/core/src/auth/auth.ts @@ -339,11 +339,6 @@ export class Auth implements AuthService, ConnectionManager { metadata: { connectionState: 'unauthenticated' }, }) - // Remove the split session logout prompt, if it exists. - if (!isAmazonQ()) { - await globals.globalState.update('aws.toolkit.separationPromptDismissed', true) - } - try { ;(await tokenProvider.getToken()) ?? (await tokenProvider.createToken()) const storedProfile = await this.store.addProfile(id, profile) @@ -1136,71 +1131,3 @@ export function hasVendedIamCredentials(isC9?: boolean, isSM?: boolean) { isSM ??= isSageMaker() return isSM || isC9 } - -type LoginCommand = 'aws.toolkit.auth.manageConnections' | 'aws.codecatalyst.manageConnections' -/** - * Temporary class that handles notifiting users who were logged out as part of - * splitting auth sessions between extensions. - * - * TODO: Remove after some time. - */ -export class SessionSeparationPrompt { - // Local variable handles per session displays, e.g. we forgot a CodeCatalyst connection AND - // an Explorer only connection. We only want to display once in this case. - // However, we don't want to set this at the global state level until a user interacts with the - // notification in case they miss it the first time. - #separationPromptDisplayed = false - - /** - * Open a prompt for that last used command name (or do nothing if no command name has ever been passed), - * which is useful to redisplay the prompt after reloads in case a user misses it. - */ - public async showAnyPreviousPrompt() { - const cmd = globals.globalState.tryGet('aws.toolkit.separationPromptCommand', String) - return cmd ? await this.showForCommand(cmd as LoginCommand) : undefined - } - - /** - * Displays a sign in prompt to the user if they have been logged out of the Toolkit as part of - * separating auth sessions between extensions. It will executed the passed command for sign in, - * (e.g. codecatalyst sign in vs explorer) - */ - public async showForCommand(cmd: LoginCommand) { - if ( - this.#separationPromptDisplayed || - globals.globalState.get('aws.toolkit.separationPromptDismissed') - ) { - return - } - - await globals.globalState.update('aws.toolkit.separationPromptCommand', cmd) - - await telemetry.toolkit_showNotification.run(async () => { - telemetry.record({ id: 'sessionSeparation' }) - this.#separationPromptDisplayed = true - void vscode.window - .showWarningMessage( - 'Amazon Q and AWS Toolkit no longer share connections. Please sign in again to use AWS Toolkit.', - 'Sign In' - ) - .then(async (resp) => { - await telemetry.toolkit_invokeAction.run(async () => { - telemetry.record({ source: 'sessionSeparationNotification' }) - if (resp === 'Sign In') { - telemetry.record({ action: 'signIn' }) - await vscode.commands.executeCommand(cmd) - } else { - telemetry.record({ action: 'dismiss' }) - } - - await globals.globalState.update('aws.toolkit.separationPromptDismissed', true) - }) - }) - }) - } - - static #instance: SessionSeparationPrompt - public static get instance() { - return (this.#instance ??= new SessionSeparationPrompt()) - } -} diff --git a/packages/core/src/codecatalyst/activation.ts b/packages/core/src/codecatalyst/activation.ts index 4a2385559f4..3e47dd53879 100644 --- a/packages/core/src/codecatalyst/activation.ts +++ b/packages/core/src/codecatalyst/activation.ts @@ -26,7 +26,6 @@ import { DevEnvActivityStarter } from './devEnv' import { learnMoreCommand, onboardCommand, reauth } from './explorer' import { isInDevEnv } from '../shared/vscode/env' import { hasScopes, scopesCodeWhispererCore, getTelemetryMetadataForConn } from '../auth/connection' -import { SessionSeparationPrompt } from '../auth/auth' import { telemetry } from '../shared/telemetry/telemetry' import { asStringifiedStack } from '../shared/telemetry/spans' @@ -64,7 +63,6 @@ export async function activate(ctx: ExtContext): Promise { }) await authProvider.secondaryAuth.forgetConnection() - await SessionSeparationPrompt.instance.showForCommand('aws.codecatalyst.manageConnections') }) }, { emit: false, functionId: { name: 'activate', class: 'CodeCatalyst' } } diff --git a/packages/core/src/extensionNode.ts b/packages/core/src/extensionNode.ts index d0275f0274f..0c53cc89975 100644 --- a/packages/core/src/extensionNode.ts +++ b/packages/core/src/extensionNode.ts @@ -46,12 +46,12 @@ import globals from './shared/extensionGlobals' import { Experiments, Settings, showSettingsFailedMsg } from './shared/settings' import { isReleaseVersion } from './shared/vscode/env' import { AuthStatus, AuthUserState, telemetry } from './shared/telemetry/telemetry' -import { Auth, SessionSeparationPrompt } from './auth/auth' +import { Auth } from './auth/auth' import { getTelemetryMetadataForConn } from './auth/connection' import { registerSubmitFeedback } from './feedback/vue/submitFeedback' import { activateCommon, deactivateCommon } from './extension' import { learnMoreAmazonQCommand, qExtensionPageCommand, dismissQTree } from './amazonq/explorer/amazonQChildrenNodes' -import { AuthUtil, codeWhispererCoreScopes } from './codewhisperer/util/authUtil' +import { codeWhispererCoreScopes } from './codewhisperer/util/authUtil' import { installAmazonQExtension } from './codewhisperer/commands/basicCommands' import { isExtensionInstalled, VSCODE_EXTENSION_ID } from './shared/utilities' import { ExtensionUse, getAuthFormIdsFromConnection, initializeCredentialsProviderManager } from './auth/utils' @@ -139,16 +139,8 @@ export async function activate(context: vscode.ExtensionContext) { conn.scopes ) await Auth.instance.forgetConnection(conn) - await SessionSeparationPrompt.instance.showForCommand('aws.toolkit.auth.manageConnections') } } - - // Display last prompt if connections were forgotten in prior sessions - // but the user did not interact or sign in again. Useful in case the user misses it the first time. - await SessionSeparationPrompt.instance.showAnyPreviousPrompt() - - // MUST restore CW/Q auth so that we can see if this user is already a Q user. - await AuthUtil.instance.restore() }, { emit: false, functionId: { name: 'activate', class: 'ExtensionNodeCore' } } ) diff --git a/packages/core/src/shared/globalState.ts b/packages/core/src/shared/globalState.ts index 5cce9ff6f84..5662c3e608e 100644 --- a/packages/core/src/shared/globalState.ts +++ b/packages/core/src/shared/globalState.ts @@ -44,8 +44,6 @@ export type globalKey = | 'aws.toolkit.amazonq.dismissed' | 'aws.toolkit.amazonqInstall.dismissed' | 'aws.amazonq.workspaceIndexToggleOn' - | 'aws.toolkit.separationPromptCommand' - | 'aws.toolkit.separationPromptDismissed' // Deprecated/legacy names. New keys should start with "aws.". | '#sessionCreationDates' // Legacy name from `ssoAccessTokenProvider.ts`. | 'CODECATALYST_RECONNECT' diff --git a/packages/core/src/test/techdebt.test.ts b/packages/core/src/test/techdebt.test.ts index caa9a977b62..69e557100f7 100644 --- a/packages/core/src/test/techdebt.test.ts +++ b/packages/core/src/test/techdebt.test.ts @@ -10,6 +10,7 @@ import * as env from '../shared/vscode/env' // Checks project config and dependencies, to remind us to remove old things // when possible. describe('tech debt', function () { + // @ts-ignore function fixByDate(date: string, msg: string) { const now = Date.now() const cutoffDate = Date.parse(date) @@ -38,14 +39,4 @@ describe('tech debt', function () { // This is relevant for the use of `fs.cpSync` in the copyFiles scripts. assert.ok(semver.lt(minNodejs, '18.0.0'), 'with node18+, we can remove the dependency on @types/node@18') }) - - it('remove separate sessions login edge cases', async function () { - // src/auth/auth.ts:SessionSeparationPrompt - // forgetConnection() function and calls - - // Monitor telemtry to determine removal or snooze - // toolkit_showNotification.id = sessionSeparation - // auth_modifyConnection.action = deleteProfile OR auth_modifyConnection.source contains CodeCatalyst - fixByDate('2025-06-06', 'Remove the edge case code from the commit that this test is a part of.') - }) }) diff --git a/packages/toolkit/.changes/next-release/Removal-6703e62b-3835-402b-b187-b327c58f425b.json b/packages/toolkit/.changes/next-release/Removal-6703e62b-3835-402b-b187-b327c58f425b.json new file mode 100644 index 00000000000..7cb1f436b51 --- /dev/null +++ b/packages/toolkit/.changes/next-release/Removal-6703e62b-3835-402b-b187-b327c58f425b.json @@ -0,0 +1,4 @@ +{ + "type": "Removal", + "description": "Auth: No longer inform users that Amazon Q and Toolkit extensions have separate auth sessions." +}