#64440·server

db:schema:check: 那些代码已被删除(但仍然已注册)的应用程序的表被报告为阻止性发现,而不是非阻止性发现

作者: afischer211创建于 2026年9月16日更新于 2026年9月17日

错误描述 occ db:schema:check 旨在仅将 核心已启用 应用程序中的发现结果视为阻止因素,而属于 已禁用 应用程序的发现结果则单独收集,并从退出代码中排除(SchemaChecker::partitionFindings())。 然而,当一个应用程序被注册为已安装(具有 installed_version 应用程序配置项)但其代码目录不再存在时 - 例如,它以前被使用,并且在没有完整的 occ app:remove 操作的情况下删除了其文件,或者在主要版本升级期间其代码变得不可用,而其 appconfig/表格保留在原位 - SchemaChecker::applyDisabledMigrations() 会抛出 AppPathNotFoundException 并简单地返回,而不重放该应用程序的任何迁移: php 尝试 { $appPath = $this->appManager->getAppPath($app); } 捕获 AppPathNotFoundException { // 已安装,但代码已消失:没有迁移可重放。 返回; } 由于没有为该应用程序添加到内存中的预期模式,因此仍然由其拥有的所有活动表都被报告为 unexpected_table,并且 - 至关重要的是 - 并未归属于任何应用程序($disabledAppTableOwners 对于它保持为空)。 在 getFindings() 中,这使得 enabled 评估为 true: php $finding['enabled'] = $app === null || $app === 'core' || isset($enabledApps[$app]); 因此,来自一个早已不存在的应用程序的孤儿表最终出现在 阻止 容器中,作为普通发现打印出来,并影响退出代码 - 完全像一个真正的核心/已启用应用程序模式问题一样 - 而不是命令明确设计为在此情况下生成的非阻止 "已禁用应用程序" 部分。 同样地,在 applyDisabledMigrations() 内部的 applyMigrations() 附近的 catch (\Throwable) { return; } 循环也可以吞噬一个无法加载的迁移类,因为它引用了同一个应用程序中的其他类,而这些类没有自动加载(已禁用应用程序仅通过 lib/Migration/*.php 直接 require_once 其文件,而不是全面的 PSR-4 自动加载)。 这会为一个 现有但已禁用 应用程序产生相同的错误分类,而没有任何原因的指示。 ## 相关的单独假阳性(相同的命令) 与上述情况无关: occ db:schema:check 可以报告一个应用程序的索引丢失,该应用程序已故意通过 AddMissingIndicesEvent::replaceIndex() 使索引多余,而没有任何迁移正式删除旧索引。 示例: activity 应用程序的初始迁移(Version2006Date20170808154933)创建了 activity_object(object_type, object_id) 和 activity_object_user(affecteduser, object_type, object_id, timestamp)。 后来的 AddMissingIndicesListener 执行: php $event->replaceIndex('activity', ['activity_object'], 'activity_object_user', [...], false); ... 以退出 activity_object 并取代其为替代的 activity_object_user。 由于没有添加任何迁移来删除 activity_object, db:schema:check 的迁移回放仍然期望它,并报告 `oc_activity: 缺失索引 ...

内容来源: nextcloud/server