

亚马逊 CodeCatalyst 不再向新买家开放。现有客户可以继续正常使用该服务。有关更多信息，请参阅 [如何从中迁移 CodeCatalyst](migration.md)。

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 教程：部署无服务器应用程序
<a name="deploy-tut-lambda"></a>

在本教程中，您将学习如何使用工作流程构建、测试和部署无服务器应用程序作为 CloudFormation 堆栈。

本教程中的应用程序是一个输出“Hello World”消息的简单 Web 应用程序。它由一个 AWS Lambda 函数和一个 Amazon API Gateway 组成，你可以使用 [AWS Serverless Application Model (AWS SAM)](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) 来构建它，后者是的扩展[CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html)。

**Topics**
+ [

## 先决条件
](#deploy-tut-lambda-cfn-prereqs)
+ [

## 步骤 1：创建源存储库
](#deploy-tut-lambda-cfn-source)
+ [

## 步骤 2：创建 AWS 角色
](#deploy-tut-lambda-cfn-roles)
+ [

## 步骤 3：将 AWS 角色添加到 CodeCatalyst
](#deploy-tut-lambda-cfn-roles-add)
+ [

## 步骤 4：创建 Amazon S3 存储桶
](#deploy-tut-lambda-cfn-s3)
+ [

## 步骤 5：添加源文件
](#deploy-tut-lambda-cfn-files)
+ [

## 步骤 6：创建并运行工作流
](#deploy-tut-lambda-cfn-workflow)
+ [

## 步骤 7：进行更改
](#deploy-tut-lambda-cfn-change)
+ [

## 清理
](#deploy-tut-lambda-cfn-clean-up)

## 先决条件
<a name="deploy-tut-lambda-cfn-prereqs"></a>

开始前的准备工作：
+ 你需要一个带有关联 AWS 账户的 CodeCatalyst **空间**。有关更多信息，请参阅 [创建空间](spaces-create.md)。
+ 在您的空间中，您需要一个空项目，其名称为：

  ```
  codecatalyst-cfn-project
  ```

  使用**从头开始**选项来创建此项目。

  有关更多信息，请参阅 [在 Amazon 中创建一个空项目 CodeCatalyst](projects-create.md#projects-create-empty)。
+ 在你的项目中，你需要一个 CodeCatalyst **名**为：

  ```
  codecatalyst-cfn-environment
  ```

  按如下方式配置此环境：
  + 选择任何类型，例如**非生产**。
  + 将您的 AWS 账户与之关联。
  + 对于**默认 IAM 角色**，选择任何角色。稍后需要指定另一个角色。

  有关更多信息，请参阅 [部署到 AWS 账户 和 VPCs](deploy-environments.md)。

## 步骤 1：创建源存储库
<a name="deploy-tut-lambda-cfn-source"></a>

在此步骤中，您将在中创建源存储库 CodeCatalyst。此存储库用于存储教程的源文件，例如 Lambda 函数文件。

有关源存储库的更多信息，请参阅[创建源存储库](source-repositories-create.md)。

**创建源存储库**

1. 在 CodeCatalyst导航窗格中，选择**代码**，然后选择**源存储库**。

1. 选择**添加存储库**，然后选择**创建存储库**。

1. 在**存储库名称**中，输入：

   ```
   codecatalyst-cfn-source-repository
   ```

1. 选择**创建**。

现在，您已经创建了一个名为 `codecatalyst-cfn-source-repository` 的存储库。

## 步骤 2：创建 AWS 角色
<a name="deploy-tut-lambda-cfn-roles"></a>

在此步骤中，您将创建以下 AWS IAM 角色：
+ **部署角色**-授予 CodeCatalyst **Deploy CloudFormation stack** 操作访问您的 AWS 账户和 CloudFormation 服务的权限，您将在其中部署无服务器应用程序。**部署 CloudFormation 堆栈**操作是您的工作流程的一部分。
+ **构建角色**-授予 CodeCatalyst 构建操作访问您的 AWS 账户并写入存储无服务器应用程序包的 Amazon S3 的权限。构建操作是您的工作流的一部分。
+ **堆栈角色**- CloudFormation 授予读取和修改您稍后将提供的 AWS SAM 模板中指定的资源的权限。还授予权限 CloudWatch。

有关 IAM 角色的更多信息，请参阅《AWS Identity and Access Management 用户指南》**中的 [IAM 角色](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html)。

**注意**  
要节省时间，您可以创建一个名为 `CodeCatalystWorkflowDevelopmentRole-spaceName` 角色的角色，而不是前面列出的三个角色。有关更多信息，请参阅 [为您的账户和空间创建 **CodeCatalystWorkflowDevelopmentRole-*spaceName*** 角色](ipa-iam-roles.md#ipa-iam-roles-service-create)。了解 `CodeCatalystWorkflowDevelopmentRole-spaceName` 角色具有非常广泛的权限，这可能会带来安全风险。我们建议您仅在教程和安全要求较低的场景中使用此角色。本教程假定您创建的是前面列出的三个角色。

**注意**  
还需要一个 [Lambda 执行角色](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html)，但您无需立即创建此角色，因为当您在步骤 5 中运行工作流时，`sam-template.yml` 文件会为您创建它。



**创建部署角色**

1. 按如下步骤操作，为角色创建策略：

   1. 登录到 AWS。

   1. 使用 [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/) 打开 IAM 控制台。

   1. 在导航窗格中，选择**策略**。

   1. 选择**创建策略**。

   1. 选择 **JSON** 选项卡。

   1. 删除现有代码。

   1. 粘贴以下代码：
**注意**  
第一次使用该角色运行工作流操作时，请在资源策略语句中使用以下通配符，然后在策略可用后使用资源名称缩小策略范围。  

      ```
      "Resource": "*"
      ```

   1. 选择**下一步：标签**。

   1. 选择**下一步：审核**。

   1. 在**名称**中，输入：

      ```
      codecatalyst-deploy-policy
      ```

   1. 选择**创建策略**。

      现在，您已经创建了权限策略。

1. 按如下步骤操作，创建部署角色：

   1. 在导航窗格中，选择**角色**，然后选择**创建角色**。

   1. 选择**自定义信任策略**。

   1. 删除现有的自定义信任策略。

   1. 添加以下自定义信任策略：

   1. 选择**下一步**。

   1. 在**权限策略**中，搜索 `codecatalyst-deploy-policy` 并选中其复选框。

   1. 选择**下一步**。

   1. 对于**角色名称**，输入：

      ```
      codecatalyst-deploy-role
      ```

   1. 对于**角色描述**，输入：

      ```
      CodeCatalyst deploy role
      ```

   1. 选择**创建角色**。

   现在，您已创建一个具有信任策略和权限策略的部署角色。

1. 按如下步骤操作，获取部署角色 ARN：

   1. 在导航窗格中，选择**角色**。

   1. 在搜索框中，输入刚创建的角色的名称（`codecatalyst-deploy-role`）。

   1. 从列表中选择该角色。

      此时将显示该角色的**摘要**页面。

   1. 在顶部，复制 **ARN** 值。

   现在，您已创建具有相应权限的部署角色并已获取其 ARN。

**创建构建角色**

1. 按如下步骤操作，为角色创建策略：

   1. 登录到 AWS。

   1. 使用 [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/) 打开 IAM 控制台。

   1. 在导航窗格中，选择**策略**。

   1. 选择**创建策略**。

   1. 选择 **JSON** 选项卡。

   1. 删除现有代码。

   1. 粘贴以下代码：
**注意**  
第一次使用该角色运行工作流操作时，请在资源策略语句中使用以下通配符，然后在策略可用后使用资源名称缩小策略范围。  

      ```
      "Resource": "*"
      ```

   1. 选择**下一步：标签**。

   1. 选择**下一步：审核**。

   1. 在**名称**中，输入：

      ```
      codecatalyst-build-policy
      ```

   1. 选择**创建策略**。

      现在，您已经创建了权限策略。

1. 按如下步骤操作，创建构建角色：

   1. 在导航窗格中，选择**角色**，然后选择**创建角色**。

   1. 选择**自定义信任策略**。

   1. 删除现有的自定义信任策略。

   1. 添加以下自定义信任策略：

   1. 选择**下一步**。

   1. 在**权限策略**中，搜索 `codecatalyst-build-policy` 并选中其复选框。

   1. 选择**下一步**。

   1. 对于**角色名称**，输入：

      ```
      codecatalyst-build-role
      ```

   1. 对于**角色描述**，输入：

      ```
      CodeCatalyst build role
      ```

   1. 选择**创建角色**。

   现在，您已创建一个具有信任策略和权限策略的构建角色。

1. 按如下步骤操作，获取构建角色 ARN：

   1. 在导航窗格中，选择**角色**。

   1. 在搜索框中，输入刚创建的角色的名称（`codecatalyst-build-role`）。

   1. 从列表中选择该角色。

      此时将显示该角色的**摘要**页面。

   1. 在顶部，复制 **ARN** 值。

   现在，您已创建具有相应权限的构建角色并已获取其 ARN。<a name="deploy-tut-lambda-cfn-roles-stack"></a>

**创建堆栈角色**

1.  AWS 使用要部署堆栈的账户登录。

1. 使用 [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/) 打开 IAM 控制台。

1. 按如下步骤操作，创建堆栈角色：

   1. 在导航窗格中，选择**角色**。

   1. 选择**创建角色**。

   1. 选择 **AWS 服务**。

   1. 在 “**用例**” 部分，**CloudFormation**从下拉列表中进行选择。

   1. 选择 **CloudFormation** 单选按钮。

   1. 选择底部的**下一步**。

   1. 使用搜索框找到以下权限策略，然后选中它们对应的复选框。
**注意**  
如果您搜索一个策略，但该策略未显示，请务必选择**清除筛选条件**，然后重试。
      + **CloudWatchFullAccess**
      + **AWS CloudFormationFullAccess**
      + **IAMFull访问**
      + **AWS Lambda\$1 FullAccess**
      + **亚马逊APIGateway管理员**
      + **亚马逊 3 FullAccess**
      + **AmazonEC2ContainerRegistryFullAccess**

      第一个策略允许访问 CloudWatch 以在警报发生时启用堆栈回滚。

      其余策略 AWS SAM 允许访问堆栈中将在本教程中部署的服务和资源。有关授予权限的更多信息，请参阅 *AWS Serverless Application Model 开发人员指南*的 [ 权限](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-permissions.html)。

   1. 选择**下一步**。

   1. 对于**角色名称**，输入：

      ```
      codecatalyst-stack-role
      ```

   1. 选择**创建角色**。

1. 按如下步骤操作，获取堆栈角色的 ARN：

   1. 在导航窗格中，选择**角色**。

   1. 在搜索框中，输入刚创建的角色的名称（`codecatalyst-stack-role`）。

   1. 从列表中选择该角色。

   1. 在**摘要**部分中，复制 **ARN** 值。稍后您将需要用到它。

   现在，您已创建具有相应权限的堆栈角色并已获取其 ARN。

## 步骤 3：将 AWS 角色添加到 CodeCatalyst
<a name="deploy-tut-lambda-cfn-roles-add"></a>

在此步骤中，您将构建角色 (`codecatalyst-build-role`) 和部署角色 (`codecatalyst-deploy-role`) 添加到空间中的 CodeCatalyst 账户连接。

**注意**  
您无需将堆栈角色（`codecatalyst-stack-role`）添加到连接。这是因为在部署角色之间 CodeCatalyst 已经建立连接*之后 *CloudFormation**（不是 CodeCatalyst） AWS 使用堆栈角色。由于堆栈角色不用于获取 CodeCatalyst 访问权限 AWS，因此无需将其与账户连接相关联。

**将构建角色和部署角色添加到账户连接**

1. 在中 CodeCatalyst，导航到您的空间。

1. 选择 **AWS accounts (账户)**。此时将显示账户连接列表。

1. 选择代表您在其中创建构建和部署角色的 AWS 账户的账户连接。

1. **从管理控制台中选择 “ AWS 管理角色**”。

   此时将出现 “**将 IAM 角色添加到 Amazon CodeCatalyst 空间**” 页面。您可能需要登录才能访问该页面。

1. 选择**添加您在 IAM 中创建的现有角色**。

   这将显示一个下拉列表。该列表显示所有具有包含 `codecatalyst-runner.amazonaws.com` 和 `codecatalyst.amazonaws.com` 服务主体的信任策略的 IAM 角色。

1. 在该下拉列表中，选择 `codecatalyst-build-role`，然后选择**添加角色**。

1. 选择**添加 IAM 角色**，再选择**添加您在 IAM 中创建的现有角色**，然后在下拉列表中选择 `codecatalyst-deploy-role`。选择**添加角色**。

   现在，您已将构建角色和部署角色添加到您的空间。

1. 复制 A **mazon CodeCatalyst 显示名称**的值。您稍后在创建工作流时将需要此值。

## 步骤 4：创建 Amazon S3 存储桶
<a name="deploy-tut-lambda-cfn-s3"></a>

在此步骤中，您将创建可在其中存储无服务器应用程序的部署包 .zip 文件的 Amazon S3 存储桶。

**创建 Amazon S3 存储桶**

1. 打开 Amazon S3 控制台，网址为 [https://console.aws.amazon.com/s3/](https://console.aws.amazon.com/s3/)。

1. 在主窗格中，选择**创建存储桶**。

1. 对于**存储桶名称**，输入：

   ```
   codecatalyst-cfn-s3-bucket
   ```

1. 对于 **AWS 区域**，选择一个区域。本教程假设您选择了**美国西部（俄勒冈州）us-west-2**。有关 Amazon S3 支持的区域的信息，请参阅《AWS 一般参考》**中的 [Amazon Simple Storage Service endpoints and quotas](https://docs.aws.amazon.com/general/latest/gr/s3.html)。

1. 在页面底部选择**创建存储桶**。

现在，您已经在美国西部（俄勒冈州）us-west-2 区域中创建了一个名为 **codecatalyst-cfn-s3-bucket** 的存储桶。

## 步骤 5：添加源文件
<a name="deploy-tut-lambda-cfn-files"></a>

在此步骤中，您将向源存储库中添加多个应用程序 CodeCatalyst 源文件。`hello-world` 文件夹包含您将部署的应用程序文件。`tests` 文件夹包含单元测试。文件夹结构如下所示：

```
.
|— hello-world
|  |— tests
|     |— unit
|        |— test-handler.js
|  |— app.js
|— .npmignore
|— package.json
|— sam-template.yml
|— setup-sam.sh
```

### .npmignore 文件
<a name="deploy-tut-lambda-cfn-files-npmignore"></a>

`.npmignore` 文件指明 npm 应从应用程序包中排除哪些文件和文件夹。在本教程中，npm 将排除 `tests` 文件夹，因为它不是应用程序的一部分。

**添加 .npmignore 文件**

1. 打开 CodeCatalyst 控制台，[网址为 https://codecatalyst.aws/](https://codecatalyst.aws/)。

1. 选择您的项目 `codecatalyst-cfn-project`。

1. 在导航窗格中，选择**代码**，然后选择**源存储库**。

1. 从源存储库列表中，选择您的存储库 `codecatalyst-cfn-source-repository`。

1. 在**文件**中，选择**创建文件**。

1. 对于**文件名**，输入：

   ```
   .npmignore
   ```

1. 在文本框中，输入以下代码：

   ```
   tests/*
   ```

1. 选择**提交**，然后再次选择**提交**。

   现在，您已在存储库的根目录中创建名为 `.npmignore` 的文件。

### package.json 文件
<a name="deploy-tut-lambda-cfn-files-package-json"></a>

`package.json` 文件包含有关您的 Node 项目的重要元数据，例如项目名称、版本号、描述、依赖项以及描述如何运行应用程序并与之交互的其他详细信息。

本教程中的 `package.json` 包括依赖项列表和 `test` 脚本。测试脚本执行以下操作：
+ 通过使用 [mocha](https://mochajs.org/)，测试脚本运行 `hello-world/tests/unit/` 中指定的单元测试，并使用 [xunit]() 报告器将结果写入 `junit.xml` 文件。
+ 通过使用 [Istanbul (nyc)](https://istanbul.js.org/)，测试脚本使用 [clover](https://openclover.org/doc/manual/4.2.0/general--about-openclover.html) 报告器生成代码覆盖率报告（`clover.xml`）。有关更多信息，请参阅 Istanbul 文档中的 [Using alternative reporters](https://istanbul.js.org/docs/advanced/alternative-reporters/#clover)。

**添加 package.json 文件**

1. 在存储库中的**文件**中，选择**创建文件**。

1. 对于**文件名**，输入：

   ```
   package.json
   ```

1. 在文本框中，输入以下代码：

   ```
   {
     "name": "hello_world",
     "version": "1.0.0",
     "description": "hello world sample for NodeJS",
     "main": "app.js",
     "repository": "https://github.com/awslabs/aws-sam-cli/tree/develop/samcli/local/init/templates/cookiecutter-aws-sam-hello-nodejs",
     "author": "SAM CLI",
     "license": "MIT",
     "dependencies": {
       "axios": "^0.21.1",
       "nyc": "^15.1.0"
     },
     "scripts": {
       "test": "nyc --reporter=clover mocha hello-world/tests/unit/ --reporter xunit --reporter-option output=junit.xml"
     },
     "devDependencies": {
       "aws-sdk": "^2.815.0",
       "chai": "^4.2.0",
       "mocha": "^8.2.1"
     }
   }
   ```

1. 选择**提交**，然后再次选择**提交**。

   现在，您已将名为 `package.json` 的文件添加到存储库的根目录。

### sam-template.yml 文件
<a name="deploy-tut-lambda-cfn-files-sam-template-yml"></a>

`sam-template.yml` 文件包含有关部署 Lambda 函数和 API Gateway 并将它们一起配置的说明。它遵循[AWS Serverless Application Model 模板规范](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification.html)，该规范扩展了 CloudFormation 模板规范。

在本教程中，您将使用 AWS SAM 模板而不是常规 CloudFormation 模板，因为 AWS SAM 提供了一种有用的:: [Serverless AWS:: Function 资源](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)类型。这种类型执行许多 behind-the-scenes配置，你通常必须写出这些配置才能使用基本 CloudFormation 语法。例如，`AWS::Serverless::Function` 创建一个 Lambda 函数、Lambda 执行角色和启动该函数的事件源映射。如果你想用 basic 来编写，你必须对所有这些代码进行编码 CloudFormation。

本教程使用的是预先编写的模板，您可以使用构建操作在工作流中生成一个模板。有关更多信息，请参阅 [部署 CloudFormation 堆栈](deploy-action-cfn.md)。

**添加 sam-template.yml 文件**

1. 在存储库中的**文件**中，选择**创建文件**。

1. 对于**文件名**，输入：

   ```
   sam-template.yml
   ```

1. 在文本框中，输入以下代码：

   ```
   AWSTemplateFormatVersion: '2010-09-09'
   Transform: AWS::Serverless-2016-10-31
   Description: >
     serverless-api
   
     Sample SAM Template for serverless-api
     
   # More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
   Globals:
     Function:
       Timeout: 3
   
   Resources:
     HelloWorldFunction:
       Type: AWS::Serverless::Function # For details on this resource type, see https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
       Properties:
         CodeUri: hello-world/
         Handler: app.lambdaHandler
         Runtime: nodejs12.x
         Events:
           HelloWorld:
             Type: Api # For details on this event source type, see https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
             Properties:
               Path: /hello
               Method: get
   
   Outputs:
     # ServerlessRestApi is an implicit API created out of the events key under Serverless::Function
     # Find out about other implicit resources you can reference within AWS SAM at
     # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
     HelloWorldApi:
       Description: "API Gateway endpoint URL for the Hello World function"
       Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
     HelloWorldFunction:
       Description: "Hello World Lambda function ARN"
       Value: !GetAtt HelloWorldFunction.Arn
     HelloWorldFunctionIamRole:
       Description: "Implicit Lambda execution role created for the Hello World function"
       Value: !GetAtt HelloWorldFunctionRole.Arn
   ```

1. 选择**提交**，然后再次选择**提交**。

   现在，您已将名为 `sam-template.yml` 的文件添加到存储库的根文件夹下。

### setup-sam.sh 文件
<a name="deploy-tut-lambda-cfn-files-setup-sam"></a>

该`setup-sam.sh`文件包含下载和安装 AWS SAM CLI 实用程序的说明。工作流使用此实用工具来打包 `hello-world` 源。

**添加 setup-sam.sh 文件**

1. 在存储库中的**文件**中，选择**创建文件**。

1. 对于**文件名**，输入：

   ```
   setup-sam.sh
   ```

1. 在文本框中，输入以下代码：

   ```
   #!/usr/bin/env bash
   echo "Setting up sam"
   
   yum install unzip -y
   
   curl -LO https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip
   unzip -qq aws-sam-cli-linux-x86_64.zip -d sam-installation-directory
   
   ./sam-installation-directory/install; export AWS_DEFAULT_REGION=us-west-2
   ```

   在前面的代码中，*us-west-2*替换为您所在 AWS 的地区。

1. 选择**提交**，然后再次选择**提交**。

   现在，您已将名为 `setup-sam.sh` 的文件添加到存储库的根目录。

### app.js 文件
<a name="deploy-tut-lambda-cfn-files-app-js"></a>

`app.js` 包含 Lambda 函数代码。在本教程中，代码返回文本 `hello world`。

**添加 app.js 文件**

1. 在存储库中的**文件**中，选择**创建文件**。

1. 对于**文件名**，输入：

   ```
   hello-world/app.js
   ```

1. 在文本框中，输入以下代码：

   ```
   // const axios = require('axios')
   // const url = 'http://checkip.amazonaws.com/';
   let response;
   
   /**
    *
    * Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
    * @param {Object} event - API Gateway Lambda Proxy Input Format
    *
    * Context doc: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html 
    * @param {Object} context
    *
    * Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html
    * @returns {Object} object - API Gateway Lambda Proxy Output Format
    * 
    */
   exports.lambdaHandler = async (event, context) => {
       try {
           // const ret = await axios(url);
           response = {
               'statusCode': 200,
               'body': JSON.stringify({
                   message: 'hello world',
                   // location: ret.data.trim()
               })
           }
       } catch (err) {
           console.log(err);
           return err;
       }
   
       return response
   };
   ```

1. 选择**提交**，然后再次选择**提交**。

   现在，您已创建名为 `hello-world` 的文件夹和名为 `app.js` 的文件。

### test-handler.js 文件
<a name="deploy-tut-lambda-cfn-files-test-handler-js"></a>

`test-handler.js` 文件包含 Lambda 函数的单元测试。

**添加 test-handler.js 文件**

1. 在存储库中的**文件**中，选择**创建文件**。

1. 对于**文件名**，输入：

   ```
   hello-world/tests/unit/test-handler.js
   ```

1. 在文本框中，输入以下代码：

   ```
   'use strict';
   
   const app = require('../../app.js');
   const chai = require('chai');
   const expect = chai.expect;
   var event, context;
   
   describe('Tests index', function () {
       it('verifies successful response', async () => {
           const result = await app.lambdaHandler(event, context)
   
           expect(result).to.be.an('object');
           expect(result.statusCode).to.equal(200);
           expect(result.body).to.be.an('string');
   
           let response = JSON.parse(result.body);
   
           expect(response).to.be.an('object');
           expect(response.message).to.be.equal("hello world");
           // expect(response.location).to.be.an("string");
       });
   });
   ```

1. 选择**提交**，然后再次选择**提交**。

   现在，您已将名为 `test-handler.js` 的文件添加到 `hello-world/tests/unit` 文件夹下。

现在，您已添加所有源文件。

请花点时间仔细检查您的工作，确保已将所有文件置于正确的文件夹中。文件夹结构如下所示：

```
.
|— hello-world
|  |— tests
|     |— unit
|        |— test-handler.js
|  |— app.js
|— .npmignore
|— README.md
|— package.json
|— sam-template.yml
|— setup-sam.sh
```

## 步骤 6：创建并运行工作流
<a name="deploy-tut-lambda-cfn-workflow"></a>

在此步骤中，您将创建一个工作流来打包 Lambda 源代码并对其进行部署。工作流包含以下按顺序运行的构造块：
+ 触发器 – 当您将更改推送到源存储库时，此触发器会自动启动工作流运行。有关触发器的更多信息，请参阅[使用触发器自动启动工作流运行](workflows-add-trigger.md)。
+ 测试操作（`Test`）– 触发时，此操作将安装 [Node package manager (npm)](https://www.npmjs.com/)，然后运行 `npm run test` 命令。此命令告知 npm 运行 `package.json` 文件中定义的 `test` 脚本。`test` 脚本反过来运行单元测试并生成两个报告：测试报告（`junit.xml`）和代码覆盖率报告（`clover.xml`）。有关更多信息，请参阅 [package.json 文件](#deploy-tut-lambda-cfn-files-package-json)。

  接下来，测试操作将 XML 报告转换为 CodeCatalyst 报告，并将其显示在 CodeCatalyst 控制台中，位于测试操作的 “**报告**” 选项卡下。

  有关测试操作的更多信息，请参阅[使用工作流进行测试使用工作流进行测试](test-workflow-actions.md)。
+ 构建操作 (`BuildBackend`)-测试操作完成后，构建操作将下载并安装 AWS SAM CLI，打包`hello-world`源代码，然后将包复制到您的 Amazon S3 存储桶（Lambda 服务期望的位置）。该操作还会输出一个名为的新 AWS SAM 模板文件，`sam-template-packaged.yml`并将其放置在名为的输出构件中`buildArtifact`。

  有关构建操作的更多信息，请参阅[使用工作流进行构建](build-workflow-actions.md)。
+ 部署操作 (`DeployCloudFormationStack`)-生成操作完成后，部署操作将查找生成操作 (`buildArtifact`) 生成的输出对象，在其中找到 AWS SAM 模板，然后运行该模板。该 AWS SAM 模板创建了一个用于部署无服务器应用程序的堆栈。

**创建工作流**

1. 在导航窗格中，选择 **CI/CD**，然后选择**工作流**。

1. 选择**创建工作流**。

1. 对于**源存储库**，选择 `codecatalyst-cfn-source-repository`。

1. 对于**分支**，选择 `main`。

1. 选择**创建**。

1. 删除 YAML 示例代码。

1. 添加以下 YAML 代码：
**注意**  
在接下来的 YAML 代码中，如果需要，可以省略 `Connections:` 部分。如果您省略这些部分，则必须确保您环境的**默认 IAM 角色**字段中指定的角色包含[步骤 2：创建 AWS 角色](#deploy-tut-lambda-cfn-roles)中描述的两个角色的权限和信任策略。有关使用默认 IAM 角色设置环境的更多信息，请参阅[创建环境](deploy-environments-creating-environment.md)。

   ```
   Name: codecatalyst-cfn-workflow
   SchemaVersion: 1.0
   
   Triggers:
     - Type: PUSH
       Branches:
         - main   
   Actions:
     Test:
       Identifier: aws/managed-test@v1
       Inputs:
         Sources:
           - WorkflowSource
       Outputs:
         Reports:
           CoverageReport:
             Format: CLOVERXML
             IncludePaths:
               - "coverage/*"
           TestReport:
             Format: JUNITXML
             IncludePaths:
               - junit.xml
       Configuration:
         Steps:
           - Run: npm install
           - Run: npm run test  
     BuildBackend:
       Identifier: aws/build@v1
       DependsOn:
         - Test
       Environment:
         Name: codecatalyst-cfn-environment
         Connections:
           - Name: codecatalyst-account-connection
             Role: codecatalyst-build-role
       Inputs:
         Sources:
           - WorkflowSource
       Configuration: 
         Steps:
           - Run: . ./setup-sam.sh
           - Run: sam package --template-file sam-template.yml --s3-bucket codecatalyst-cfn-s3-bucket --output-template-file sam-template-packaged.yml --region us-west-2
       Outputs:
         Artifacts:
           - Name: buildArtifact
             Files:
               - "**/*"
     DeployCloudFormationStack:
       Identifier: aws/cfn-deploy@v1
       DependsOn: 
         - BuildBackend
       Environment:
         Name: codecatalyst-cfn-environment
         Connections:
           - Name: codecatalyst-account-connection
             Role: codecatalyst-deploy-role
       Inputs:
         Artifacts:
           - buildArtifact
         Sources: []
       Configuration:
         name: codecatalyst-cfn-stack
         region: us-west-2
         role-arn: arn:aws:iam::111122223333:role/StackRole
         template: ./sam-template-packaged.yml
         capabilities: CAPABILITY_IAM,CAPABILITY_AUTO_EXPAND
   ```

   在上述代码中，进行如下替换：
   + 的两个实例均*codecatalyst-cfn-environment*以您的环境名称命名。
   + 的两个实例都*codecatalyst-account-connection*带有您的账户连接的显示名称。显示名称可能是数字。有关更多信息，请参阅 [步骤 3：将 AWS 角色添加到 CodeCatalyst](#deploy-tut-lambda-cfn-roles-add)。
   + 将 *codecatalyst-build-role* 替换为您在[步骤 2：创建 AWS 角色](#deploy-tut-lambda-cfn-roles)中创建的构建角色的名称。
   + *codecatalyst-cfn-s3-bucket*使用您在中创建的 Amazon S3 存储桶的名称[步骤 4：创建 Amazon S3 存储桶](#deploy-tut-lambda-cfn-s3)。
   + *us-west-2*包含您的 Amazon S3 存储桶所在区域（第一个实例）和堆栈将部署的位置（第二个实例）的两个实例。这两个区域可能不同。本教程假定两个区域都设置为 `us-west-2`。有关 Amazon S3 和支持的区域的详细信息 CloudFormation，请参阅中的[服务终端节点和配额*AWS 一般参考*](https://docs.aws.amazon.com/general/latest/gr/aws-service-information.html)。
   + 将 *codecatalyst-deploy-role* 替换为您在[步骤 2：创建 AWS 角色](#deploy-tut-lambda-cfn-roles)中创建的部署角色的名称。
   + *codecatalyst-cfn-environment*使用您在中创建的环境的名称[先决条件](#deploy-tut-lambda-cfn-prereqs)。
   + *arn:aws:iam::111122223333:role/StackRole*使用您在中创建的堆栈角色的 Amazon 资源名称 (ARN)。[步骤 2：创建 AWS 角色](#deploy-tut-lambda-cfn-roles)
**注意**  
如果您决定不创建构建、部署和堆叠角色 *codecatalyst-build-role**codecatalyst-deploy-role*，请使用角色的*arn:aws:iam::111122223333:role/StackRole*名称或 ARN 替换、和。`CodeCatalystWorkflowDevelopmentRole-spaceName`有关该角色的更多信息，请参阅[步骤 2：创建 AWS 角色](#deploy-tut-lambda-cfn-roles)。

   有关前面显示的代码中的属性的信息，请参阅['部署 CloudFormation 堆栈'动作 YAML](deploy-action-ref-cfn.md)。

1. （可选）选择**验证**，确保 YAML 代码在提交之前有效。

1. 选择**提交**。

1. 在**提交工作流**对话框中，输入以下内容：

   1. 对于**工作流文件名**，保留默认值 `codecatalyst-cfn-workflow`。

   1. 对于**提交消息**，输入：

      ```
      add initial workflow file
      ```

   1. 对于**存储库**，选择 **codecatalyst-cfn-source-repository**。

   1. 对于**分支名称**，选择**主**。

   1. 选择**提交**。

   现在，您已创建工作流。由于在工作流顶部定义了触发器，因此工作流运行会自动启动。具体而言，当您将 `codecatalyst-cfn-workflow.yaml` 文件提交（并推送）到源存储库时，触发器启动了工作流运行。

**查看正在运行的工作流**

1. 在导航窗格中，选择 **CI/CD**，然后选择**工作流**。

1. 选择您刚刚创建的工作流：`codecatalyst-cfn-workflow`。

1. 选择**运行**选项卡。

1. 在**运行 ID** 列中，选择运行 ID。

1. 选择**测试**以查看测试进度。

1. 选择**BuildBackend**查看构建进度。

1. 选择**DeployCloudFormationStack**查看部署进度。

   有关查看运行详细信息的更多信息，请参阅[查看工作流运行状态和详细信息](workflows-view-run.md)。

1. **DeployCloudFormationStack**操作完成后，请执行以下操作：
   + 如果工作流运行成功，请转到下一过程。
   + 如果工作流程在**测试**或**BuildBackend**操作中运行失败，请选择**日志**来解决问题。
   + 如果**DeployCloudFormationStack**操作的工作流程运行失败，请选择部署操作，然后选择**摘要**选项卡。滚动至**CloudFormation 事件**部分以查看详细的错误消息。如果发生了回滚， AWS 请在重新运行工作流程之前通过 CloudFormation 控制台删除`codecatalyst-cfn-stack`堆栈。

**验证部署**

1. 在部署成功后，从顶部附近的水平菜单栏中选择**变量 (7)**。（请勿在右侧窗格中选择**变量**。）

1. 旁边 **HelloWorldApi**，将 `https://` URL 粘贴到浏览器中。

   这将显示来自 Lambda 函数的 **hello world** JSON 消息，表示工作流已成功部署和配置 Lambda 函数以及 API Gateway。
**提示**  
您可以通过一些小配置在工作流程图中 CodeCatalyst 显示此 URL。有关更多信息，请参阅 [在工作流图中显示应用程序 URL](deploy-app-url.md)。

**验证单元测试结果和代码覆盖率**

1. 在工作流图中，选择**测试**，然后选择**报告**。

1. 选择**TestReport**查看单元测试结果，或者选择**CoverageReport**查看正在测试的文件的代码覆盖率详细信息，在本例中为`app.js`和`test-handler.js`。

**验证已部署的资源**

1. 登录 AWS 管理控制台 并打开 API Gateway 控制台，网址为[https://console.aws.amazon.com/apigateway/](https://console.aws.amazon.com/apigateway/)。

1. 观察 AWS SAM 模板创建的 **codecatalyst-cfn-stack**API。API 名称来自工作流定义文件（`codecatalyst-cfn-workflow.yaml`）中的 `Configuration/name` 值。

1. 打开 AWS Lambda 控制台，网址为[https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/)。

1. 在导航窗格中，选择**函数**。

1. 选择您的 Lambda 函数 `codecatalyst-cfn-stack-HelloWorldFunction-string`。

1. 您可以查看 API Gateway 是如何成为该函数的触发器的。此集成是根据 AWS SAM `AWS::Serverless::Function`资源类型自动配置的。

## 步骤 7：进行更改
<a name="deploy-tut-lambda-cfn-change"></a>

在此步骤中，您对 Lambda 源代码进行更改，然后提交它。此提交将启动新的工作流运行。此运行在蓝绿方案中部署新的 Lambda 函数，该方案使用 Lambda 控制台中指定的默认流量转移配置。

**更改您的 Lambda 源**

1. 在中 CodeCatalyst，导航到您的项目。

1. 在导航窗格中，选择**代码**，然后选择**源存储库**。

1. 选择您的源存储库 `codecatalyst-cfn-source-repository`。

1. 更改应用程序文件：

   1. 选择 `hello-world` 文件夹。

   1. 选择 `app.js` 文件。

   1. 选择**编辑**。

   1. 在第 23 行上，将 `hello world` 更改为 **Tutorial complete\$1**。

   1. 选择**提交**，然后再次选择**提交**。

      提交会促使启动工作流运行。此运行将失败，因为您尚未更新单元测试来反映名称更改。

1. 更新单元测试：

   1. 选择 `hello-world\tests\unit\test-handler.js`。

   1. 选择**编辑**。

   1. 在第 19 行上，将 `hello world` 更改为 **Tutorial complete\$1**。

   1. 选择**提交**，然后再次选择**提交**。

      提交会促使启动另一个工作流运行。此运行将成功。

1. 在导航窗格中，选择 **CI/CD**，然后选择**工作流**。

1. 选择 `codecatalyst-cfn-workflow`，然后选择**运行**。

1. 选择最新运行的运行 ID。该运行应仍在进行中。

1. 选择 “**测试**” **BuildBackend**、“和” **DeployCloudFormationStack**以查看工作流程的运行进度。

1. 在工作流完成后，选择顶部附近的**变量 (7)**。

1. 旁边 **HelloWorldApi**，将 `https://` URL 粘贴到浏览器中。

   一条 `Tutorial complete!` 消息将显示在浏览器中，这表示您已成功部署新应用程序。

## 清理
<a name="deploy-tut-lambda-cfn-clean-up"></a>

清理本教程中使用的文件和服务以免被收取费用。

**在 CodeCatalyst 控制台中进行清理**

1. 打开 CodeCatalyst 控制台，[网址为 https://codecatalyst.aws/](https://codecatalyst.aws/)。

1. 删除 `codecatalyst-cfn-workflow`。

1. 删除 `codecatalyst-cfn-environment`。

1. 删除 `codecatalyst-cfn-source-repository`。

1. 删除 `codecatalyst-cfn-project`。

**要在里面清理干净 AWS 管理控制台**

1. 清理一下 CloudFormation，如下所示：

   1. 在 [https://console.aws.amazon.com/cloudformat](https://console.aws.amazon.com/cloudformation/) ion 上打开 CloudFormation 控制台。

   1. 删除 `codecatalyst-cfn-stack`。

      删除堆栈将从 API Gateway 和 Lambda 服务中移除所有教程资源。

1. 在 Amazon S3 中进行清理，如下所示：

   1. 打开 Amazon S3 控制台，网址为 [https://console.aws.amazon.com/s3/](https://console.aws.amazon.com/s3/)。

   1. 选择 `codecatalyst-cfn-s3-bucket`。

   1. 删除存储桶内容。

   1. 删除 存储桶。

1. 在 IAM 中进行清理，如下所示：

   1. 使用 [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/) 打开 IAM 控制台。

   1. 删除 `codecatalyst-deploy-policy`。

   1. 删除 `codecatalyst-build-policy`。

   1. 删除 `codecatalyst-stack-policy`。

   1. 删除 `codecatalyst-deploy-role`。

   1. 删除 `codecatalyst-build-role`。

   1. 删除 `codecatalyst-stack-role`。

在本教程中，您学习了如何使用 CodeCatalyst 工作流程和部署 CloudFormation 堆栈操作将无服务器应用程序**部署为 CloudFormation 堆栈**。