JEP 322: Time-Based Release Versioning | 基于时间的发布版本控制
摘要
修订 Java SE 平台和 JDK 的版本字符串方案,以及相关的版本信息,以适应当前和未来的基于时间的发布模型。
目标
- 重新制定 JEP 223 引入的版本号方案,使其更适合定义包含新特性的 特性发布 和仅修复错误的 更新发布 的基于时间的发布模型。
- 允许其他于 当前模型 不同的基于时间的发布模型,具有不同的节奏或比特性发布小但比更新发布大的 中间 发布。
- 保持与整体 JEP 223 版本字符串方案的兼容性。
- 使开发人员或最终用户可以轻松判断发布版本的年龄,以决定是否将其升级到具有最新安全修复和可能的其他特性的较新版本。
- 提供一种方法,使实施者可以指示发布版本是否属于一个系列的发布版本,实施者为其提供长期支持。
- 提供一种方法,使实施者可以包含和显示一个附加的、特定于实施者的版本字符串,以便将发布版本与相关产品对齐。
非目标
不修订现有的版本字符串方案以满足与基于时间的发布模型无关的要求。
不修订除 java
启动器之外的命令行工具的版本报告输出。虽然这样做是可取的,但不是必需的,可以在以后完成。
动机
由 JEP 223 引入的版本字符串方案是过去的一个重大改进。然而,该方案不适合未来,我们计划按照 严格的六个月节奏 发布 Java SE 平台和 JDK 的新版本。
JEP 223 的版本号语义的主要困难在于,版本号编码了与其前趋者相比的兼容性和重要性。然而,在基于时间的发布模型中,这些质量并不是提前已知的。它们在整个发布周期中都可能发生变化,直到最后一个特性被集成。因此,版本号也不是提前已知的。
因此,本次提议的主要变化是将版本号重新制定为编码时间的经过,以释放版本周期的形式。这对于基于时间的发布模型来说是一个更好的适配,因为每个发布周期,以及每个版本号,都是提前已知的。
描述
版本号
一个 版本号,$VNUM
,是由点字符(U+002E)分隔的一个或多个元素的序列。一个元素要么是零,要么是一个没有前导零的无符号整数数字。版本号的最后一个元素不能是零。当一个元素被递增时,所有后续元素都将被移除。格式如下:
[1-9][0-9]*((\.0)*\.[1-9][0-9]*)*
序列可以是任意长度,但前四个元素被赋予特定的含义,如下所示:
$FEATURE.$INTERIM.$UPDATE.$PATCH
$FEATURE
— 特性发布计数器,无论发布内容如何,每个特性发布都会递增。特性可以在特性发布中添加;它们也可以被移除,如果提前至少一个特性发布通知。当有必要时,可以进行不兼容的更改。(以前的$MAJOR
。)$INTERIM
— 中间发布计数器,递增用于包含兼容错误修复和增强但不包含不兼容更改、特性移除和对标准 API 的更改的非特性发布。(以前的$MINOR
。)$UPDATE
— 更新发布计数器,递增用于兼容的更新发布,以修复安全问题、回归和较新特性中的错误。(以前的$SECURITY
,但具有非平凡的递增规则。)$PATCH
— 紧急修补程序发布计数器,仅在必须生成紧急修补程序以修复关键问题时递增。(使用额外的元素用于此目的可以最小化对正在进行的更新发布的开发人员和用户的干扰。)
版本号的第五和后续元素保留供 JDK 代码库的下游消费者使用。第五个元素可用于,例如,标识特定于实施者的修补程序发布。
版本号永远不会有尾随零元素。如果一个元素及其后面的所有元素在逻辑上都为零,则所有这些元素都被省略。
版本号中的数字序列以数字、逐点方式与另一个序列进行比较;例如,10.0.4
小于 10.1.2
。如果一个序列比另一个序列短,则较短序列的缺失元素被认为小于较长序列的对应元素;例如,10.0.2
小于 10.0.2.1
。
六个月发布模型中的版本号
在 六个月发布模型 下,版本号的元素如下变化:
$FEATURE
每六个月递增一次:2018 年 3 月的发布是 JDK 10,2018 年 9 月的发布是 JDK 11,等等。$INTERIM
始终为零,因为六个月的模型没有中间发布。我们在此保留它以便灵活,以便未来的发布模型修订可以包含这些发布,并声明 JDK$N.1
和 JDK$N.2
是 JDK$N
的兼容升级。例如,JDK 1.4.1 和 1.4.2 的发布本质上是中间发布,在这个方案下将被编号为 4.1 和 4.2。$UPDATE
在$FEATURE
递增一个月后递增,之后每三个月递增一次:2018 年 4 月的发布是 JDK 10.0.1,7 月的发布是 JDK 10.0.2,等等。
我们预计大多数特性发布至少包含一两个重要特性,并且更新发布永远不会包含不兼容的更改。结合 $INTERIM
始终为零的事实,在实践中,这个方案通常会定义与 JEP 223 方案所定义的版本号无法区分的版本号。
版本字符串
版本字符串的整体格式与 JEP 223 定义的格式相同。版本字符串是一个版本号,$VNUM
,后跟可选的预发布、构建和其他可选信息之一:
$VNUM(-$PRE)?\+$BUILD(-$OPT)?
$VNUM-$PRE(-$OPT)?
$VNUM(+-$OPT)?
其中 $PRE
是预发布标识符(例如,ea
),$BUILD
是构建号,$OPT
是可选的构建信息。
如果一个发布是一个实施者为其提供长期支持的发布系列的一部分,那么 $OPT
的值应该以 "LTS"
开头,例如 11.0.2+13-LTS。这将导致 "LTS"
在 java --version
等的输出中显示得很突出,更多信息请参见下文。
API
我们按照下列方式修订 JEP 223 定义的 Runtime.Version
API:
- 添加四个新的
int
- 返回访问器方法,用于上述定义的版本号的主要组件:feature()
,interim()
,update()
和patch()
。 - 重新定义现有的访问器方法
major()
,minor()
和security()
,使它们返回与feature()
,interim()
和update()
相同的值。 - 废弃现有的访问器方法,但不是为了移除,而是提供建议使用对应的新方法。这将有助于使开发人员了解版本号的新语义。
系统属性
我们向 JEP 223 提到的系统属性添加两个新属性:
java.version.date
— 本次发布的正式发布(GA)日期,格式为 ISO-8601 YYYY-MM-DD。对于早期访问发布,这将是预期的 GA 日期,即某个未来的日期。
这个新属性使得判断发布版本的年龄变得容易,这样你就可以了解你有多少落后了。它也反映了发布版本的安全级别:如果一个 GA 发布的版本日期不早于任何其他 GA 发布的版本日期,那么它就包含最新的安全修复。
java.vendor.version
— 一个可选的、特定于实施者的产品版本字符串,由生产特定实现的个人或组织分配。如果在构建时未分配,则它没有值;否则,其值是一个匹配正则表达式\p{Graph}+
的非空字符串。
这个新属性使得实施者可以提供可能需要与相关产品对齐的其他版本信息。一个使用形如 $YEAR.$MONTH
的日期版本的实施者可以相应地设置这个属性,使他们的 JDK 发布版本与他们的其他发布版本明显相关。(这个属性被命名为 java.vendor.version
而不是更明显的 java.implementor.version
,这是为了与 现有系统属性 的名称保持一致,其名称包含 vendor
。)
启动器
对于一个假设的 JDK 10.0.1 的构建 13,java
启动器将显示版本字符串和系统属性如下:
$ java --version
openjdk 10.0.1 2018-04-19
OpenJDK Runtime Environment (build 10.0.1+13)
OpenJDK 64-Bit Server VM (build 10.0.1+13, mixed mode)
$
同样,对于一个假设的 JDK 11 的构建 42,一个 LTS 发布:
$ java --version
openjdk 11 2018-09-20 LTS
OpenJDK Runtime Environment (build 11+42-LTS)
OpenJDK 64-Bit Server VM (build 11+42-LTS, mixed mode)
$
如果实施者将供应商版本字符串分配给一个 JDK 11 LTS 构建,例如 18.9
,则它将被显示为:
$ java --version
openjdk 11 2018-09-20 LTS
OpenJDK Runtime Environment 18.9 (build 11+42-LTS)
OpenJDK 64-Bit Server VM 18.9 (build 11+42-LTS, mixed mode)
$
具体来说,java
启动器的版本报告选项的输出将按以下方式格式化,其中 ${LTS}
扩展为 "\u0020LTS"
如果 $OPT
的前三个字符是 "LTS"
,并且 ${JVV}
扩展为 "\u0020${java.vendor.version}"
如果定义了该系统属性:
$ java --version
openjdk ${java.version} ${java.version.date}${LTS}
${java.runtime.name}${JVV} (build ${java.runtime.version})
${java.vm.name}${JVV} (build ${java.vm.version}, ${java.vm.info})
$
$ java --show-version < ... >
openjdk ${java.version} ${java.version.date}${LTS}
${java.runtime.name}${JVV} (build ${java.runtime.version})
${java.vm.name}${JVV} (build ${java.vm.version}, ${java.vm.info})
[ ... ]
$
$ java --full-version
openjdk ${java.runtime.version}
$
$ java -version
openjdk version \"${java.version}\" ${java.version.date}${LTS}
${java.runtime.name}${JVV} (build ${java.runtime.version})
${java.vm.name}${JVV} (build ${java.vm.version}, ${java.vm.info})
$
$ java -showversion < ... >
openjdk version \"${java.version}\" ${java.version.date}${LTS}
${java.runtime.name}${JVV} (build ${java.runtime.version})
${java.vm.name}${JVV} (build ${java.vm.version}, ${java.vm.info})
[ ... ]
$
$ java -fullversion
openjdk full version \"${java.runtime.version}\"
$
@since
JavaDoc 标签
与 java.specification.version
系统属性保持一致,因此在 JDK 10 中引入的 API 将被标记为 @since 10
。
Mercurial 更改集标签
用于标识促销构建的 Mercurial 标签的一般语法未改变:jdk\-$VNUM\+$BUILD
。
构建配置和输出
三个现有的版本相关配置选项将被废弃并被忽略,相关的 Make 变量将不再被定义:
--with-version-major VERSION_MAJOR
--with-version-minor VERSION_MINOR
--with-version-security VERSION_SECURITY
将定义五个新选项和相应的变量:
--with-version-feature VERSION_FEATURE
--with-version-interim VERSION_INTERIM
--with-version-update VERSION_UPDATE
--with-version-date VERSION_DATE
--with-vendor-version-string VENDOR_VERSION_STRING
(没有必要定义 --with-version-patch
和 VERSION_PATCH
,因为它们已经存在。)
写入 JDK 映像根目录的 release
文件将定义现有的 JAVA_VERSION
变量,并定义 JAVA_VERSION_DATE
与 java.version.date
系统属性的值,以及 IMPLEMENTOR_VERSION
与 java.vendor.version
系统属性的值,如果定义了该属性。
替代方案
六个月基于时间的发布模型的提议 建议特性发布的版本字符串 adopt the form $YEAR.$MONTH
。因此,明年三月的发布将是 18.3,九月的发布将是 18.9,每年如此。
在对这个方案提出了合理的反对意见后,我们 审视了版本号中编码的各种类型的信息并提出了一些替代方案,然后 总结并回应了随后的讨论,最后 发布了一个提议,该提议得到了好评,因此成为了本 JEP 的基础。
测试
这种较新的版本字符串方案与 JEP 223 定义的方案大致兼容,因此测试应该很直接。主要区别是第四个元素用于紧急修补程序发布,这可能需要一些新的单元测试用例。对相关构建配置选项的更改需要直接的手动测试。
风险和假设
本次更改引入了三个较小的不兼容性:
- JEP 223 规定
Runtime.Version
API 的security()
方法返回版本号的$SECURITY
元素的值。当$SECURITY
的前一个元素$MINOR
递增时,不会递增$SECURITY
元素。本提议将$SECURITY
元素重命名为$UPDATE
,并在$INTERIM
(原来的$MINOR
)递增时清除该元素。因此,将security()
重新定义为update()
的函数在理论上是一个不兼容的更改。然而,这个 API 在 JDK 9 中引入,并且没有预见到 JDK 9 的发布版本具有$MINOR
的非零值,因此在实践中这个更改应该影响较小。 java
启动器的版本报告选项的输出现在在第一行的末尾包含版本日期,可能后跟"\u0020LTS"
。假定第一行上的最后一个令牌是版本号的现有代码可能需要调整。java
启动器的--version
,--show-version
,-version
和-showversion
选项的输出将在第二行和第三行上包含java.vendor.version
系统属性的值,如果该值与java.version
的值不同。解析此输出的现有代码可能需要调整。