Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Composer repository type depends on environment

I want to add repositories in my composer.json where the source depends on the application environment. For example, if I am in local environment, I want to include repositories from a local file path and if it is in production, then I want to include from GIT.

In local:

"repositories": [
     {
         "type": "path",
         "url": "../local-path"
     },
 ]

In production:

"repositories": [
     {
         "type": "vcs",
         "url": "https://github.com/...."
     },
 ]

In my .env file is an APP_ENV variable. Are there any possibilities to achive this?

like image 827
Jochem Gruter Avatar asked Dec 06 '19 14:12

Jochem Gruter


People also ask

What is composer repositories?

A repository is a package source. It's a list of packages/versions. Composer will look in all your repositories to find the packages your project requires. By default, only the Packagist.org repository is registered in Composer. You can add more repositories to your project by declaring them in composer.

What are composer dependencies?

Composer makes information about the environment Composer runs in available as virtual packages. This allows other packages to define dependencies (require, conflict, provide, replace) on different aspects of the platform, like PHP, extensions or system libraries, including version constraints.


2 Answers

I think this isn't a great idea because you have a risk of potentially committing your composer.lock file from the wrong environment and deploying it. Hopefully you have stricter deployment checks in place though!

I don't have an exact solution, but some options instead:

Use a Composer config file locally

  • No need for separate composer file
  • Might get finicky about versions (I've had trouble getting composer to symlink before)
  • Should allow you to only maintain one composer.json and only touch the config file when you add new local repos

Documentation

In this example I created a project with a simple composer.json.

{
    "name": "mickadoo/test",
    "type": "project",
    "require": {
        "mickadoo/basedata": "dev-master"
    }
}

I added a single requirement which is a package I put on packagist myself years ago.

I then created a dummy library to test it locally with the same name. It was in a library directory which contained only a composer.json file. The goal is to check if composer will install this empty library (no requirements) instead of the online one.

{
    "name": "mickadoo/basedata",
    "type": "library",
    "require": {}
}

I then added a config.json file to the project root with configuration telling composer to add a local repo one directory up:

{
  "repositories": [
    {
      "type": "path",
      "url": "../library"
    }
  ]
}

After all that I tried first running composer update and setting the COMPOSER_HOME env variable to my current directory. This ensures that composer will pick up the config.json and merge it into the configuration it's using.

$ COMPOSER_HOME=$PWD composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing mickadoo/basedata (dev-master): Symlinking from ../library
Writing lock file
Generating autoload files

I then deleted everything I did because I've messed around with local paths in composer before and know it can be frustrating to get working:

$ rm -rf vendor/ && rm composer.lock 

Finally I tried just running composer update as normal, hoping it would skip the config.json and just pull the package from Github.

$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 14 installs, 0 updates, 0 removals
  - Installing symfony/polyfill-apcu (v1.13.1): Downloading (100%)         
  - Installing psr/log (1.1.2): Downloading (100%)         
... more package installs from Github here....
Writing lock file
Generating autoload files

Which it did!

Use a separate composer.json

  • Keeps things pretty visible
  • Separate composer.lock file

Documentation

This would mean maintaining two separate files, like composer.local.json and composer.json. It might be tedious, but at least it's clear what's going on. Based on your COMPOSER env variable you can change which filename it's using

like image 100
mickadoo Avatar answered Oct 22 '22 21:10

mickadoo


I see here a couple of options.

  1. Use a local path to a repository. Then on the dev env checkout different one than on the production. But this would require to keep the local repository in sync with the remote.
  2. Define dist and source for the repository and then differentiate it running composer commands (--prefer-dist on prod, --prefer-source on dev).
  3. Build your own plugin https://getcomposer.org/doc/articles/plugins.md which would jump into action before certain events https://getcomposer.org/doc/articles/scripts.md#event-names
  4. Another option would be to have composer.json file for production and composer-dev.json for development and run the second with setting system ENV variable first:

    COMPOSER=composer-dev.json php composer install

    But this can produce some incompatibility issues (when you forgot to move a package from composer-dev.json to production composer.json.

like image 1
Vokiel Avatar answered Oct 22 '22 21:10

Vokiel