Skip to content

Commit 170cd88

Browse files
authored
Merge aws#5293 globalState abstraction
2 parents 6d90624 + d8cce7c commit 170cd88

File tree

19 files changed

+427
-134
lines changed

19 files changed

+427
-134
lines changed

packages/amazonq/src/extensionCommon.ts

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,38 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import * as vscode from 'vscode'
7-
import * as semver from 'semver'
8-
import { join } from 'path'
6+
import { AuthUtils, CredentialsStore, LoginManager, SsoConnection, initializeAuth } from 'aws-core-vscode/auth'
97
import {
8+
AuthUtil,
109
activate as activateCodeWhisperer,
1110
shutdown as shutdownCodeWhisperer,
12-
AuthUtil,
1311
} from 'aws-core-vscode/codewhispererCommon'
12+
import { makeEndpointsProvider, registerGenericCommands } from 'aws-core-vscode/extensionCommon'
13+
import { CommonAuthWebview } from 'aws-core-vscode/login'
1414
import {
15+
DefaultAWSClientBuilder,
16+
DefaultAwsContext,
1517
ExtContext,
16-
initialize,
18+
RegionProvider,
19+
Settings,
1720
activateLogger,
1821
activateTelemetry,
19-
Settings,
20-
DefaultAwsContext,
21-
initializeComputeRegion,
22-
DefaultAWSClientBuilder,
23-
globals,
24-
RegionProvider,
22+
env,
23+
errors,
24+
fs,
2525
getLogger,
2626
getMachineId,
27+
globals,
28+
initialize,
29+
initializeComputeRegion,
2730
messages,
31+
setContext,
2832
} from 'aws-core-vscode/shared'
29-
import { fs, errors, setContext } from 'aws-core-vscode/shared'
30-
import { initializeAuth, CredentialsStore, LoginManager, AuthUtils, SsoConnection } from 'aws-core-vscode/auth'
31-
import { CommonAuthWebview } from 'aws-core-vscode/login'
33+
import { ExtStartUpSources, telemetry } from 'aws-core-vscode/telemetry'
3234
import { VSCODE_EXTENSION_ID } from 'aws-core-vscode/utils'
33-
import { telemetry, ExtStartUpSources } from 'aws-core-vscode/telemetry'
34-
import { makeEndpointsProvider, registerGenericCommands } from 'aws-core-vscode/extensionCommon'
35+
import { join } from 'path'
36+
import * as semver from 'semver'
37+
import * as vscode from 'vscode'
3538
import { registerCommands } from './commands'
3639

3740
export const amazonQContextPrefix = 'amazonq'
@@ -44,7 +47,7 @@ export async function activateAmazonQCommon(context: vscode.ExtensionContext, is
4447
const homeDirLogs = await fs.init(context, homeDir => {
4548
void messages.showViewLogsMessage(`Invalid home directory (check $HOME): "${homeDir}"`)
4649
})
47-
errors.init(fs.getUsername())
50+
errors.init(fs.getUsername(), env.isAutomation())
4851
await initializeComputeRegion()
4952

5053
globals.contextPrefix = 'amazonq.' //todo: disconnect from above line

packages/amazonq/test/unit/codewhisperer/service/telemetry.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import {
2626
vsCodeCursorUpdateDelay,
2727
AuthUtil,
2828
} from 'aws-core-vscode/codewhisperer'
29-
import { sleep, waitUntil, getMinVscodeVersion, CodewhispererUserTriggerDecision } from 'aws-core-vscode/shared'
29+
import { sleep, waitUntil, env, CodewhispererUserTriggerDecision } from 'aws-core-vscode/shared'
3030
import { resetCodeWhispererGlobalVariables } from 'aws-core-vscode/test'
3131

3232
type CodeWhispererResponse = ListRecommendationsResponse & {
@@ -288,7 +288,7 @@ describe.skip('CodeWhisperer telemetry', async function () {
288288
// as per vscode official repo PR https://github.com/microsoft/vscode/commit/cb0e59c56677181b570b110167d13efb4ba7677d#diff-84b7f4a5ab7c383d86e2d40e2c704d255dc1e187a29386c036023a4696196556R19
289289
// navigation commands seem to be introduced since 1.78.0
290290
function shouldRun() {
291-
const version = getMinVscodeVersion()
291+
const version = env.getMinVscodeVersion()
292292
if (semver.gte(version, '1.78.0')) {
293293
throw new Error('Minimum VSCode version is greater than 1.78.0, this check should be removed')
294294
}

packages/core/src/auth/sso/ssoAccessTokenProvider.ts

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ export abstract class SsoAccessTokenProvider {
107107
const access = await this.runFlow()
108108
const identity = this.tokenCacheKey
109109
await this.cache.token.save(identity, access)
110-
await setSessionCreationDate(this.tokenCacheKey, new Date())
110+
await globals.globalState.setSsoSessionCreationDate(this.tokenCacheKey, new globals.clock.Date())
111111

112112
return { ...access.token, identity }
113113
}
@@ -309,25 +309,13 @@ async function pollForTokenWithProgress<T extends { requestId?: string }>(
309309
)
310310
}
311311

312-
const sessionCreationDateKey = '#sessionCreationDates'
313-
async function setSessionCreationDate(id: string, date: Date, memento = globals.context.globalState) {
314-
try {
315-
await memento.update(sessionCreationDateKey, {
316-
...memento.get(sessionCreationDateKey),
317-
[id]: date.getTime(),
318-
})
319-
} catch (err) {
320-
getLogger().verbose('auth: failed to set session creation date: %s', err)
321-
}
322-
}
323-
324-
function getSessionCreationDate(id: string, memento = globals.context.globalState): number | undefined {
325-
return memento.get(sessionCreationDateKey, {} as Record<string, number>)[id]
326-
}
327-
328-
function getSessionDuration(id: string, memento = globals.context.globalState) {
329-
const creationDate = getSessionCreationDate(id, memento)
330-
312+
/**
313+
* Gets SSO session creation timestamp for the given session `id`.
314+
*
315+
* @param id Session id
316+
*/
317+
function getSessionDuration(id: string) {
318+
const creationDate = globals.globalState.getSsoSessionCreationDate(id)
331319
return creationDate !== undefined ? Date.now() - creationDate : undefined
332320
}
333321

packages/core/src/awsService/redshift/activation.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ import { RedshiftNotebookController } from './notebook/redshiftNotebookControlle
1010
import { CellStatusBarItemProvider } from './notebook/cellStatusBarItemProvider'
1111
import { Commands } from '../../shared/vscode/commands2'
1212
import { NotebookConnectionWizard, RedshiftNodeConnectionWizard } from './wizards/connectionWizard'
13-
import { ConnectionParams, ConnectionType } from './models/models'
13+
import { deleteConnection, ConnectionParams, ConnectionType } from './models/models'
1414
import { DefaultRedshiftClient } from '../../shared/clients/redshiftClient'
1515
import { localize } from '../../shared/utilities/vsCodeUtils'
1616
import { RedshiftWarehouseNode } from './explorer/redshiftWarehouseNode'
1717
import { ToolkitError } from '../../shared/errors'
18-
import { deleteConnection, updateConnectionParamsState } from './explorer/redshiftState'
1918
import { showViewLogsMessage } from '../../shared/utilities/messages'
2019
import { showConnectionMessage } from './messageUtils'
20+
import globals from '../../shared/extensionGlobals'
2121

2222
export async function activate(ctx: ExtContext): Promise<void> {
2323
if ('NotebookEdit' in vscode) {
@@ -123,7 +123,10 @@ function getEditConnectionHandler() {
123123
connectionParams.secret = secretArnFetched
124124
}
125125
redshiftWarehouseNode.setConnectionParams(connectionParams)
126-
await updateConnectionParamsState(redshiftWarehouseNode.arn, redshiftWarehouseNode.connectionParams)
126+
await globals.globalState.saveRedshiftConnection(
127+
redshiftWarehouseNode.arn,
128+
redshiftWarehouseNode.connectionParams
129+
)
127130
await vscode.commands.executeCommand('aws.refreshAwsExplorerNode', redshiftWarehouseNode)
128131
}
129132
} catch (error) {
@@ -135,7 +138,7 @@ function getEditConnectionHandler() {
135138
function getDeleteConnectionHandler() {
136139
return async (redshiftWarehouseNode: RedshiftWarehouseNode) => {
137140
redshiftWarehouseNode.connectionParams = undefined
138-
await updateConnectionParamsState(redshiftWarehouseNode.arn, deleteConnection)
141+
await globals.globalState.saveRedshiftConnection(redshiftWarehouseNode.arn, deleteConnection)
139142
await vscode.commands.executeCommand('aws.refreshAwsExplorerNode', redshiftWarehouseNode)
140143
}
141144
}

packages/core/src/awsService/redshift/explorer/redshiftState.ts

Lines changed: 0 additions & 45 deletions
This file was deleted.

packages/core/src/awsService/redshift/explorer/redshiftWarehouseNode.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@
55
import { AWSResourceNode } from '../../../shared/treeview/nodes/awsResourceNode'
66
import { AWSTreeNodeBase } from '../../../shared/treeview/nodes/awsTreeNodeBase'
77
import * as vscode from 'vscode'
8+
import globals from '../../../shared/extensionGlobals'
89
import { RedshiftNode } from './redshiftNode'
910
import { makeChildrenNodes } from '../../../shared/treeview/utils'
1011
import { RedshiftDatabaseNode } from './redshiftDatabaseNode'
1112
import { localize } from '../../../shared/utilities/vsCodeUtils'
1213
import { LoadMoreNode } from '../../../shared/treeview/nodes/loadMoreNode'
1314
import { ChildNodeLoader, ChildNodePage } from '../../../awsexplorer/childNodeLoader'
1415
import { DefaultRedshiftClient } from '../../../shared/clients/redshiftClient'
15-
import { ConnectionParams, ConnectionType, RedshiftWarehouseType } from '../models/models'
16+
import { deleteConnection, ConnectionParams, ConnectionType, RedshiftWarehouseType } from '../models/models'
1617
import { RedshiftNodeConnectionWizard } from '../wizards/connectionWizard'
1718
import { ListDatabasesResponse } from 'aws-sdk/clients/redshiftdata'
1819
import { getIcon } from '../../../shared/icons'
1920
import { AWSCommandTreeNode } from '../../../shared/treeview/nodes/awsCommandTreeNode'
2021
import { telemetry } from '../../../shared/telemetry/telemetry'
21-
import { deleteConnection, getConnectionParamsState, updateConnectionParamsState } from './redshiftState'
2222
import { createLogsConnectionMessage, showConnectionMessage } from '../messageUtils'
2323

2424
export class CreateNotebookNode extends AWSCommandTreeNode {
@@ -50,7 +50,7 @@ export class RedshiftWarehouseNode extends AWSTreeNodeBase implements AWSResourc
5050
this.arn = redshiftWarehouse.arn
5151
this.name = redshiftWarehouse.name
5252
this.redshiftClient = parent.redshiftClient
53-
const existingConnectionParams = getConnectionParamsState(this.arn)
53+
const existingConnectionParams = globals.globalState.getRedshiftConnection(this.arn)
5454
if (existingConnectionParams && existingConnectionParams !== deleteConnection) {
5555
this.connectionParams = existingConnectionParams as ConnectionParams
5656
this.iconPath = getIcon('aws-redshift-cluster-connected')
@@ -108,14 +108,14 @@ export class RedshiftWarehouseNode extends AWSTreeNodeBase implements AWSResourc
108108
return await makeChildrenNodes({
109109
getChildNodes: async () => {
110110
this.childLoader.clearChildren()
111-
const existingConnectionParams = getConnectionParamsState(this.arn)
111+
const existingConnectionParams = globals.globalState.getRedshiftConnection(this.arn)
112112
if (existingConnectionParams && existingConnectionParams === deleteConnection) {
113113
// connection is deleted but explorer is not refreshed: return clickToEstablishConnectionNode
114-
await updateConnectionParamsState(this.arn, undefined)
114+
await globals.globalState.saveRedshiftConnection(this.arn, undefined)
115115
return this.getClickToEstablishConnectionNode()
116-
} else if (existingConnectionParams && existingConnectionParams !== deleteConnection) {
116+
} else if (existingConnectionParams) {
117117
// valid connectionParams: update the redshiftWarehouseNode
118-
this.connectionParams = existingConnectionParams as ConnectionParams
118+
this.connectionParams = existingConnectionParams
119119
} else {
120120
// No connectionParams: trigger connection wizard to get user input
121121
this.connectionParams = await new RedshiftNodeConnectionWizard(this).run()
@@ -137,11 +137,11 @@ export class RedshiftWarehouseNode extends AWSTreeNodeBase implements AWSResourc
137137
const childNodes = await this.childLoader.getChildren()
138138
const startButtonNode = new CreateNotebookNode(this)
139139
childNodes.unshift(startButtonNode)
140-
await updateConnectionParamsState(this.arn, this.connectionParams)
140+
await globals.globalState.saveRedshiftConnection(this.arn, this.connectionParams)
141141
return childNodes
142142
} catch (error) {
143143
showConnectionMessage(this.redshiftWarehouse.name, error as Error)
144-
await updateConnectionParamsState(this.arn, undefined)
144+
await globals.globalState.saveRedshiftConnection(this.arn, undefined)
145145
return this.getRetryNode()
146146
}
147147
},

packages/core/src/awsService/redshift/models/models.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55

66
import { Region } from '../../../shared/regions/endpoints'
77

8+
// Sigil treated such that the connection wizard is not triggered during explorer node refresh after
9+
// connection deletion.
10+
export const deleteConnection = 'DELETE_CONNECTION' as const
11+
812
export class ConnectionParams {
913
constructor(
1014
public readonly connectionType: ConnectionType,

packages/core/src/extensionCommon.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import { LoginManager } from './auth/deprecated/loginManager'
3535
import { CredentialsStore } from './auth/credentials/store'
3636
import { initializeAwsCredentialsStatusBarItem } from './auth/ui/statusBarItem'
3737
import { RegionProvider, getEndpointsFromFetcher } from './shared/regions/regionProvider'
38-
import { getMachineId } from './shared/vscode/env'
38+
import { getMachineId, isAutomation } from './shared/vscode/env'
3939
import { registerCommandErrorHandler } from './shared/vscode/commands2'
4040
import { registerWebviewErrorHandler } from './webviews/server'
4141
import { showQuickStartWebview } from './shared/extensionStartup'
@@ -77,7 +77,7 @@ export async function activateCommon(
7777
const homeDirLogs = await fs.init(context, homeDir => {
7878
void showViewLogsMessage(`Invalid home directory (check $HOME): "${homeDir}"`)
7979
})
80-
errors.init(fs.getUsername())
80+
errors.init(fs.getUsername(), isAutomation())
8181
await initializeComputeRegion()
8282

8383
globals.contextPrefix = '' //todo: disconnect supplied argument

packages/core/src/shared/errors.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@ import { isNonNullable } from './utilities/tsUtils'
1313
import type * as nodefs from 'fs'
1414
import type * as os from 'os'
1515
import { CodeWhispererStreamingServiceException } from '@amzn/codewhisperer-streaming'
16-
import { isAutomation } from './vscode/env'
1716
import { driveLetterRegex } from './utilities/pathUtils'
1817

1918
let _username = 'unknown-user'
19+
let _isAutomation = false
2020

21-
/** One-time initialization for this module. */
22-
export function init(username: string) {
21+
/** Performs one-time initialization, to avoid circular dependencies. */
22+
export function init(username: string, isAutomation: boolean) {
2323
_username = username
24+
_isAutomation = isAutomation
2425
}
2526

2627
export const errorCode = {
@@ -667,7 +668,7 @@ function vscodeModeToString(mode: vscode.FileStat['permissions']) {
667668
}
668669

669670
// XXX: future-proof in case vscode.FileStat.permissions gains more granularity.
670-
if (isAutomation()) {
671+
if (_isAutomation) {
671672
throw new Error('vscode.FileStat.permissions gained new fields, update this logic')
672673
}
673674
}

packages/core/src/shared/extensionGlobals.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ export function initialize(context: ExtensionContext, isWeb: boolean = false): T
147147
context,
148148
clock: copyClock(),
149149
didReload: checkDidReload(context),
150-
globalState: new GlobalState(context),
150+
globalState: new GlobalState(context.globalState),
151151
manifestPaths: {} as ToolkitGlobals['manifestPaths'],
152152
visualizationResourcePaths: {} as ToolkitGlobals['visualizationResourcePaths'],
153153
isWeb,
@@ -171,7 +171,7 @@ export { globals as default }
171171
*/
172172
interface ToolkitGlobals {
173173
readonly context: ExtensionContext
174-
/** Global, shared, mutable, persisted state (survives IDE restart), namespaced to the extension (i.e. not shared with other vscode extensions). */
174+
/** Global, shared (with all vscode instances, including remote!), mutable, persisted state (survives IDE restart), namespaced to the extension (not shared with other vscode extensions). */
175175
readonly globalState: GlobalState
176176
/** Decides the prefix for package.json extension parameters, e.g. commands, 'setContext' values, etc. */
177177
contextPrefix: string

0 commit comments

Comments
 (0)