跳转至

Function versioning(函数版本管理)

This document describes the versioning system used for functions. Versions for function releases are chosen by their publishers and are immutable after creation. Applying appropriate versions is critical to providing consumers of your functions with a stable and reliable experience.

Backward compatible changes vs. breaking changes

The versioning system for functions distinguishes between backward compatible changes and breaking changes. Backward compatible changes are changes that do not disrupt existing consumers of your functions. A change that is not backward compatible can be referred to as a backward incompatible or a breaking change.

Some examples of backward compatible changes are:

  • Adding an optional input to a function’s signature.
  • Optimizing a function’s performance without changing its expected behavior.
  • Fixing a bug in your function without changing its expected behavior.

Some examples of breaking changes are:

  • Adding a required input to a function’s signature.
  • Changing the output type of a function’s signature from an integer to a string.
  • Deleting a function.

When considering whether a change to an existing version is backward compatible, ask yourself if the change would cause disruption to or require explicit attention from a consumer of the existing version.

Remember that you are ultimately in charge of dictating the expected consumption patterns of your functions.

The semantic versioning system

Functions are versioned according to the Semantic Versioning ↗ system.

In Semantic Versioning, versions take the form X.Y.Z where X, Y, and Z—known as the major, minor, and patch versions respectively—are non-negative integers (for instance, 1.2.3). A version may also include a prerelease identifier comprised of alphanumeric characters by appending a hyphen immediately following the patch version (for example, 1.2.3-rc1).

:::callout{theme="neutral"} This page provides a brief summary of Semantic Versioning. We encourage you to read the full specification ↗ since adhering to the specification is an important aspect of publishing functions that can be reliably consumed in other applications. :::

Choosing a release version

When publishing a new version of a function, consider the following points from the Semantic Versioning specification:

  • Major version 0 (0.y.z) is for initial development. During initial development, the function may change at any time and your functions should not be considered stable by consumers.
  • The major version should be incremented when you make backward incompatible changes.
  • The minor version should be incremented when you add functionality in a backward compatible manner.
  • The patch version should be incremented when you make backward compatible bug fixes.
  • A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version.

Backward compatibility checks

Backward compatibility checks are performed for your functions before you publish a new version. In particular, you will be warned about any of the following breaking changes:

  • Dropping a function. This includes deleting a function in your Python or TypeScript function code repository.
  • Dropping an input (even an optional one) on a function’s signature.
  • Reordering an input on a function’s signature.
  • Adding a required input to a function’s signature.
  • Bad input type changes (such as integer to string). Note that widening a numeric input type (like integer to float) will result in a warning.
  • Bad output type changes (such as string to optional string).

If these checks fail for any reason, it is recommended that you release a major version. However, this does not apply if you are still in the initial development phase (that is, you are still at major version 0).

:::callout{theme="warning"} Palantir's built-in checks are not exhaustive of all types of breaking changes. For instance, breaking changes from your internal implementation may not be detected. It is not safe to release a minor or patch version based solely on a successful outcome from these checks. :::

Caveat: Custom types

The internal functions data type representation currently lacks sufficient information regarding the optionality of custom type fields. As a result, you may notice that for custom type inputs and outputs, the backward compatibility checks will warn you when removing or adding any fields, including optional fields (such as quantity?: Integer in Typescript or quantity: Integer = 0 in Python).

We are currently making changes so that going forward you will not be warned when removing an optional field on an output custom type or adding an optional field on an input custom type.

:::callout{theme="neutral"} You will still receive a warning when removing an optional field on an input custom type. It is generally considered bad practice to ignore any fields provided by a consumer as they likely expect the provided fields to tell the behavior of your function. :::

Restrict stable version tags

Stable Semantic Version releases (non-prerelease versions) may be immediately consumed by downstream production applications if the applications have been configured to reference the Function by a version range (for example, >=1.2.3 <2.0.0). This makes it important to review and test code changes before releasing them in a new stable version.

It is possible to enforce restrictions on the release of stable versions of your Functions by enabling a toggle in the repository settings for protected branches.

Frequently asked questions

Choosing release versions in the 0.y.z initial development phase

It is common practice that any breaking changes be made in a minor release and any backward compatible changes be made in a patch release. This is an assumption made by consumers in many development spheres, such as the Node/NPM ecosystem, as demonstrated by their wide use of caret ranges ↗.

Accidentally releasing a backward incompatible change as a patch or minor version

As soon as you realize that you’ve released a breaking change, you should correct the problem and restore backward compatibility in a new minor version.

Consider the following example.

  1. You have a function called myFunction at version 1.0.0 which takes a single string input.
  2. You add a new required input to myFunction and accidentally release this change in a minor version release 1.1.0.

To remediate this, you can revert the breaking change to the signature (that is, remove the new required input you added in 1.1.0) and release this change in version 1.2.0.

Checking backward compatibility when a release fails or has not yet been published

In the case of TypeScript or Python functions, your functions may fail or take a few minutes to publish. In either of these cases, the built-in backward compatibility checks will be unable to run. If you want to see the results of these checks before making a new release, you have the following options:

  • If the last release failed, you should use the “custom tag” option to compare against the last successful tag.
  • If the last release has not been published yet, you should wait for it to finish.

中文翻译

函数版本管理

本文档描述了函数所使用的版本管理系统。函数版本的发布由发布者选择,创建后不可更改。应用适当的版本对于为函数使用者提供稳定可靠的体验至关重要。

向后兼容变更 vs. 破坏性变更

函数的版本管理系统区分向后兼容变更和破坏性变更。向后兼容变更是指不会影响现有函数使用者的变更。不向后兼容的变更可称为向后不兼容破坏性变更。

向后兼容变更的示例包括:

  • 在函数签名中添加可选输入。
  • 优化函数性能而不改变其预期行为。
  • 修复函数中的错误而不改变其预期行为。

破坏性变更的示例包括:

  • 在函数签名中添加必需输入。
  • 将函数签名的输出类型从整数改为字符串。
  • 删除函数。

在考虑对现有版本的变更是否向后兼容时,请自问该变更是否会导致现有版本的使用者受到影响或需要其特别关注。

请记住,您最终负责规定函数的预期使用模式。

语义化版本系统

函数按照语义化版本 ↗系统进行版本管理。

在语义化版本中,版本号采用 X.Y.Z 格式,其中 XYZ(分别称为主版本号、次版本号和补丁版本号)是非负整数(例如 1.2.3)。版本号还可以包含由字母数字字符组成的预发布标识符,方法是在补丁版本号后立即附加连字符(例如 1.2.3-rc1)。

:::callout{theme="neutral"} 本页提供语义化版本的简要概述。我们建议您阅读完整规范 ↗,因为遵守规范是发布可在其他应用程序中可靠使用的函数的重要方面。 :::

选择发布版本

在发布函数的新版本时,请考虑语义化版本规范中的以下几点:

  • 主版本号 00.y.z)用于初始开发阶段。在初始开发阶段,函数可能随时发生变化,使用者不应认为您的函数是稳定的。
  • 当您进行向后不兼容的变更时,应递增主版本号。
  • 当您以向后兼容的方式添加功能时,应递增次版本号。
  • 当您进行向后兼容的错误修复时,应递增补丁版本号。
  • 预发布版本表示该版本不稳定,可能无法满足其对应正式版本所表示的预期兼容性要求。

向后兼容性检查

在您发布新版本之前,系统会对您的函数执行向后兼容性检查。具体来说,系统会就以下任何破坏性变更向您发出警告:

  • 删除函数。这包括在您的 Python 或 TypeScript 函数代码仓库中删除函数。
  • 删除函数签名上的输入(即使是可选输入)。
  • 重新排列函数签名上的输入顺序。
  • 在函数签名中添加必需输入。
  • 不良的输入类型变更(例如从整数改为字符串)。请注意,扩大数值输入类型(如从整数改为浮点数)将产生警告。
  • 不良的输出类型变更(例如从字符串改为可选字符串)。

如果这些检查因任何原因失败,建议您发布主版本。但是,如果您仍处于初始开发阶段(即主版本号仍为 0),则不适用此规则。

:::callout{theme="warning"} Palantir 的内置检查并未涵盖所有类型的破坏性变更。例如,内部实现中的破坏性变更可能无法被检测到。仅凭这些检查的成功结果就发布次版本或补丁版本是不安全的。 :::

注意事项:自定义类型

当前内部函数数据类型表示缺乏关于自定义类型字段可选性的足够信息。因此,您可能会注意到,对于自定义类型的输入和输出,向后兼容性检查会在删除或添加任何字段(包括可选字段,如 TypeScript 中的 quantity?: Integer 或 Python 中的 quantity: Integer = 0)时向您发出警告。

我们目前正在进行更改,以便将来在删除输出自定义类型上的可选字段或添加输入自定义类型上的可选字段时,您将不会收到警告。

:::callout{theme="neutral"} 在删除输入自定义类型上的可选字段时,您仍会收到警告。通常认为忽略使用者提供的任何字段是不良做法,因为使用者可能期望这些提供的字段能够影响函数的行为。 :::

限制稳定版本标签

如果下游生产应用程序已配置为通过版本范围(例如 >=1.2.3 <2.0.0)引用函数,则稳定的语义化版本发布(非预发布版本)可能会被立即使用。这使得在发布新的稳定版本之前审查和测试代码变更变得非常重要。

可以通过在受保护分支的仓库设置中启用开关来对函数稳定版本的发布实施限制。

常见问题

在 0.y.z 初始开发阶段选择发布版本

通常的做法是,任何破坏性变更都在次版本中发布,任何向后兼容的变更都在补丁版本中发布。这是许多开发领域(如 Node/NPM 生态系统)中使用者所做的假设,这从他们广泛使用脱字符范围 ↗中可以看出。

意外将向后不兼容的变更作为补丁或次版本发布

一旦您意识到发布了破坏性变更,应立即纠正问题并在新的次版本中恢复向后兼容性。

请考虑以下示例:

  1. 您有一个名为 myFunction 的函数,版本为 1.0.0,接受单个字符串输入。
  2. 您向 myFunction 添加了一个新的必需输入,并意外地将此变更作为次版本 1.1.0 发布。

要解决此问题,您可以还原对签名的破坏性变更(即删除您在 1.1.0 中添加的新必需输入),并在版本 1.2.0 中发布此变更。

在发布失败或尚未发布时检查向后兼容性

对于 TypeScript 或 Python 函数,您的函数可能发布失败或需要几分钟才能完成发布。在这两种情况下,内置的向后兼容性检查将无法运行。如果您希望在发布新版本之前查看这些检查的结果,您有以下选择:

  • 如果上次发布失败,您应使用"自定义标签"选项与上次成功的标签进行比较。
  • 如果上次发布尚未完成,您应等待其完成。