Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/core/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -414,5 +414,6 @@
"AWS.toolkit.lambda.walkthrough.step1.title": "Iterate locally",
"AWS.toolkit.lambda.walkthrough.step1.description": "Locally test and debug your code.",
"AWS.toolkit.lambda.walkthrough.step2.title": "Deploy to the cloud",
"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)"
"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)",
"AWS.toolkit.lambda.serverlessLand.quickpickTitle": "Create Lambda Application from template"
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@
</checkbox>
</div>
</checklist>
<checkbox class="theme-picker-link" when-checked="command:aws.lambda.createNewSamApp" checked-on="false">
<checkbox class="theme-picker-link" when-checked="command:aws.toolkit.lambda.createServerlessLandProject" checked-on="false">
See more application example...
</checkbox>
5 changes: 4 additions & 1 deletion packages/core/src/awsService/appBuilder/activation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { ResourceNode } from './explorer/nodes/resourceNode'
import { getSyncWizard, runSync } from '../../shared/sam/sync'
import { getDeployWizard, runDeploy } from '../../shared/sam/deploy'
import { DeployTypeWizard } from './wizards/deployTypeWizard'

import { createNewServerlessLandProject } from './serverlessLand/main'
export const templateToOpenAppComposer = 'aws.toolkit.appComposer.templateToOpenOnStart'

/**
Expand Down Expand Up @@ -200,6 +200,9 @@ async function registerAppBuilderCommands(context: ExtContext): Promise<void> {
await runSync('infra', arg, undefined, choices.syncParam)
}
}
}),
Commands.register({ id: 'aws.toolkit.lambda.createServerlessLandProject', autoconnect: false }, async () => {
await createNewServerlessLandProject(context)
})
)
}
82 changes: 82 additions & 0 deletions packages/core/src/awsService/appBuilder/serverlessLand/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*!
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

import * as nls from 'vscode-nls'
const localize = nls.loadMessageBundle()
import * as path from 'path'
import { getTelemetryReason, getTelemetryResult } from '../../../shared/errors'
import { getLogger } from '../../../shared/logger/logger'
import globals from '../../../shared/extensionGlobals'
import { checklogs } from '../../../shared/localizedText'
import { Result, telemetry } from '../../../shared/telemetry/telemetry'
import { CreateServerlessLandWizard } from './wizard'
import { ExtContext } from '../../../shared/extensions'
import { addFolderToWorkspace } from '../../../shared/utilities/workspaceUtils'

export const readmeFile: string = 'README.md'

/**
* Creates a new Serverless Land project using the provided extension context
* @param extContext Extension context containing AWS credentials and region information
* @returns Promise that resolves when the project creation is complete
*
* This function:
* 1. Validates AWS credentials and regions
* 2. Launches the Serverless Land project creation wizard
* 3. Creates the project structure
* 4. Adds the project folder to the workspace
* 5. Opens the README.md file if available
* 6. Handles errors and emits telemetry
*/
export async function createNewServerlessLandProject(extContext: ExtContext): Promise<void> {
const awsContext = extContext.awsContext
let createResult: Result = 'Succeeded'
let reason: string | undefined

try {
const credentials = await awsContext.getCredentials()
const defaultRegion = awsContext.getCredentialDefaultRegion()

// Launch the project creation wizard
const config = await new CreateServerlessLandWizard({
credentials,
defaultRegion,
}).run()
if (!config) {
createResult = 'Cancelled'
reason = 'userCancelled'
return
}

// Add the project folder to the workspace
await addFolderToWorkspace(
{
uri: config.location,
name: path.basename(config.location.fsPath),
},
true
)
} catch (err) {
createResult = getTelemetryResult(err)
reason = getTelemetryReason(err)

globals.outputChannel.show(true)
getLogger().error(
localize(
'AWS.serverlessland.initWizard.general.error',
'Error creating new Serverless Land Application. {0}',
checklogs()
)
)
getLogger().error('Error creating new Serverless Land Application: %O', err as Error)
} finally {
// add telemetry
// TODO: Will add telemetry once the implementation gets completed
telemetry.sam_init.emit({
result: createResult,
reason: reason,
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"patterns": {
"s3-lambda-resizing-sam": {
"name": "Resizing image",
"description": "Lambda, S3 • Python, Javascript, Java, .NET • SAM",
"runtimes": [
{
"id": "python",
"name": "Python"
},
{
"id": "javascript",
"name": "Javascript"
},
{
"id": "dotnet",
"name": "Dotnet"
},
{
"id": "java",
"name": "Java"
}
],
"iac": [
{
"id": "sam",
"name": "SAM"
}
]
},
"apigw-rest-api-lambda-sam": {
"name": "Rest API",
"description": "Lambda, API Gateway • Python, Javascript, Java, .NET • SAM",
"runtimes": [
{
"id": "python",
"name": "Python"
},
{
"id": "javascript",
"name": "Javascript"
},
{
"id": "dotnet",
"name": "Dotnet"
},
{
"id": "java",
"name": "Java"
}
],
"iac": [
{
"id": "sam",
"name": "AWS SAM"
}
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*!
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
import * as nodefs from 'fs' // eslint-disable-line no-restricted-imports
import { ToolkitError } from '../../../shared/errors'

interface IaC {
id: string
name: string
}
interface Runtime {
id: string
name: string
version: string
}
interface PatternData {
name: string
description: string
runtimes: Runtime[]
iac: IaC[]
}

export interface ProjectMetadata {
patterns: Record<string, PatternData>
}

/**
* Manages metadata for serverless application patterns
*/

export class MetadataManager {
private static instance: MetadataManager
private metadata: ProjectMetadata | undefined

private constructor() {}

public static getInstance(): MetadataManager {
if (!MetadataManager.instance) {
MetadataManager.instance = new MetadataManager()
}
return MetadataManager.instance
}

/**
* Loads metadata from a JSON file
* @param metadataPath Path to the metadata JSON file
* @returns Promise containing the parsed ProjectMetadata
*/
public async loadMetadata(metadataPath: string): Promise<ProjectMetadata> {
try {
if (!this.metadata) {
const metadataContent = nodefs.readFileSync(metadataPath, { encoding: 'utf-8' })
const parseMetadata = JSON.parse(metadataContent) as ProjectMetadata
this.metadata = parseMetadata
}
return this.metadata
} catch (err) {
throw new ToolkitError(`Failed to load metadata: ${err instanceof Error ? err.message : String(err)}`)
}
}

/**
* Retrieves available patterns with their descriptions
* @returns Array of pattern objects containing labels and descriptions
*/
public getPatterns(): { label: string; description?: string }[] {
if (!this.metadata) {
return []
}
return Object.entries(this.metadata.patterns).map(([patternName, patternData]) => {
let description: string | undefined = undefined
if (typeof patternData === 'string') {
description = patternData
} else if (Array.isArray(patternData)) {
// If description is an array, join it into a single string
description = patternData.join(' ')
}
if (!patternData || !patternData.name) {
return {
label: patternName,
description: description || 'No description available',
}
}
return {
label: patternName,
description: patternData.description,
}
})
}

/**
* Gets available runtimes for a specific pattern
* @param pattern The pattern name to get runtimes for
* @returns Array of runtime options with labels
*/
public getRuntimes(pattern: string): { label: string }[] {
const patternData = this.metadata?.patterns?.[pattern]
if (!patternData || !patternData.runtimes) {
return []
}
return patternData.runtimes.map((runtime) => ({
label: runtime.name,
}))
}

/**
* Gets available Infrastructure as Code options for a specific pattern
* @param pattern The pattern name to get IaC options for
* @returns Array of IaC options with labels
*/
public getIacOptions(pattern: string): { label: string }[] {
const patternData = this.metadata?.patterns?.[pattern]
if (!patternData || !patternData.iac) {
return []
}
return patternData.iac.map((iac) => ({
label: iac.name,
}))
}
}
Loading
Loading