Skip to content

Commit 7201d87

Browse files
author
Vandita Patidar
committed
Building Quick Pick structure
1 parent eccc7bd commit 7201d87

File tree

6 files changed

+195
-76
lines changed

6 files changed

+195
-76
lines changed

aws-toolkit-vscode.code-workspace

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,50 @@
11
{
2-
"folders": [
3-
{
4-
"path": "."
5-
},
6-
{
7-
"path": "packages/toolkit"
8-
},
9-
{
10-
"path": "packages/core"
11-
},
12-
{
13-
"path": "packages/amazonq"
14-
}
15-
],
16-
"settings": {
17-
"typescript.tsdk": "node_modules/typescript/lib"
18-
}
19-
}
2+
"folders": [
3+
{
4+
"path": ".",
5+
},
6+
{
7+
"path": "packages/toolkit",
8+
},
9+
{
10+
"path": "packages/core",
11+
},
12+
{
13+
"path": "packages/amazonq",
14+
},
15+
],
16+
"settings": {
17+
"typescript.tsdk": "node_modules/typescript/lib",
18+
},
19+
"launch": {
20+
"configurations": [
21+
{
22+
"type": "aws-sam",
23+
"request": "direct-invoke",
24+
"name": "core:src/awsService/appBuilder/serverlessLand.getProjectUri (nodejs14.x)",
25+
"invokeTarget": {
26+
"target": "code",
27+
"projectRoot": "/Users/vanditap/src/github.com/aws-toolkit-vscode/packages/core",
28+
"lambdaHandler": "src/awsService/appBuilder/serverlessLand.getProjectUri",
29+
},
30+
"lambda": {
31+
"runtime": "nodejs14.x",
32+
"payload": {},
33+
"environmentVariables": {},
34+
},
35+
},
36+
{
37+
"name": "Test Lint",
38+
"type": "node",
39+
"request": "launch",
40+
"program": "${workspaceFolder}/scripts/lint/testLint.ts",
41+
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
42+
"preLaunchTask": "build",
43+
"presentation": {
44+
"group": "7_TestLint",
45+
"order": 1,
46+
},
47+
},
48+
],
49+
},
50+
}

packages/core/scripts/build/copyFiles.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ const tasks: CopyTask[] = [
4444
target: path.join('../../node_modules', 'aws-ssm-document-language-service', 'dist', 'server.js.map'),
4545
destination: path.join('src', 'ssmDocument', 'ssm', 'server.js.map'),
4646
},
47+
{
48+
target: path.join('../core', 'src', 'awsService', 'appBuilder', 'serverlessLand', 'metadata.json'),
49+
destination: path.join('src', 'awsService', 'appBuilder', 'serverlessLand', 'metadata.json'),
50+
},
4751
]
4852

4953
function copy(task: CopyTask): void {

packages/core/src/awsService/appBuilder/serverlessLand/main.ts

Lines changed: 88 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,22 @@
66
import * as nls from 'vscode-nls'
77
const localize = nls.loadMessageBundle()
88
import * as path from 'path'
9+
import * as vscode from 'vscode'
910
import { getTelemetryReason, getTelemetryResult } from '../../../shared/errors'
1011
import { getLogger } from '../../../shared/logger/logger'
1112
import globals from '../../../shared/extensionGlobals'
1213
import { checklogs } from '../../../shared/localizedText'
1314
import { Result, telemetry } from '../../../shared/telemetry/telemetry'
14-
import { CreateServerlessLandWizard } from './wizard'
15+
import { CreateServerlessLandWizardForm, CreateServerlessLandWizard } from './wizard'
1516
import { ExtContext } from '../../../shared/extensions'
1617
import { addFolderToWorkspace } from '../../../shared/utilities/workspaceUtils'
18+
import { ToolkitError } from '../../../shared/errors'
19+
import { fileExists } from '../../../shared/filesystemUtilities'
20+
import { getPattern } from '../../../shared/utilities/downloadPatterns'
1721

1822
export const readmeFile: string = 'README.md'
23+
const serverlessLandOwner = 'aws-samples'
24+
const serverlessLandRepo = 'serverless-patterns'
1925

2026
/**
2127
* Creates a new Serverless Land project using the provided extension context
@@ -31,30 +37,24 @@ export const readmeFile: string = 'README.md'
3137
* 6. Handles errors and emits telemetry
3238
*/
3339
export async function createNewServerlessLandProject(extContext: ExtContext): Promise<void> {
34-
const awsContext = extContext.awsContext
3540
let createResult: Result = 'Succeeded'
3641
let reason: string | undefined
3742

3843
try {
39-
const credentials = await awsContext.getCredentials()
40-
const defaultRegion = awsContext.getCredentialDefaultRegion()
41-
4244
// Launch the project creation wizard
43-
const config = await new CreateServerlessLandWizard({
44-
credentials,
45-
defaultRegion,
46-
}).run()
45+
const config = await launchProjectCreationWizard(extContext)
4746
if (!config) {
4847
createResult = 'Cancelled'
4948
reason = 'userCancelled'
5049
return
5150
}
5251

53-
// Add the project folder to the workspace
52+
await downloadPatternCode(config)
53+
await openReadmeFile(config)
5454
await addFolderToWorkspace(
5555
{
56-
uri: config.location,
57-
name: path.basename(config.location.fsPath),
56+
uri: vscode.Uri.joinPath(config.location, config.name),
57+
name: path.basename(config.name),
5858
},
5959
true
6060
)
@@ -80,3 +80,79 @@ export async function createNewServerlessLandProject(extContext: ExtContext): Pr
8080
})
8181
}
8282
}
83+
84+
async function launchProjectCreationWizard(
85+
extContext: ExtContext
86+
): Promise<CreateServerlessLandWizardForm | undefined> {
87+
const awsContext = extContext.awsContext
88+
const credentials = await awsContext.getCredentials()
89+
const defaultRegion = awsContext.getCredentialDefaultRegion()
90+
91+
return new CreateServerlessLandWizard({
92+
credentials,
93+
defaultRegion,
94+
}).run()
95+
}
96+
97+
async function downloadPatternCode(config: CreateServerlessLandWizardForm): Promise<void> {
98+
const assetName = config.assetName + '.zip'
99+
const location = vscode.Uri.joinPath(config.location, config.name)
100+
try {
101+
await getPattern(serverlessLandOwner, serverlessLandRepo, assetName, location, true)
102+
} catch (error) {
103+
if (error instanceof ToolkitError) {
104+
throw error
105+
}
106+
throw new ToolkitError(`Failed to download pattern: ${error}`)
107+
}
108+
}
109+
110+
async function openReadmeFile(config: CreateServerlessLandWizardForm): Promise<void> {
111+
try {
112+
const projectUri = await getProjectUri(config, readmeFile)
113+
if (!projectUri) {
114+
getLogger().warn('Project URI not found when trying to open README')
115+
return
116+
}
117+
118+
const readmeUri = vscode.Uri.file(path.join(path.dirname(projectUri.fsPath), readmeFile))
119+
if (!(await fileExists(readmeUri.fsPath))) {
120+
getLogger().warn(
121+
localize('AWS.serverlessLand.readme.notFound', 'README.md file not found in the project directory')
122+
)
123+
return
124+
}
125+
126+
try {
127+
const document = await vscode.workspace.openTextDocument(readmeUri)
128+
await vscode.window.showTextDocument(document, { preview: true })
129+
} catch (err) {
130+
getLogger().error(`Failed to open README file: ${err}`)
131+
throw new ToolkitError('Failed to open README file')
132+
}
133+
} catch (err) {
134+
getLogger().error(`Error in openReadmeFile: ${err}`)
135+
throw new ToolkitError('Error processing README file')
136+
}
137+
}
138+
139+
async function getProjectUri(
140+
config: Pick<CreateServerlessLandWizardForm, 'location' | 'name'>,
141+
file: string
142+
): Promise<vscode.Uri | undefined> {
143+
if (!file) {
144+
throw Error('expected "file" parameter to have at least one item')
145+
}
146+
const cfnTemplatePath = path.resolve(config.location.fsPath, config.name, file)
147+
if (await fileExists(cfnTemplatePath)) {
148+
return vscode.Uri.file(cfnTemplatePath)
149+
}
150+
void vscode.window.showWarningMessage(
151+
localize(
152+
'AWS.serverlessLand.initWizard.source.error.notFound',
153+
'Project created successfully, but {0} file not found: {1}',
154+
file!,
155+
cfnTemplatePath!
156+
)
157+
)
158+
}

packages/core/src/awsService/appBuilder/serverlessLand/metadata.json

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,56 +3,52 @@
33
"s3-lambda-resizing-sam": {
44
"name": "Resizing image",
55
"description": "Lambda, S3 • Python, Javascript, Java, .NET • SAM",
6-
"runtimes": [
6+
"implementation": [
77
{
8-
"id": "python",
9-
"name": "Python"
8+
"iac": "sam",
9+
"runtime": "python",
10+
"assetName": "s3-lambda-resizing-python"
1011
},
1112
{
12-
"id": "javascript",
13-
"name": "Javascript"
13+
"iac": "sam",
14+
"runtime": "javascript",
15+
"assetName": "s3-lambda"
1416
},
1517
{
16-
"id": "dotnet",
17-
"name": "Dotnet"
18+
"iac": "sam",
19+
"runtime": "java",
20+
"assetName": "s3-lambda-resizing-java"
1821
},
1922
{
20-
"id": "java",
21-
"name": "Java"
22-
}
23-
],
24-
"iac": [
25-
{
26-
"id": "sam",
27-
"name": "SAM"
23+
"iac": "sam",
24+
"runtime": "dotnet",
25+
"assetName": "s3-lambda-dotnet"
2826
}
2927
]
3028
},
3129
"apigw-rest-api-lambda-sam": {
3230
"name": "Rest API",
3331
"description": "Lambda, API Gateway • Python, Javascript, Java, .NET • SAM",
34-
"runtimes": [
32+
"implementation": [
3533
{
36-
"id": "python",
37-
"name": "Python"
34+
"iac": "sam",
35+
"runtime": "python",
36+
"assetName": "apigw-rest-api-lambda-python"
3837
},
3938
{
40-
"id": "javascript",
41-
"name": "Javascript"
39+
"iac": "sam",
40+
"runtime": "javascript",
41+
"assetName": "apigw-rest-api-lambda-node"
4242
},
4343
{
44-
"id": "dotnet",
45-
"name": "Dotnet"
44+
"iac": "sam",
45+
"runtime": "java",
46+
"assetName": "apigw-rest-api-lambda-java"
4647
},
4748
{
48-
"id": "java",
49-
"name": "Java"
50-
}
51-
],
52-
"iac": [
53-
{
54-
"id": "sam",
55-
"name": "AWS SAM"
49+
"iac": "sam",
50+
"runtime": "dotnet",
51+
"assetName": "apigw-rest-api-lambda-dotnet"
5652
}
5753
]
5854
}

packages/core/src/awsService/appBuilder/serverlessLand/metadataManager.ts

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,15 @@
55
import * as nodefs from 'fs' // eslint-disable-line no-restricted-imports
66
import { ToolkitError } from '../../../shared/errors'
77

8-
interface IaC {
9-
id: string
10-
name: string
11-
}
12-
interface Runtime {
13-
id: string
14-
name: string
15-
version: string
8+
interface Implementation {
9+
iac: string
10+
runtime: string
11+
assetName: string
1612
}
1713
interface PatternData {
1814
name: string
1915
description: string
20-
runtimes: Runtime[]
21-
iac: IaC[]
16+
implementation: Implementation[]
2217
}
2318

2419
export interface ProjectMetadata {
@@ -97,11 +92,12 @@ export class MetadataManager {
9792
*/
9893
public getRuntimes(pattern: string): { label: string }[] {
9994
const patternData = this.metadata?.patterns?.[pattern]
100-
if (!patternData || !patternData.runtimes) {
95+
if (!patternData || !patternData.implementation) {
10196
return []
10297
}
103-
return patternData.runtimes.map((runtime) => ({
104-
label: runtime.name,
98+
const uniqueRuntimes = new Set(patternData.implementation.map((item) => item.runtime))
99+
return Array.from(uniqueRuntimes).map((runtime) => ({
100+
label: runtime,
105101
}))
106102
}
107103

@@ -112,11 +108,22 @@ export class MetadataManager {
112108
*/
113109
public getIacOptions(pattern: string): { label: string }[] {
114110
const patternData = this.metadata?.patterns?.[pattern]
115-
if (!patternData || !patternData.iac) {
111+
if (!patternData || !patternData.implementation) {
116112
return []
117113
}
118-
return patternData.iac.map((iac) => ({
119-
label: iac.name,
114+
const uniqueIaCs = new Set(patternData.implementation.map((item) => item.iac))
115+
return Array.from(uniqueIaCs).map((iac) => ({
116+
label: iac,
120117
}))
121118
}
119+
public getAssetName(selectedPattern: string, selectedRuntime: string, selectedIaC: string): string {
120+
const patternData = this.metadata?.patterns?.[selectedPattern]
121+
if (!patternData || !patternData.implementation) {
122+
return ''
123+
}
124+
const matchingImplementation = patternData.implementation.find(
125+
(impl) => impl.runtime === selectedRuntime && impl.iac === selectedIaC
126+
)
127+
return matchingImplementation?.assetName ?? ''
128+
}
122129
}

packages/core/src/awsService/appBuilder/serverlessLand/wizard.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export interface CreateServerlessLandWizardForm {
2020
pattern: string
2121
runtime: string
2222
iac: string
23+
assetName: string
2324
}
2425

2526
/**
@@ -133,6 +134,9 @@ export class CreateServerlessLandWizard extends Wizard<CreateServerlessLandWizar
133134
}
134135
const selectedIac = iacResult
135136

137+
// Get Asset Name based on selected Pattern, Runtime and IaC
138+
const assetName = this.metadataManager.getAssetName(selectedPattern, selectedRuntime, selectedIac)
139+
136140
// Create and show location picker
137141
const locationPicker = createFolderPrompt(vscode.workspace.workspaceFolders ?? [], {
138142
title: 'Select Project Location',
@@ -173,6 +177,7 @@ export class CreateServerlessLandWizard extends Wizard<CreateServerlessLandWizar
173177
pattern: selectedPattern,
174178
runtime: selectedRuntime,
175179
iac: selectedIac,
180+
assetName: assetName,
176181
}
177182
} catch (err) {
178183
throw new ToolkitError(`Failed to run wizard: ${err instanceof Error ? err.message : String(err)}`)

0 commit comments

Comments
 (0)