composer/satis

RFC: Satis as a composer 2.3 plugin (POC implementation available)

ralflang opened this issue · 9 comments

Running Satis as a Composer Plugin

tldr - I have mostly implemented a composer plugin that makes a slightly patched satis work as a composer 2.3.x plugin. I want to know if anybody is interested in this before I spend more time on it.

Motivation

I use satis in the build pipeline for a 100+ packages framework. I have recently begun to expand the framework's composer installer plugin to replace older standalone tools that are currently used in CI jobs and in the development process. Discovering the similarities between satis and composer I decided to spend two evening hours on making satis run inside composer

State of the PoC

All four commands are wrapped into shim classes which changes the name to satis:add, satis:build etc and nicely groups them below the native composer commands in a special satis section.

The add and purge commands work as normal.
All commandline options are passed work as desired. I did only limited testing.
The build command sort of works:

  • packagist is not used unless explicitly configured in satis.json

  • in require-all mode, all packages of the configured repos are downloaded. If you enable the packagist repo, you will essentially get a local. static mirror

  • commandline repo filters do work
    - Explicit require lists in the satis.json file currently don't work as expected. Instead, as soon as the satis file contains a require section, the require section of the root package is used. In standalone mode, satis abuses a composer installation and pretends its config file is a root package. I will need to trick the already running composer into accepting satis' config file as the root package.
    Now composer accepts requires from the commandline's json file. This may be a satis.json or your project's root package if that's what you desire. Could actually be a useful edge case.

  • commandline package filters were not tested but likely are affected by the root package issue.

  • In plugin mode, satis does not install its own composer/composer version (unless it is the root package) but runs against the composer phar file which calls into it.

Potential uses/benefits

Composer has a more mature but similar base application, event system, and plugin ecosystem. Hooking satis into composer allows us to shrink satis' codebase. Developers / volunteers can focus on actual functionality and leave infrastucture work to composer/composer which is already maintained much better. Third party plugin developers can leverage satis for their automation or integration plugins and call into it by emitting events (provided satis moves into that direction).

One could easily integrate the little boilerplate plugin into satis itself, in other words make satis itself a composer plugin. I decided to leave that unexplored for the moment and gather feedback first. Maybe there is no interest in this at all.

As a side effect I fixed some incompatibilities between satis (dev-main) and composer 2.3.x

Questions

  • Is there any interest at all in this? If not, at least it was a fun experiment.
  • Which line of development would you prefer, making satis itself the plugin or making satis only capable of working with the plugin library and otherwise leaving it as it is?

Update: I did run this against the phar release of composer 2.4.0 and it did work just as well as with composer 2.3.10.

How to reproduce:

Have a root project with a standin composer.json

{
    "name": "satis/repo",
    "homepage": "horde-satis.maintaina.com",
    "description": "A base project for a satis-generated repo",
    "type": "project",
    "repositories": {
        "ralflang/satis-plugin" : {
            "url": "https://github.com/ralflang/satis-plugin",
            "type": "github"
            },
        "composer/satis": {
          "url": "https://github.com/ralflang/satis",
          "type": "github"

        }
    },
    "require": {
        "composer-plugin-api": "^2.3",
    },
    "require-dev": {
        "ralflang/satis-plugin": "dev-0.1.0-dev"
    },
    "license": "GPL-3.0-only",
    "authors": [
        {
            "name": "Ralf Lang",
            "email": "ralf.lang@ralf-lang.de"
        }
    ],
    "minimum-stability": "dev",
    "prefer-stable": true,
    "config": {
        "allow-plugins": {
            "horde/horde-installer-plugin": true,
            "ralflang/satis-plugin": true
        }
    }
}

now run composer install and if asked, trust the plugin.
now run composerand see the new commands pop up in your help screen

...
 update               [u|upgrade] Updates your dependencies to the latest version according to composer.json, and updates the composer.lock file.
  validate             Validates a composer.json and composer.lock.
 satis
  satis:add            Add repository URL to satis JSON file
  satis:build          Builds a composer repository out of a json file
  satis:configure      
  satis:init           Initialize Satis configuration file
  satis:purge          Purge packages

Unfortunately satis and composer json files are not 100% compatible. They don't tolerate each others' keys like "type" (for composer.json) and the mandatory "homepage" (for satis.json). Otherwise you could use a project's root package composer.json as an input file for a composer satis:build run.

What is your idea behind it? I see I can execute some commands now, but what is intended to happen - in a broad sense and more high-level?

Currently I can have a dedicated configuration file and a dedicated CLI executable, and it is creating my repository. What is happening better/different with the plugin approach?

Ultimately I wanted it to work with composer 2.3/2.4 and then got to play around a bit. Abandoning satis' own Application kernel in favor of hooking into composer's runtime helped me get there fast.

As a stretch goal, to trigger satis based on events programmatically from another composer plugin. Think like #508 but through the intended interface rather than by touching implementation details of composer itself.

Not having satis install its own, outdated copy of composer made sense to me.

As an option, reducing the amount of code that is just a less maintained, older copy of composer's internals and ends up calling into composer anyway also seemed not bad. The plugin approach does not stop you from having a dedicated config file or multiple.

Interesting. If you can make it work as intended, without disrupting normal usage of Satis as most users are accustomed to, then I'm fine with merging your PR.

Yes, that is easily possible.
The current PR creates one disruptive change on purpose:

  • If satis is not the root project, composer will not be installed as a dependency. In this case, a call to the standalone cli creates an instructive error message and aborts.

I will move composer/composer back to the require: section and test for possible conflicting scenarios. I will report back once it is in the PR.

@alcohol I have re-added composer/composer to require section. In my tests it now works in CLI mode both as a root package and as a dependency.

@alcohol Is there anything left to do?

I don't think so, sorry. Will see if I can merge this right now.

Closing as the RFC resulted in a merge.