Support VPC router DNS records#4010
Conversation
Walkthrough新增 VPC 路由器 DNS 记录表与索引;添加域名校验工具与单元测试;补充中英文 i18n 文案;在测试库新增 add/remove/update/get VPC Router DNS 记录的 ApiHelper 方法;新增一组 VPC 错误码常量。 ChangesVPC 路由器 DNS 记录支持
预估代码审查工作量🎯 3 (Moderate) | ⏱️ ~20 minutes 诗
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 error, 1 warning)
✅ Passed checks (3 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
⚔️ Resolve merge conflicts
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ast-grep (0.42.2)utils/src/main/java/org/zstack/utils/clouderrorcode/CloudOperationsErrorCode.javaComment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
utils/src/test/java/org/zstack/utils/test/TestNetworkUtils.java (1)
57-58: 💤 Low value建议增强测试用例的可读性和完整性。
当前边界测试使用了魔法值 64 和 254,建议改进:
- 可以引用
NetworkUtils中的常量或添加注释说明测试意图- 考虑补充以下边界测试用例以提高覆盖率:
- 空字符串
""- 连续点号
"a..b"- 最大合法长度域名(253 字符且所有标签 ≤ 63 字符)
可读性改进示例
- assertFalse(NetworkUtils.isDomainName(new String(new char[64]).replace('\0', 'a') + ".local")); - assertFalse(NetworkUtils.isDomainName(new String(new char[254]).replace('\0', 'a'))); + // Label exceeds MAX_DOMAIN_NAME_LABEL_LENGTH (63) + assertFalse(NetworkUtils.isDomainName(new String(new char[64]).replace('\0', 'a') + ".local")); + // Total length exceeds MAX_DOMAIN_NAME_LENGTH (253) + assertFalse(NetworkUtils.isDomainName(new String(new char[254]).replace('\0', 'a'))); + + // Additional edge cases + assertFalse(NetworkUtils.isDomainName("")); + assertFalse(NetworkUtils.isDomainName("a..b"));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@utils/src/test/java/org/zstack/utils/test/TestNetworkUtils.java` around lines 57 - 58, Replace the magic numeric tests in TestNetworkUtils by clarifying intent and adding boundary cases: instead of raw 64 and 254, reference or comment the related length constants from NetworkUtils and/or explain that 63 and 253 are per-label and total limits; add assertions calling NetworkUtils.isDomainName for an empty string (""), a name with consecutive dots ("a..b"), and a constructed maximum-legal domain (total length 253 with all labels ≤63) to validate the true/false expectations; keep existing long-name negative tests but document why each length is chosen and use helper(s) to build the repeated-label strings so the test is readable and self-explanatory.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@conf/db/upgrade/V5.5.22__schema.sql`:
- Around line 90-91: The SQL uses illegal zero DATETIME defaults which break
strict SQL modes; update the two TIMESTAMP columns so they do not use DEFAULT
'0000-00-00 00:00:00': change `createDate` to use a non-zero sentinel (e.g.
'2000-01-01 00:00:00') as its DEFAULT, and change `lastOpDate` to use the same
non-zero DEFAULT while keeping ON UPDATE CURRENT_TIMESTAMP (i.e. `lastOpDate`
DEFAULT '2000-01-01 00:00:00' ON UPDATE CURRENT_TIMESTAMP) to avoid
NO_ZERO_DATE/1293 errors while preserving auto-update behavior.
In `@conf/i18n/messages_en_US.properties`:
- Line 14063: Update the message value for the property key currently written as
"domain[{0}] is not a valid format" to a more natural English phrase such as
"domain[{0}] is not in a valid format"; also locate the related message around
line 14083 and change its wording to "has not been added" (ensure placeholders
remain as {0} where used) so both entries use correct, natural English and no
Chinese.
In `@utils/src/test/java/org/zstack/utils/test/TestNetworkUtils.java`:
- Line 52: The test TestNetworkUtils currently uses a literal Chinese string in
the assertion (NetworkUtils.isDomainName("中文.local")); replace the non-ASCII
literal with a Unicode-escaped form (e.g. "\u4E2D\u6587.local") or extract it
into a clearly named variable (e.g. CHINESE_LABEL) and add an English comment
explaining it tests rejection of Unicode/Chinese labels so the test remains
clear while avoiding raw Chinese characters in source; update the assertion to
use the new escaped string or variable and keep the test name and behavior
unchanged.
---
Nitpick comments:
In `@utils/src/test/java/org/zstack/utils/test/TestNetworkUtils.java`:
- Around line 57-58: Replace the magic numeric tests in TestNetworkUtils by
clarifying intent and adding boundary cases: instead of raw 64 and 254,
reference or comment the related length constants from NetworkUtils and/or
explain that 63 and 253 are per-label and total limits; add assertions calling
NetworkUtils.isDomainName for an empty string (""), a name with consecutive dots
("a..b"), and a constructed maximum-legal domain (total length 253 with all
labels ≤63) to validate the true/false expectations; keep existing long-name
negative tests but document why each length is chosen and use helper(s) to build
the repeated-label strings so the test is readable and self-explanatory.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: http://open.zstack.ai:20001/code-reviews/zstack-cloud.yaml (via .coderabbit.yaml)
Review profile: CHILL
Plan: Pro
Run ID: 4dc42d44-3476-4c7c-90af-930cbd7364ac
⛔ Files ignored due to path filters (19)
conf/i18n.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-de-DE.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-en_US.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-fr-FR.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-id-ID.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-ja-JP.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-ko-KR.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-ru-RU.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-th-TH.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-zh_CN.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-zh_TW.jsonis excluded by!**/*.jsonsdk/src/main/java/org/zstack/sdk/AddDnsRecordToVpcRouterAction.javais excluded by!sdk/**sdk/src/main/java/org/zstack/sdk/AddDnsRecordToVpcRouterResult.javais excluded by!sdk/**sdk/src/main/java/org/zstack/sdk/GetVpcRouterDnsRecordAction.javais excluded by!sdk/**sdk/src/main/java/org/zstack/sdk/GetVpcRouterDnsRecordResult.javais excluded by!sdk/**sdk/src/main/java/org/zstack/sdk/RemoveDnsRecordFromVpcRouterAction.javais excluded by!sdk/**sdk/src/main/java/org/zstack/sdk/RemoveDnsRecordFromVpcRouterResult.javais excluded by!sdk/**sdk/src/main/java/org/zstack/sdk/VpcRouterDnsRecordInventory.javais excluded by!sdk/**sdk/src/main/java/org/zstack/sdk/VpcRouterVmInventory.javais excluded by!sdk/**
📒 Files selected for processing (7)
conf/db/upgrade/V5.5.22__schema.sqlconf/i18n/messages_en_US.propertiesconf/i18n/messages_zh_CN.propertiestestlib/src/main/java/org/zstack/testlib/ApiHelper.groovyutils/src/main/java/org/zstack/utils/clouderrorcode/CloudOperationsErrorCode.javautils/src/main/java/org/zstack/utils/network/NetworkUtils.javautils/src/test/java/org/zstack/utils/test/TestNetworkUtils.java
| `createDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00', | ||
| `lastOpDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP, |
There was a problem hiding this comment.
修复零时间默认值,避免升级兼容性风险
createDate/lastOpDate 使用 DEFAULT '0000-00-00 00:00:00' 有升级失败风险(严格 SQL 模式下常见)。建议改为仓库内已采用的非零 sentinel(如 '2000-01-01 00:00:00')以保持一致并避免 NO_ZERO_DATE 问题。Line 90、Line 91 需要调整。
建议修改
CREATE TABLE IF NOT EXISTS `zstack`.`VpcRouterDnsRecordVO` (
@@
- `createDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
- `lastOpDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
+ `createDate` TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:00',
+ `lastOpDate` TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
@@
) ENGINE=InnoDB DEFAULT CHARSET=utf8;As per coding guidelines: **/*.sql requires “Do not use DEFAULT 0000-00-00 00:00:00”. Based on learnings: in conf/db/upgrade/*.sql, when another TIMESTAMP already uses ON UPDATE CURRENT_TIMESTAMP, prefer a non-CURRENT_TIMESTAMP sentinel default to avoid MySQL 5.7 Error 1293.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| `createDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00', | |
| `lastOpDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP, | |
| `createDate` TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:00', | |
| `lastOpDate` TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:00' ON UPDATE CURRENT_TIMESTAMP, |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@conf/db/upgrade/V5.5.22__schema.sql` around lines 90 - 91, The SQL uses
illegal zero DATETIME defaults which break strict SQL modes; update the two
TIMESTAMP columns so they do not use DEFAULT '0000-00-00 00:00:00': change
`createDate` to use a non-zero sentinel (e.g. '2000-01-01 00:00:00') as its
DEFAULT, and change `lastOpDate` to use the same non-zero DEFAULT while keeping
ON UPDATE CURRENT_TIMESTAMP (i.e. `lastOpDate` DEFAULT '2000-01-01 00:00:00' ON
UPDATE CURRENT_TIMESTAMP) to avoid NO_ZERO_DATE/1293 errors while preserving
auto-update behavior.
|
|
||
| # at: src/main/java/org/zstack/vpc/VpcApiInterceptor.java:627 | ||
| # args: domain | ||
| domain[%s]\ is\ not\ a\ valid\ format = domain[{0}] is not a valid format |
There was a problem hiding this comment.
修正文案语法以避免用户侧英文提示不自然
Line 14063 和 Line 14083 的英文表达建议调整为更自然的写法(in a valid format、has not been added)。
建议修改
-domain[%s]\ is\ not\ a\ valid\ format = domain[{0}] is not a valid format
+domain[%s]\ is\ not\ in\ a\ valid\ format = domain[{0}] is not in a valid format
@@
-dns\ record[domain\:%s]\ is\ not\ added\ to\ vpc\ router[uuid\:%s] = dns record[domain:{0}] is not added to vpc router[uuid:{1}]
+dns\ record[domain\:%s]\ has\ not\ been\ added\ to\ vpc\ router[uuid\:%s] = dns record[domain:{0}] has not been added to vpc router[uuid:{1}]As per coding guidelines, “代码里不应当有有中文,包括报错、注释等都应当使用正确的、无拼写错误的英文来写”.
Also applies to: 14083-14083
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@conf/i18n/messages_en_US.properties` at line 14063, Update the message value
for the property key currently written as "domain[{0}] is not a valid format" to
a more natural English phrase such as "domain[{0}] is not in a valid format";
also locate the related message around line 14083 and change its wording to "has
not been added" (ensure placeholders remain as {0} where used) so both entries
use correct, natural English and no Chinese.
| assertFalse(NetworkUtils.isDomainName(null)); | ||
| assertFalse(NetworkUtils.isDomainName("*.app.local")); | ||
| assertFalse(NetworkUtils.isDomainName("db_prod.local")); | ||
| assertFalse(NetworkUtils.isDomainName("中文.local")); |
There was a problem hiding this comment.
测试数据中包含中文字符,建议使用 Unicode 转义或添加英文注释。
根据编码规范:"代码里不应当有有中文,包括报错、注释等都应当使用正确的、无拼写错误的英文来写"。虽然这是用于测试 Unicode 字符拒绝的测试数据,但为了符合规范并提高代码可维护性,建议改为:
建议的修改方案
方案 1:使用 Unicode 转义序列
- assertFalse(NetworkUtils.isDomainName("中文.local"));
+ assertFalse(NetworkUtils.isDomainName("\u4e2d\u6587.local")); // Chinese characters方案 2:使用变量并添加英文注释
+ // Test rejection of non-ASCII characters (Chinese)
+ String unicodeDomain = "\u4e2d\u6587.local";
+ assertFalse(NetworkUtils.isDomainName(unicodeDomain));
- assertFalse(NetworkUtils.isDomainName("中文.local"));As per coding guidelines: 代码里不应当有有中文,包括报错、注释等都应当使用正确的、无拼写错误的英文来写
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@utils/src/test/java/org/zstack/utils/test/TestNetworkUtils.java` at line 52,
The test TestNetworkUtils currently uses a literal Chinese string in the
assertion (NetworkUtils.isDomainName("中文.local")); replace the non-ASCII literal
with a Unicode-escaped form (e.g. "\u4E2D\u6587.local") or extract it into a
clearly named variable (e.g. CHINESE_LABEL) and add an English comment
explaining it tests rejection of Unicode/Chinese labels so the test remains
clear while avoiding raw Chinese characters in source; update the assertion to
use the new escaped string or variable and keep the test name and behavior
unchanged.
fc7371a to
264e9c4
Compare
Regenerate SDK actions and API artifacts for add, remove, and get VPC router DNS record operations. Resolves: ZSTAC-85249 Change-Id: I1bbbe741422d273dc8d631d6ead98405c7ad1532
264e9c4 to
9d88cef
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
conf/db/upgrade/V5.5.22__schema.sql (1)
92-93:⚠️ Potential issue | 🟠 Major | ⚡ Quick win修复零时间默认值以避免升级失败风险
Line 92-93 仍使用
DEFAULT '0000-00-00 00:00:00'。这在严格 SQL 模式和部分 MySQL 版本升级时容易报错,建议改为非零 sentinel,并保留lastOpDate的ON UPDATE CURRENT_TIMESTAMP。建议修改
- `createDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00', - `lastOpDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP, + `createDate` TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:00', + `lastOpDate` TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:00' ON UPDATE CURRENT_TIMESTAMP,As per coding guidelines:
**/*.sql要求 “Do not useDEFAULT 0000-00-00 00:00:00”。
Based on learnings: 在conf/db/upgrade/*.sql且存在另一个带ON UPDATE CURRENT_TIMESTAMP的 TIMESTAMP 列时,使用非 CURRENT_TIMESTAMP 的非零默认值可避免 MySQL 5.7 Error 1293/严格模式兼容问题。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@conf/db/upgrade/V5.5.22__schema.sql` around lines 92 - 93, The SQL uses invalid zero DATETIME defaults for columns createDate and lastOpDate which can fail in strict SQL modes; update the column definitions to replace DEFAULT '0000-00-00 00:00:00' with a non-zero sentinel (e.g., a valid past timestamp like '1970-01-01 00:00:00' or CURRENT_TIMESTAMP where appropriate) while preserving the ON UPDATE CURRENT_TIMESTAMP behavior for lastOpDate so that lastOpDate still auto-updates and createDate has a valid non-zero default.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy`:
- Line 57778: The code calls a.conditions.collect directly which throws a NPE
when conditions is null; update the handling of a.conditions (e.g., in the block
where a.conditions is transformed) to guard against null by using a null-check
or defaulting to an empty list before calling collect (for example, replace
direct a.conditions.collect with (a.conditions ?: []) .collect or check if
(a.conditions != null) then map), ensuring downstream logic still works when
a.conditions is absent.
---
Duplicate comments:
In `@conf/db/upgrade/V5.5.22__schema.sql`:
- Around line 92-93: The SQL uses invalid zero DATETIME defaults for columns
createDate and lastOpDate which can fail in strict SQL modes; update the column
definitions to replace DEFAULT '0000-00-00 00:00:00' with a non-zero sentinel
(e.g., a valid past timestamp like '1970-01-01 00:00:00' or CURRENT_TIMESTAMP
where appropriate) while preserving the ON UPDATE CURRENT_TIMESTAMP behavior for
lastOpDate so that lastOpDate still auto-updates and createDate has a valid
non-zero default.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: http://open.zstack.ai:20001/code-reviews/zstack-cloud.yaml (via .coderabbit.yaml)
Review profile: CHILL
Plan: Pro
Run ID: 5c86049b-4b29-41ac-b939-93e7f17d043f
⛔ Files ignored due to path filters (21)
conf/i18n.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-de-DE.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-en_US.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-fr-FR.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-id-ID.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-ja-JP.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-ko-KR.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-ru-RU.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-th-TH.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-zh_CN.jsonis excluded by!**/*.jsonconf/i18n/globalErrorCodeMapping/global-error-zh_TW.jsonis excluded by!**/*.jsonsdk/src/main/java/org/zstack/sdk/AddDnsRecordToVpcRouterAction.javais excluded by!sdk/**sdk/src/main/java/org/zstack/sdk/AddDnsRecordToVpcRouterResult.javais excluded by!sdk/**sdk/src/main/java/org/zstack/sdk/QueryVpcRouterDnsRecordAction.javais excluded by!sdk/**sdk/src/main/java/org/zstack/sdk/QueryVpcRouterDnsRecordResult.javais excluded by!sdk/**sdk/src/main/java/org/zstack/sdk/RemoveDnsRecordFromVpcRouterAction.javais excluded by!sdk/**sdk/src/main/java/org/zstack/sdk/RemoveDnsRecordFromVpcRouterResult.javais excluded by!sdk/**sdk/src/main/java/org/zstack/sdk/UpdateDnsRecordToVpcRouterAction.javais excluded by!sdk/**sdk/src/main/java/org/zstack/sdk/UpdateDnsRecordToVpcRouterResult.javais excluded by!sdk/**sdk/src/main/java/org/zstack/sdk/VpcRouterDnsRecordInventory.javais excluded by!sdk/**sdk/src/main/java/org/zstack/sdk/VpcRouterVmInventory.javais excluded by!sdk/**
📒 Files selected for processing (7)
conf/db/upgrade/V5.5.22__schema.sqlconf/i18n/messages_en_US.propertiesconf/i18n/messages_zh_CN.propertiestestlib/src/main/java/org/zstack/testlib/ApiHelper.groovyutils/src/main/java/org/zstack/utils/clouderrorcode/CloudOperationsErrorCode.javautils/src/main/java/org/zstack/utils/network/NetworkUtils.javautils/src/test/java/org/zstack/utils/test/TestNetworkUtils.java
✅ Files skipped from review due to trivial changes (3)
- utils/src/main/java/org/zstack/utils/clouderrorcode/CloudOperationsErrorCode.java
- conf/i18n/messages_en_US.properties
- conf/i18n/messages_zh_CN.properties
🚧 Files skipped from review as they are similar to previous changes (2)
- utils/src/main/java/org/zstack/utils/network/NetworkUtils.java
- utils/src/test/java/org/zstack/utils/test/TestNetworkUtils.java
| c.delegate = a | ||
| c() | ||
|
|
||
| a.conditions = a.conditions.collect { it.toString() } |
There was a problem hiding this comment.
避免 conditions 为空时触发空指针异常。
Line 57778 直接对 a.conditions 调用 collect。当调用方不传 conditions(例如查询全部记录)时,这里会抛 NullPointerException,导致查询辅助方法不可用。
建议修复
- a.conditions = a.conditions.collect { it.toString() }
+ a.conditions = (a.conditions ?: []).collect { it.toString() }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| a.conditions = a.conditions.collect { it.toString() } | |
| a.conditions = (a.conditions ?: []).collect { it.toString() } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy` at line 57778, The
code calls a.conditions.collect directly which throws a NPE when conditions is
null; update the handling of a.conditions (e.g., in the block where a.conditions
is transformed) to guard against null by using a null-check or defaulting to an
empty list before calling collect (for example, replace direct
a.conditions.collect with (a.conditions ?: []) .collect or check if
(a.conditions != null) then map), ensuring downstream logic still works when
a.conditions is absent.
sync from gitlab !9903