php-tuf/composer-stager

将 Composer 命令分阶段执行,以确保它们可以在生产代码库上安全运行。


README

Latest stable version Tests status Coverage PHPStan

Composer Stager 通过“分阶段”执行,使得长时间运行的 Composer 命令可以在生产代码库上安全运行,以实现尽可能少的停机时间。

适用于谁?

Composer Stager 允许 PHP 产品和框架(如 Drupal)为无法访问更强大的解决方案(如分阶段和蓝绿部署)的用户提供基于 Composer 的自动化自更新。例如,在受限制或低成本托管上,或者在预算或开发人员很少的情况下。它还可以与自定义基于 Composer 的应用程序一起使用。它不针对最终用户。

为什么需要它?

一开始可能不明显,这种工具确实是必要的。为什么不用原地的 Composer?或者为什么不用 rsync 文件来来回回?事实证明,这个问题极其复杂,边缘情况众多。

  • 不能直接在实时代码库上使用 Composer,因为长时间运行的命令将其置于一个未知的中间状态,失败可能会导致不可恢复的损坏。唯一安全的选择是将它复制到其他地方,在那里运行命令,然后将结果同步回实时版本。但是...

  • 可能没有权限写入代码库之外的目录,特别是在低端共享托管上,因此必须提供一种(更复杂的)替代策略,使用实时代码库的子目录。

  • 不能假设有 rsync 这样的工具可用,因此必须提供检测和回退功能。

  • 存在许多跨平台问题,包括 Unix 与 Windows 路径、进程执行特性、禁用的 PHP 函数和符号链接支持等。

  • 符号链接本身就是一个问题空间,具有与技术问题一样多的逻辑问题。

  • 错误消息必须可翻译(i18n/l10n)。

  • 必须考虑非代码文件,如用户上传、缓存文件和日志,这些文件可能在运行复制上的 Composer 命令时在实时代码库中发生变化,并在同步回实时版本时被覆盖。

  • 未能处理任何这些挑战都可能导致灾难性的后果,包括数据丢失或实时代码库的完全破坏。需要预测和防止这些后果,并提供可操作的用户反馈。

还有更多。现在应该很明显,需要一个专门的库。

安装

该库通过 Composer 安装

composer require php-tuf/composer-stager

使用

通过其 PHP API 调用。给定配置的服务容器(见下文),其服务可以使用以下方式使用,例如

class Updater
{
    public function __construct(
        private readonly BeginnerInterface $beginner,
        private readonly StagerInterface $stager,
        private readonly CommitterInterface $committer,
        private readonly CleanerInterface $cleaner,
        private readonly PathFactoryInterface $pathFactory,
        private readonly PathListFactoryInterface $pathListFactory,
    ) {
    }

    public function update(): void
    {
        $activeDir = $this->pathFactory->create('/var/www/public');
        $stagingDir = $this->pathFactory->create('/var/www/staging');
        $exclusions = $this->pathListFactory->create(
            'cache',
            'uploads',
        );

        // Copy the codebase to the staging directory.
        $this->beginner->begin($activeDir, $stagingDir, $exclusions);

        // Run a Composer command on it.
        $this->stager->stage([
            'require',
            'example/package',
            '--update-with-all-dependencies',
        ], $activeDir, $stagingDir);

        // Sync the changes back to the active directory.
        $this->committer->commit($stagingDir, $activeDir, $exclusions);

        // Remove the staging directory.
        $this->cleaner->clean($stagingDir);
    }
}

配置服务

Composer Stager 使用了 依赖注入 模式,并且最佳访问方式是通过支持自动装配的容器,例如 Symfony 的。手动装配是脆弱的,因此不支持官方。

示例

完整的、功能齐全的Composer Stager实现示例可以在Composer Stager Console仓库中找到。

贡献

欢迎提交Pull requests。对于重大变更,请先创建一个问题,讨论您想要进行哪些更改。遵守编码标准,并在可能的情况下,根据适当的情况添加和更新测试

更多信息请参考Wiki。