Skip to content

Commit 9e2ebad

Browse files
author
Vandita Patidar
committed
Building Quick Pick structure
1 parent e63ca97 commit 9e2ebad

File tree

7 files changed

+476
-2
lines changed

7 files changed

+476
-2
lines changed

packages/core/package.nls.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,5 +414,6 @@
414414
"AWS.toolkit.lambda.walkthrough.step1.title": "Iterate locally",
415415
"AWS.toolkit.lambda.walkthrough.step1.description": "Locally test and debug your code.",
416416
"AWS.toolkit.lambda.walkthrough.step2.title": "Deploy to the cloud",
417-
"AWS.toolkit.lambda.walkthrough.step2.description": "Test your application in the cloud from within VS Code. \n\nNote: The AWS CLI and the SAM CLI require AWS Credentials to interact with the cloud. For information on setting up your credentials, see [Authentication and access credentials](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html). \n\n[Configure credentials](command:aws.toolkit.lambda.walkthrough.credential)"
417+
"AWS.toolkit.lambda.walkthrough.step2.description": "Test your application in the cloud from within VS Code. \n\nNote: The AWS CLI and the SAM CLI require AWS Credentials to interact with the cloud. For information on setting up your credentials, see [Authentication and access credentials](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html). \n\n[Configure credentials](command:aws.toolkit.lambda.walkthrough.credential)",
418+
"AWS.toolkit.lambda.serverlessLand.quickpickTitle": "Create Lambda application from template"
418419
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { ResourceNode } from './explorer/nodes/resourceNode'
2323
import { getSyncWizard, runSync } from '../../shared/sam/sync'
2424
import { getDeployWizard, runDeploy } from '../../shared/sam/deploy'
2525
import { DeployTypeWizard } from './wizards/deployTypeWizard'
26-
26+
import { createNewServerlessLandProject } from './serverlessLand'
2727
export const templateToOpenAppComposer = 'aws.toolkit.appComposer.templateToOpenOnStart'
2828

2929
/**
@@ -200,6 +200,9 @@ async function registerAppBuilderCommands(context: ExtContext): Promise<void> {
200200
await runSync('infra', arg, undefined, choices.syncParam)
201201
}
202202
}
203+
}),
204+
Commands.register({ id: 'aws.toolkit.lambda.serverlessLand', autoconnect: false }, async () => {
205+
await createNewServerlessLandProject(context)
203206
})
204207
)
205208
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
{
2+
"patterns": {
3+
"s3-lambda-resizing-sam": {
4+
"name": "Resizing image",
5+
"description": "Lambda, S3 • Python, Javascript, Java, .NET • SAM",
6+
"runtimes": [
7+
{
8+
"id": "python",
9+
"name": "Python"
10+
},
11+
{
12+
"id": "javascript",
13+
"name": "Javascript"
14+
},
15+
{
16+
"id": "dotnet",
17+
"name": "Dotnet"
18+
},
19+
{
20+
"id": "java",
21+
"name": "Java"
22+
}
23+
],
24+
"iac": [
25+
{
26+
"id": "sam",
27+
"name": "SAM"
28+
}
29+
]
30+
},
31+
"apigw-rest-api-lambda-sam": {
32+
"name": "Rest API",
33+
"description": "Lambda, API Gateway • Python, Javascript, Java, .NET • SAM",
34+
"runtimes": [
35+
{
36+
"id": "python",
37+
"name": "Python"
38+
},
39+
{
40+
"id": "javascript",
41+
"name": "Javascript"
42+
},
43+
{
44+
"id": "dotnet",
45+
"name": "Dotnet"
46+
},
47+
{
48+
"id": "java",
49+
"name": "Java"
50+
}
51+
],
52+
"iac": [
53+
{
54+
"id": "sam",
55+
"name": "AWS SAM"
56+
}
57+
]
58+
}
59+
}
60+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
import * as nodefs from 'fs' // eslint-disable-line no-restricted-imports
6+
import { ToolkitError } from '../../../shared/errors'
7+
8+
interface IaC {
9+
id: string
10+
name: string
11+
}
12+
interface Runtime {
13+
id: string
14+
name: string
15+
version: string
16+
}
17+
interface PatternData {
18+
name: string
19+
description: string
20+
runtimes: Runtime[]
21+
iac: IaC[]
22+
}
23+
24+
export interface ProjectMetadata {
25+
patterns: Record<string, PatternData>
26+
}
27+
28+
/**
29+
* Manages metadata for serverless application patterns
30+
* Implements Singleton pattern to ensure single instance across the application
31+
*/
32+
33+
export class MetadataManager {
34+
private static instance: MetadataManager
35+
private metadata: ProjectMetadata | undefined
36+
37+
private constructor() {}
38+
39+
public static getInstance(): MetadataManager {
40+
if (!MetadataManager.instance) {
41+
MetadataManager.instance = new MetadataManager()
42+
}
43+
return MetadataManager.instance
44+
}
45+
46+
/**
47+
* Loads metadata from a JSON file
48+
* @param metadataPath Path to the metadata JSON file
49+
* @returns Promise containing the parsed ProjectMetadata
50+
*/
51+
public async loadMetadata(metadataPath: string): Promise<ProjectMetadata> {
52+
try {
53+
if (!this.metadata) {
54+
const metadataContent = nodefs.readFileSync(metadataPath, { encoding: 'utf-8' })
55+
const parseMetadata = JSON.parse(metadataContent) as ProjectMetadata
56+
this.metadata = parseMetadata
57+
}
58+
return this.metadata
59+
} catch (err) {
60+
throw new ToolkitError(`Failed to load metadata: ${err instanceof Error ? err.message : String(err)}`)
61+
}
62+
}
63+
64+
/**
65+
* Retrieves available patterns with their descriptions
66+
* @returns Array of pattern objects containing labels and descriptions
67+
*/
68+
public getPatterns(): { label: string; description?: string }[] {
69+
if (!this.metadata) {
70+
return []
71+
}
72+
return Object.entries(this.metadata.patterns).map(([patternName, patternData]) => {
73+
let description: string | undefined = undefined
74+
if (typeof patternData === 'string') {
75+
description = patternData
76+
} else if (Array.isArray(patternData)) {
77+
// If description is an array, join it into a single string
78+
description = patternData.join(' ')
79+
}
80+
if (!patternData || !patternData.name) {
81+
return {
82+
label: patternName,
83+
description: description || 'No description available',
84+
}
85+
}
86+
return {
87+
label: patternName,
88+
description: patternData.description,
89+
}
90+
})
91+
}
92+
93+
/**
94+
* Gets available runtimes for a specific pattern
95+
* @param pattern The pattern name to get runtimes for
96+
* @returns Array of runtime options with labels
97+
*/
98+
public getRuntimes(pattern: string): { label: string }[] {
99+
const patternData = this.metadata?.patterns?.[pattern]
100+
if (!patternData || !patternData.runtimes) {
101+
return []
102+
}
103+
return patternData.runtimes.map((runtime) => ({
104+
label: runtime.name,
105+
}))
106+
}
107+
108+
/**
109+
* Gets available Infrastructure as Code options for a specific pattern
110+
* @param pattern The pattern name to get IaC options for
111+
* @returns Array of IaC options with labels
112+
*/
113+
public getIacOptions(pattern: string): { label: string }[] {
114+
const patternData = this.metadata?.patterns?.[pattern]
115+
if (!patternData || !patternData.iac) {
116+
return []
117+
}
118+
return patternData.iac.map((iac) => ({
119+
label: iac.name,
120+
}))
121+
}
122+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import * as nls from 'vscode-nls'
7+
const localize = nls.loadMessageBundle()
8+
import * as path from 'path'
9+
import { getTelemetryReason, getTelemetryResult } from '../../shared/errors'
10+
import { RegionProvider } from '../../shared/regions/regionProvider'
11+
import { getLogger } from '../../shared/logger/logger'
12+
import globals from '../../shared/extensionGlobals'
13+
import { checklogs } from '../../shared/localizedText'
14+
import { Result, telemetry } from '../../shared/telemetry/telemetry'
15+
import { CreateServerlessLandWizard } from '../appBuilder/wizards/serverlessLandWizard'
16+
import { ExtContext } from '../../shared/extensions'
17+
import { addFolderToWorkspace } from '../../shared/utilities/workspaceUtils'
18+
19+
export const readmeFile: string = 'README.md'
20+
21+
/**
22+
* Creates a new Serverless Land project using the provided extension context
23+
* @param extContext Extension context containing AWS credentials and region information
24+
* @returns Promise that resolves when the project creation is complete
25+
*
26+
* This function:
27+
* 1. Validates AWS credentials and regions
28+
* 2. Launches the Serverless Land project creation wizard
29+
* 3. Creates the project structure
30+
* 4. Adds the project folder to the workspace
31+
* 5. Opens the README.md file if available
32+
* 6. Handles errors and emits telemetry
33+
*/
34+
export async function createNewServerlessLandProject(extContext: ExtContext): Promise<void> {
35+
const awsContext = extContext.awsContext
36+
const regionProvider: RegionProvider = extContext.regionProvider
37+
let createResult: Result = 'Succeeded'
38+
let reason: string | undefined
39+
40+
try {
41+
const credentials = await awsContext.getCredentials()
42+
const schemaRegions = regionProvider
43+
.getRegions()
44+
.filter((r) => regionProvider.isServiceInRegion('schemas', r.id))
45+
const defaultRegion = awsContext.getCredentialDefaultRegion()
46+
47+
// Launch the project creation wizard
48+
const config = await new CreateServerlessLandWizard({
49+
credentials,
50+
schemaRegions,
51+
defaultRegion,
52+
}).run()
53+
if (!config) {
54+
createResult = 'Cancelled'
55+
reason = 'userCancelled'
56+
return
57+
}
58+
59+
// Add the project folder to the workspace
60+
await addFolderToWorkspace(
61+
{
62+
uri: config.location,
63+
name: path.basename(config.location.fsPath),
64+
},
65+
true
66+
)
67+
} catch (err) {
68+
createResult = getTelemetryResult(err)
69+
reason = getTelemetryReason(err)
70+
71+
globals.outputChannel.show(true)
72+
getLogger().error(
73+
localize(
74+
'AWS.serverlessland.initWizard.general.error',
75+
'Error creating new SAM Application. {0}',
76+
checklogs()
77+
)
78+
)
79+
getLogger().error('Error creating new Serverless Land Application: %O', err as Error)
80+
} finally {
81+
// add telemetry
82+
// TODO: Will add telemetry once the implementation gets completed
83+
telemetry.sam_init.emit({
84+
result: createResult,
85+
reason: reason,
86+
})
87+
}
88+
}

0 commit comments

Comments
 (0)