

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

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

# 以蓝图作者的身份使用生命周期管理功能
<a name="lifecycle-management-dev"></a>

生命周期管理功能可让您从单一的通用最佳实践来源使大量项目保持同步。这将扩展修复的传播，并在任意数量的项目的整个软件开发生命周期中对这些项目进行维护。生命周期管理功能简化了内部活动、安全修复、审计、运行时升级、最佳实践变更以及其他维护实践，因为这些标准是在同一位置定义的，并且会在发布新标准时自动集中保持最新。

在发布新版本的蓝图时，系统会提示所有包含该蓝图的项目更新到最新版本。作为蓝图作者，您还可以查看每个项目为实现合规性而包含的特定蓝图的版本。当现有源存储库中存在冲突时，生命周期管理功能会创建拉取请求。对于所有其他资源（例如开发环境），所有生命周期管理更新都会严格地创建新资源。用户可以自行选择合并或不合并这些拉取请求。合并待处理的拉取请求后，将更新项目中使用的蓝图的版本（包括选项）。要了解如何以蓝图用户的身份使用生命周期管理功能，请参阅[对现有项目使用生命周期管理功能](lifecycle-management-user.md#using-lm-existing-projects)和[对项目中的多个蓝图使用生命周期管理功能](lifecycle-management-user.md#using-lm-multiple-bp)。

**Topics**
+ [测试捆绑包输出和合并冲突的生命周期管理](test-lm.md)
+ [使用合并策略生成捆绑包并指定文件](merge-strategies-lm.md)
+ [访问上下文对象以获取项目详细信息](context-objects-lm.md)

# 测试捆绑包输出和合并冲突的生命周期管理
<a name="test-lm"></a>

您可以在本地测试蓝图的生命周期管理和合并冲突解决方案。在 `synth/` 目录下会生成一系列捆绑包，代表生命周期更新的各个阶段。要测试生命周期管理，您可以在蓝图上运行以下 yarn 命令：`yarn blueprint: resynth`。要了解有关重新合成和捆绑包的更多信息，请参阅[重新合成](custom-bp-concepts.md#resynthesis-concept)和[使用重新合成功能生成文件](merge-strategies-lm.md#three-way-merge-lm)。

# 使用合并策略生成捆绑包并指定文件
<a name="merge-strategies-lm"></a>

您可以使用合并策略生成带重新合成功能的捆绑包，并指定用于自定义蓝图的生命周期管理更新的文件。通过利用重新合成功能和合并策略，您可以管理更新并控制在部署期间更新的文件。您也可以编写自己的策略来控制如何将更改合并到现有 CodeCatalyst 项目中。

**Topics**
+ [使用重新合成功能生成文件](#three-way-merge-lm)
+ [使用合并策略](#vended-merge-strategies-lm)
+ [指定用于生命周期管理更新的文件](#specify-files-lm-updates)
+ [编写合并策略](#write-merge-strategies-lm)

## 使用重新合成功能生成文件
<a name="three-way-merge-lm"></a>

重新合成功能可以将蓝图生成的源代码与之前由同一蓝图生成的源代码合并，从而使对蓝图所做的更改能够传播到现有项目。通过 `resynth()` 函数跨蓝图输出捆绑包运行合并。重新合成功能首先会生成三个捆绑包，分别代表蓝图和项目状态的不同方面。可以使用 `yarn blueprint:resynth` 命令本地手动运行此功能，这将创建捆绑包（如果捆绑包不存在）。通过手动使用捆绑包，您可以在本地模拟和测试重新合成行为。默认情况下，蓝图仅在 `src/*` 下的存储库中运行重新合成功能，因为通常仅捆绑包的此部分受源代码控制。有关更多信息，请参阅[重新合成](custom-bp-concepts.md#resynthesis-concept)。
+ `existing-bundle` – 此捆绑包是现有项目状态的表示形式。这是由合成计算人为构造的，旨在提供蓝图上下文来说明它部署到的项目中的内容（如果有）。如果在本地运行重新合成功能时，此位置已存在某些内容，则它将被重置并视为模拟。否则，它将被设置为 `ancestor-bundle` 的内容。
+ `ancestor-bundle` – 如果蓝图输出是使用一些早期选项和/或版本合成的，则此捆绑包代表蓝图输出。如果这是此蓝图首次被添加到项目中，且其父级不存在，它将被设置为与 `existing-bundle` 相同的内容。在本地，如果该位置已存在此捆绑包，则它将被视为模拟。
+ `proposed-bundle` – 如果蓝图是使用一些新选项和/或版本合成的，则此捆绑包模拟了蓝图。这与 `synth()` 函数所生成的捆绑包相同。在本地，此捆绑包始终会被覆盖。

每个捆绑包都是在重新合成阶段创建的，可以从 `this.context.resynthesisPhase` 下的蓝图类中访问该捆绑包。
+ `resolved-bundle` – 这是最后的捆绑包，它代表已打包并部署到 CodeCatalyst 项目的内容。您可以查看已将哪些文件和差异发送到部署机制。这是解析其他三个捆绑包之间的合并的 `resynth()` 函数的输出。

通过提取 `ancestor-bundle` 和 `proposed-bundle` 之间的差异，然后将该差异添加到 `existing-bundle` 来生成 `resolved-bundle`，从而应用三向合并。所有合并策略都会将文件解析为 `resolved-bundle`。重新合成功能在 `resynth()` 期间使用蓝图的合并策略来解析这些捆绑包的覆盖范围，并根据结果生成已解析的捆绑包。

## 使用合并策略
<a name="vended-merge-strategies-lm"></a>

您可以使用蓝图库提供的合并策略。这些策略提供了解析 [使用重新合成功能生成文件](#three-way-merge-lm) 部分中提到的文件输出以及解决文件冲突的方法。
+ `alwaysUpdate` – 一种始终解析为建议的文件的策略。
+ `neverUpdate` – 一种始终解析到现有文件的策略。
+ `onlyAdd` – 一种在现有文件尚不存在时解析为建议的文件的策略。否则，解析为现有文件。
+ `threeWayMerge` – 一种在现有的、建议的和共同的父级文件之间进行三向合并的策略。如果无法干净地合并文件，则已解析的文件可能包含冲突标记。提供的文件的内容必须已通过 UTF-8 进行编码，这样策略才能生成有意义的输出。该策略尝试检测输入文件是否为二进制文件。如果该策略检测到二进制文件中存在合并冲突，则它始终返回建议的文件。
+ `preferProposed` – 一种在现有的、建议的和共同的父级文件之间进行三向合并的策略。该策略通过选择每个冲突的相关建议文件来解决冲突。
+ `preferExisting` – 一种在现有的、建议的和共同的父级文件之间进行三向合并的策略。该策略通过选择每个冲突的相关现有文件来解决冲突。

要查看合并策略的源代码，请参阅 [open-source GitHub repository](https://github.com/aws/codecatalyst-blueprints/blob/main/packages/blueprints/blueprint/src/resynthesis/merge-strategies/merge-strategies.ts#L17)。

## 指定用于生命周期管理更新的文件
<a name="specify-files-lm-updates"></a>

在重新合成期间，蓝图控制如何将更改合并到现有源存储库中。但您可能不希望将更新推送到蓝图中的每个文件。例如，像 CSS 样式表这样的示例代码是项目特定的。如果您未指定其他策略，则三向合并策略将为默认选项。蓝图可以通过指定有关存储库构造本身的合并策略来指定它们拥有哪些文件和不拥有哪些文件。蓝图可以更新其合并策略，并且可在重新合成期间使用最新策略。

```
const sourceRepo = new SourceRepository(this, {
      title: 'my-repo',
    });
    sourceRepo.setResynthStrategies([
      {
        identifier: 'dont-override-sample-code',
        description: 'This strategy is applied accross all sample code. The blueprint will create sample code, but skip attempting to update it.',
        strategy: MergeStrategies.neverUpdate,
        globs: [
          '**/src/**',
          '**/css/**',
        ],
      },
    ]);
```

可以指定多个合并策略，并且使最后一个策略优先。未发现的文件默认为类似于 Git 的三向合并。通过 `MergeStrategies` 构造提供了几种合并策略，但您可以编写自己的合并策略。提供的策略符合 [git merge strategy](https://git-scm.com/docs/merge-strategies) 驱动因素。

## 编写合并策略
<a name="write-merge-strategies-lm"></a>

除了使用提供的某个构建合并策略外，您还可以编写自己的策略。策略必须遵循标准策略接口。您必须编写一个策略函数来从 `existing-bundle`、`proposed-bundle` 和 `ancestor-bundle` 中获取文件版本，并将它们合并到单个已解析的文件中。例如：

```
type StrategyFunction = (
   /**
   * file from the ancestor bundle (if it exists)
   */
    commonAncestorFile: ContextFile | undefined, 
   /**
   * file from the existing bundle (if it exists)
   */
    existingFile: ContextFile | undefined,
   /**
   * file from the proposed bundle (if it exists)
   */ 
    proposedFile: ContextFile | undefined, 
    options?: {}) 
    /**
    * Return: file you'd like in the resolved bundle
    * passing undefined will delete the file from the resolved bundle
    */ 
=> ContextFile | undefined;
```

如果文件不存在（未定义），则该文件路径在该特定位置捆绑包中不存在。

**示例**：

```
strategies: [
          {
            identifier: 'dont-override-sample-code',
            description: 'This strategy is applied across all sample code. The blueprint will create sample code, but skip attempting to update it.',
            strategy: (ancestor, existing, proposed) => {
                const resolvedfile = ...
                ...
                // do something
                ...
                return resolvedfile
            },
            globs: [
              '**/src/**',
              '**/css/**',
            ],
          },
        ],
```

# 访问上下文对象以获取项目详细信息
<a name="context-objects-lm"></a>

作为蓝图作者，您可以在合成过程中访问蓝图项目的上下文，以便获取空间名称、项目名称或项目源存储库中的现有文件等信息。您还可以获取诸如蓝图正在生成的重新合成阶段之类的详细信息。例如，您可以访问上下文，以便了解您是要重新同步以生成原级捆绑包还是建议的捆绑包。之后，您可以使用现有的代码上下文来转换存储库中的代码。例如，您可以编写自己的重新合成策略来设置特定的代码标准。可以将策略添加到小型蓝图的 `blueprint.ts` 文件中，也可以为策略创建单独的文件。

以下示例说明如何在项目的上下文中查找文件、设置工作流生成器以及为特定文件设置蓝图提供的重新合成策略：

```
const contextFiles = this.context.project.src.findAll({
      fileGlobs: ['**/package.json'],
    });

    // const workflows = this.context.project.src.findAll({
    //   fileGlobs: ['**/.codecatalyst/**.yaml'],
    // });

    const security = new WorkflowBuilder(this, {
      Name: 'security-workflow',
    });
    new Workflow(this, repo, security.getDefinition());
    repo.setResynthStrategies([
      {
        identifier: 'force-security',
        globs: ['**/.codecatalyst/security-workflow.yaml'],
        strategy: MergeStrategies.alwaysUpdate,
      },
    ]);


    for (const contextFile of contextFiles) {
      const packageObject = JSON.parse(contextFile.buffer.toString());
      new SourceFile(internalRepo, contextFile.path, JSON.stringify({
        ...packageObject,
      }, null, 2));
    }
  }
```