Skip to content

Commit d44be74

Browse files
authored
refactor(codecatalyst): use public SDK model #3031
* Listen for errors * Smart eviction * Add some basic caching to reduce the # of verifySession and getUserDetails calls.
1 parent b5a8898 commit d44be74

21 files changed

+171
-2004
lines changed

.eslintignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ node_modules/**
33
src/shared/telemetry/clienttelemetry.d.ts
44
src/codewhisperer/client/codewhispererclient.d.ts
55
src/codewhisperer/client/codewhispereruserclient.d.ts
6-
types/clientcodecatalyst.d.ts
76
**/*.gen.ts
87
src/testFixtures/workspaceFolder/ts-plain-sam-app/
98
dist/**

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ src/shared/telemetry/vscodeTelemetry.json
2727
src/shared/telemetry/clienttelemetry.d.ts
2828
src/codewhisperer/client/codewhispererclient.d.ts
2929
src/codewhisperer/client/codewhispereruserclient.d.ts
30-
types/clientcodecatalyst.d.ts
3130

3231
# Generated by tests
3332
src/testFixtures/**/bin

package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3571,7 +3571,7 @@
35713571
"adm-zip": "^0.5.9",
35723572
"amazon-states-language-service": "^1.7.2",
35733573
"async-lock": "^1.3.0",
3574-
"aws-sdk": "^2.1211.0",
3574+
"aws-sdk": "^2.1267.0",
35753575
"aws-ssm-document-language-service": "^1.0.0",
35763576
"bytes": "^3.1.2",
35773577
"cross-spawn": "^7.0.3",

scripts/build/generateServiceClient.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,10 +206,6 @@ ${fileContents}
206206

207207
;(async () => {
208208
const serviceClientDefinitions: ServiceClientDefinition[] = [
209-
{
210-
serviceJsonPath: 'types/codecatalyst-2020-12-01.json',
211-
serviceName: 'ClientCodeCatalyst',
212-
},
213209
{
214210
serviceJsonPath: 'src/shared/telemetry/service-2.json',
215211
serviceName: 'ClientTelemetry',

src/codecatalyst/auth.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import * as vscode from 'vscode'
7-
import { ConnectedCodeCatalystClient } from '../shared/clients/codecatalystClient'
7+
import { CodeCatalystClient } from '../shared/clients/codecatalystClient'
88
import { isCloud9 } from '../shared/extensionUtilities'
99
import {
1010
Auth,
@@ -58,7 +58,7 @@ export class CodeCatalystAuthenticationProvider {
5858
}
5959

6060
// Get rid of this? Not sure where to put PAT code.
61-
public async getPat(client: ConnectedCodeCatalystClient, username = client.identity.name): Promise<string> {
61+
public async getPat(client: CodeCatalystClient, username = client.identity.name): Promise<string> {
6262
const stored = await this.storage.getPat(username)
6363

6464
if (stored) {
@@ -71,7 +71,7 @@ export class CodeCatalystAuthenticationProvider {
7171
return resp.secret
7272
}
7373

74-
public async getCredentialsForGit(client: ConnectedCodeCatalystClient) {
74+
public async getCredentialsForGit(client: CodeCatalystClient) {
7575
getLogger().verbose(`codecatalyst (git): attempting to provide credentials`)
7676

7777
const username = client.identity.name

src/codecatalyst/commands.ts

Lines changed: 20 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,24 @@ import { selectCodeCatalystResource } from './wizards/selectResource'
1313
import { openCodeCatalystUrl } from './utils'
1414
import { CodeCatalystAuthenticationProvider } from './auth'
1515
import { Commands } from '../shared/vscode/commands2'
16-
import {
17-
CodeCatalystClient,
18-
ConnectedCodeCatalystClient,
19-
CodeCatalystResource,
20-
} from '../shared/clients/codecatalystClient'
21-
import { createClientFactory, DevEnvironmentId, getConnectedDevEnv, openDevEnv } from './model'
16+
import { CodeCatalystClient, CodeCatalystResource, createClient } from '../shared/clients/codecatalystClient'
17+
import { DevEnvironmentId, getConnectedDevEnv, openDevEnv } from './model'
2218
import { showConfigureDevEnv } from './vue/configure/backend'
2319
import { showCreateDevEnv } from './vue/create/backend'
2420
import { CancellationError } from '../shared/utilities/timeoutUtils'
2521
import { ToolkitError } from '../shared/errors'
2622
import { telemetry } from '../shared/telemetry/telemetry'
2723
import { showConfirmationMessage } from '../shared/utilities/messages'
2824
import { AccountStatus } from '../shared/telemetry/telemetryClient'
29-
import { CreateDevEnvironmentRequest } from '../../types/clientcodecatalyst'
25+
import { CreateDevEnvironmentRequest } from 'aws-sdk/clients/codecatalyst'
3026

3127
/** "List CodeCatalyst Commands" command. */
3228
export async function listCommands(): Promise<void> {
3329
vscode.commands.executeCommand('workbench.action.quickOpen', '> CodeCatalyst')
3430
}
3531

3632
/** "Clone CodeCatalyst Repository" command. */
37-
export async function cloneCodeCatalystRepo(client: ConnectedCodeCatalystClient, url?: vscode.Uri): Promise<void> {
33+
export async function cloneCodeCatalystRepo(client: CodeCatalystClient, url?: vscode.Uri): Promise<void> {
3834
let resource: { name: string; project: string; org: string }
3935
if (!url) {
4036
const r = await selectCodeCatalystResource(client, 'repo')
@@ -65,7 +61,7 @@ export async function cloneCodeCatalystRepo(client: ConnectedCodeCatalystClient,
6561
* - "Open CodeCatalyst Repository"
6662
*/
6763
export async function openCodeCatalystResource(
68-
client: ConnectedCodeCatalystClient,
64+
client: CodeCatalystClient,
6965
kind: CodeCatalystResource['type']
7066
): Promise<void> {
7167
const resource = await selectCodeCatalystResource(client, kind)
@@ -78,7 +74,7 @@ export async function openCodeCatalystResource(
7874
}
7975

8076
export async function stopDevEnv(
81-
client: ConnectedCodeCatalystClient,
77+
client: CodeCatalystClient,
8278
devenv: DevEnvironmentId,
8379
opts?: { readonly showPrompt?: boolean }
8480
): Promise<void> {
@@ -102,7 +98,7 @@ export async function stopDevEnv(
10298
})
10399
}
104100

105-
export async function deleteDevEnv(client: ConnectedCodeCatalystClient, devenv: DevEnvironmentId): Promise<void> {
101+
export async function deleteDevEnv(client: CodeCatalystClient, devenv: DevEnvironmentId): Promise<void> {
106102
await client.deleteDevEnvironment({
107103
id: devenv.id,
108104
projectName: devenv.project.name,
@@ -116,7 +112,7 @@ export type DevEnvironmentSettings = Pick<
116112
>
117113

118114
export async function updateDevEnv(
119-
client: ConnectedCodeCatalystClient,
115+
client: CodeCatalystClient,
120116
devenv: DevEnvironmentId,
121117
settings: DevEnvironmentSettings
122118
) {
@@ -128,27 +124,16 @@ export async function updateDevEnv(
128124
})
129125
}
130126

131-
function createClientInjector(
132-
authProvider: CodeCatalystAuthenticationProvider,
133-
clientFactory: () => Promise<CodeCatalystClient>
134-
): ClientInjector {
127+
function createClientInjector(authProvider: CodeCatalystAuthenticationProvider): ClientInjector {
135128
return async (command, ...args) => {
136-
let client = await clientFactory()
129+
telemetry.record({ userId: AccountStatus.NotSet })
137130

138-
try {
139-
if (!client.connected) {
140-
const conn = await authProvider.promptNotConnected()
141-
client = await client.setCredentials(async () => (await conn.getToken()).accessToken)
142-
}
131+
await authProvider.restore()
132+
const conn = authProvider.activeConnection ?? (await authProvider.promptNotConnected())
133+
const client = await createClient(conn)
134+
telemetry.record({ userId: client.identity.id })
143135

144-
return await command(client, ...args)
145-
} finally {
146-
const userId = client.connected ? client.identity.id : AccountStatus.NotApplicable
147-
148-
// TODO(sijaden): should this mark only instantiated spans or future spans as well?
149-
// right now it won't mark spans if they're created and emitted prior to the command finishing
150-
telemetry.record({ userId })
151-
}
136+
return command(client, ...args)
152137
}
153138
}
154139

@@ -159,7 +144,7 @@ function createCommandDecorator(commands: CodeCatalystCommands): CommandDecorato
159144
}
160145

161146
interface CodeCatalystCommand<T extends any[], U> {
162-
(client: ConnectedCodeCatalystClient, ...args: T): U | Promise<U>
147+
(client: CodeCatalystClient, ...args: T): U | Promise<U>
163148
}
164149

165150
interface ClientInjector {
@@ -176,17 +161,14 @@ type Inject<T, U> = T extends (...args: infer P) => infer R
176161
: never
177162
: never
178163

179-
type WithClient<T> = Parameters<Inject<T, ConnectedCodeCatalystClient>>
164+
type WithClient<T> = Parameters<Inject<T, CodeCatalystClient>>
180165

181166
export class CodeCatalystCommands {
182167
public readonly withClient: ClientInjector
183168
public readonly bindClient = createCommandDecorator(this)
184169

185-
public constructor(
186-
authProvider: CodeCatalystAuthenticationProvider,
187-
clientFactory = createClientFactory(authProvider)
188-
) {
189-
this.withClient = createClientInjector(authProvider, clientFactory)
170+
public constructor(authProvider: CodeCatalystAuthenticationProvider) {
171+
this.withClient = createClientInjector(authProvider)
190172
}
191173

192174
public listCommands() {
@@ -282,9 +264,8 @@ export class CodeCatalystCommands {
282264

283265
public static fromContext(ctx: Pick<vscode.ExtensionContext, 'secrets' | 'globalState'>) {
284266
const auth = CodeCatalystAuthenticationProvider.fromContext(ctx)
285-
const factory = createClientFactory(auth)
286267

287-
return new this(auth, factory)
268+
return new this(auth)
288269
}
289270

290271
public static readonly declared = {

src/codecatalyst/explorer.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import * as vscode from 'vscode'
77
import { RootNode } from '../awsexplorer/localExplorer'
88
import { Connection, createBuilderIdConnection, isBuilderIdConnection } from '../credentials/auth'
9-
import { DevEnvironment } from '../shared/clients/codecatalystClient'
9+
import { createClient, DevEnvironment } from '../shared/clients/codecatalystClient'
1010
import { UnknownError } from '../shared/errors'
1111
import { isCloud9 } from '../shared/extensionUtilities'
1212
import { addColor, getIcon } from '../shared/icons'
@@ -15,7 +15,7 @@ import { TreeNode } from '../shared/treeview/resourceTreeDataProvider'
1515
import { Commands } from '../shared/vscode/commands2'
1616
import { CodeCatalystAuthenticationProvider } from './auth'
1717
import { CodeCatalystCommands } from './commands'
18-
import { ConnectedDevEnv, createClientFactory, getConnectedDevEnv, getDevfileLocation } from './model'
18+
import { ConnectedDevEnv, getConnectedDevEnv, getDevfileLocation } from './model'
1919
import * as codecatalyst from './model'
2020

2121
const getStartedCommand = Commands.register(
@@ -146,8 +146,11 @@ export class CodeCatalystRootNode implements RootNode {
146146

147147
private async getDevEnv() {
148148
try {
149-
const client = await createClientFactory(this.authProvider)()
150-
return client.connected ? await getConnectedDevEnv(client) : undefined
149+
await this.authProvider.restore()
150+
const conn = this.authProvider.activeConnection
151+
const client = conn !== undefined ? await createClient(conn) : undefined
152+
153+
return client !== undefined ? await getConnectedDevEnv(client) : undefined
151154
} catch (err) {
152155
getLogger().warn(`codecatalyst: failed to get Dev Environment: ${UnknownError.cast(err).message}`)
153156
}

src/codecatalyst/model.ts

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,10 @@ import {
1111
CodeCatalystClient,
1212
DevEnvironment,
1313
CodeCatalystRepo,
14-
ConnectedCodeCatalystClient,
15-
createClient,
1614
getCodeCatalystConfig,
1715
} from '../shared/clients/codecatalystClient'
1816
import { DevEnvClient } from '../shared/clients/devenvClient'
1917
import { getLogger } from '../shared/logger'
20-
import { CodeCatalystAuthenticationProvider } from './auth'
2118
import { AsyncCollection, toCollection } from '../shared/utilities/asyncCollection'
2219
import { getCodeCatalystSpaceName, getCodeCatalystProjectName } from '../shared/vscode/env'
2320
import { writeFile } from 'fs-extra'
@@ -95,17 +92,13 @@ export function getCodeCatalystSsmEnv(region: string, ssmPath: string, devenv: D
9592
}
9693

9794
export function createCodeCatalystEnvProvider(
98-
client: ConnectedCodeCatalystClient,
95+
client: CodeCatalystClient,
9996
ssmPath: string,
10097
devenv: DevEnvironment,
10198
useSshAgent: boolean = true
10299
): EnvProvider {
103100
return async () => {
104-
if (!client.connected) {
105-
throw new Error('Cannot provide environment variables when not logged-in')
106-
}
107-
108-
await cacheBearerToken(client.token, devenv.id)
101+
await cacheBearerToken(await client.getBearerToken(), devenv.id)
109102
const vars = getCodeCatalystSsmEnv(client.regionCode, ssmPath, devenv)
110103

111104
return useSshAgent ? { [SSH_AGENT_SOCKET_VARIABLE]: await startSshAgent(), ...vars } : vars
@@ -150,32 +143,13 @@ export function getHostNameFromEnv(env: DevEnvironmentId): string {
150143
return `${HOST_NAME_PREFIX}${env.id}`
151144
}
152145

153-
export function createClientFactory(
154-
authProvider: CodeCatalystAuthenticationProvider
155-
): () => Promise<CodeCatalystClient> {
156-
return async () => {
157-
await authProvider.restore()
158-
const client = await createClient()
159-
const conn = authProvider.activeConnection
160-
161-
if (conn) {
162-
// TODO(sijaden): add global caching module
163-
return client.setCredentials(async () => (await conn.getToken()).accessToken)
164-
} else {
165-
// TODO: show prompt/notification to use Builder ID
166-
}
167-
168-
return client
169-
}
170-
}
171-
172146
export interface ConnectedDevEnv {
173147
readonly summary: DevEnvironment
174148
readonly devenvClient: DevEnvClient
175149
}
176150

177151
export async function getConnectedDevEnv(
178-
codeCatalystClient: ConnectedCodeCatalystClient,
152+
codeCatalystClient: CodeCatalystClient,
179153
devenvClient = new DevEnvClient()
180154
): Promise<ConnectedDevEnv | undefined> {
181155
const devEnvId = devenvClient.id
@@ -211,7 +185,7 @@ interface DevEnvConnection {
211185
}
212186

213187
export async function prepareDevEnvConnection(
214-
client: ConnectedCodeCatalystClient,
188+
client: CodeCatalystClient,
215189
{ id, org, project }: DevEnvironmentId,
216190
{ topic, timeout }: { topic?: string; timeout?: Timeout } = {}
217191
): Promise<DevEnvConnection> {
@@ -253,7 +227,7 @@ export async function prepareDevEnvConnection(
253227
* @param targetPath vscode workspace (default: "/projects/[repo]")
254228
*/
255229
export async function openDevEnv(
256-
client: ConnectedCodeCatalystClient,
230+
client: CodeCatalystClient,
257231
devenv: DevEnvironmentId,
258232
targetPath?: string
259233
): Promise<void> {
@@ -338,7 +312,7 @@ export async function getDevfileLocation(client: DevEnvClient, root?: vscode.Uri
338312
* Given a collection of CodeCatalyst repos, try to find a corresponding devenv, if any
339313
*/
340314
export function associateDevEnv(
341-
client: ConnectedCodeCatalystClient,
315+
client: CodeCatalystClient,
342316
repos: AsyncCollection<CodeCatalystRepo>
343317
): AsyncCollection<CodeCatalystRepo & { devEnv?: DevEnvironment }> {
344318
return toCollection(async function* () {

0 commit comments

Comments
 (0)