Composer - installing dependency from private git repository - composer-php

I have two projects on a private GitHub account - one is a library, and the other my application.
I want to include my library into my application.
My library's composer.json looks like this:
{
"name": "andyw/mylibrary",
"description": "My Library",
"license": "proprietary",
"homepage": "https://github.com/andyw/mylibrary",
"require": {
"php": ">=5.5.0",
"monolog/monolog": "1.*",
"guzzle/guzzle": "3.*",
"aws/aws-sdk-php": "2.*",
"nixilla/twitter-api-consumer": "*",
"webignition/robots-txt-file": "dev-master",
"webignition/robots-txt-parser": "dev-master",
"pusher/pusher-php-server": "*",
"symfony/validator": "2.*"
},
"require-dev": {
"phpunit/phpunit": "3.*"
},
"autoload": {
"psr-0": {
"": "src/"
}
}
}
Running composer update on that project installs the dependencies just fine. So far, so good.
Now this is my application's composer.json:
{
"name": "andyw/myapp",
"type": "project",
"description": "My application",
"homepage": "https://github.com/andyw/myapplication",
"license": "proprietary",
"repositories": [
{
"type": "git",
"url": "git#github.com:andyw/myapplication.git"
}
],
"require": {
"php": ">=5.5.0",
"andyw/mylibrary": "dev-master",
"facebook/php-sdk-v4": "4.0.*",
"silex/silex": "~1.1",
"monolog/monolog": "~1.6",
"twig/twig": "~1.14",
"doctrine/dbal": "~2.4",
"nesbot/Carbon": "~1.6",
"aws/aws-sdk-php": "2.*",
"jms/serializer": "0.15",
"symfony/validator": "2.*",
"jdesrosiers/silex-cors-provider": "~0.1.2",
"swiftmailer/swiftmailer": ">=4.1.2,<4.2-dev",
"fzaninotto/faker": "~1.4"
},
"require-dev": {
"mockery/mockery": "~0.8.0"
},
"autoload": {
"psr-0": {
"App": "src/"
}
}
}
Running composer update on that project fails. Adding the --verbose flag gives this output:
Your requirements could not be resolved to an installable set of packages.
Problem 1
- Installation request for andyw/mylibrary dev-master -> satisfiable by andyw/mylibrary[dev-master].
- andyw/mylibrary dev-master requires webignition/robots-txt-file dev-master -> no matching package found.
If mylibrary can install webignition/robots-txt-file dev-master, why can't it be installed as a dependency of a dependency? How can I fix this?
FYI: None of my repos are public and I've changed the names of my packages/files for privacy reasons.

Never never never never depend on branches! Always use a tagged version. This is the most important rule when using Composer.
Branches are moving targets. If anyone commits something new, this will move the pointer to the software's state that you were using, and you cannot easily find this state again. Also, branches are considered development-stability, and the only package that can set stability is the root application package. Libraries that depend on other packages in dev stability are a very bad idea because they force the root application to explicitly allow development stability.
This is extremely bad in the long run. It will make your software unmaintainable to the point where using Composer will always fail, break stuff, and you start wondering why everyone keeps using it (hint: they are not depending on branches).
Now here's the thing:
webignition/robots-txt-file has tagged versions: 0.1 and 0.2, and the 0.2 is exactly at the same commit as the master branch. Just use that!
The same is true for webignition/robots-txt-parser, but here you have version 1.0, 1.0.1 and 1.0.2, and the master branch is exactly version 1.0.2.
You should be able to simply update to these versions. If that does not work because your software relies on an older version of the master branch, you are experiencing the exact problem when depending on branches: Your library told me that dev-master is ok, and when I look at the packages' repo, dev-master is version 0.2 or 1.0.2 respectively, and I'd expect it to work. If you do explicitly point to something like 0.1 and 1.0.1, this is unlikely to change over time and will always be a working combination.
Note that it is a good idea to check if the external package developers use semantic versioning, and then use an appropriate wildcard selector for a version range. Allowing some slack in versions will make multiple packages depending on the same third package to agree on a common version easier.

Related

Can't replace a package with Composer

I made an improvement (PR not merged yet) to an upstream library, guzzlehttp/psr-7, that's a dependency of another package that I depend on, spatie/crawler.
To force Composer to use my package instead of the upstream package, I tried the following:
I branched my fork of the library (branch name: cache-to-string) and updated its composer.json:
"name": "benmorel/guzzle-psr7",
"replace": {
"guzzlehttp/psr7": "1.6.*"
}
I updated my project's composer.json to use my fork instead:
"repositories": [
{
"type": "vcs",
"url": "https://github.com/BenMorel/psr7"
}
],
"require": {
"benmorel/guzzle-psr7": "dev-cache-to-string"
}
And ran composer update, which fails with the following error:
Your requirements could not be resolved to an installable set of packages.
Problem 1
The requested package benmorel/guzzle-psr7 could not be found in any version, there may be a typo in the package name.
How to fix this?
You don't need to change package name in your fork. You don't need to change composer.json of your fork at all. All you need is to add your fork to repositories section and change constraint of required package to use your dev branch:
"repositories": [
{
"type": "vcs",
"url": "https://github.com/BenMorel/psr7"
}
],
"require": {
"guzzlehttp/psr7": "dev-cache-to-string as 1.6.1"
}
Composer will override original guzzlehttp/psr7 package by version from your repository.
Using alias for branch may be required if some other package require guzzlehttp/psr7 - dev-cache-to-string will not match ^1.4. If you use dev-cache-to-string as 1.6.1 as a constraint, your branch will be detected as 1.6.1 release.

Can a composer "master" package pull in dev-master packages without modifying minimum-stability

I want to achieve the following setup (I've omitted other dependencies and stuff for clarity):
Project's composer.json
{
"require": {
"vendor/masterpackage": "*"
}
}
Master package's composer.json
{
"require": {
"vendor/package-1": "dev-master",
"vendor/package-2": "dev-master"
}
}
The master package is versioned with releases, child packages are not, hence the dev-master requirement.
Since minimum-stability can only be set in the root composer.json and is applied to all dependencies (which is undesired in my case), is it possible to set a dev-stability flag for only the master package AND its own dependencies so that its child packages get installed properly? I've already tried "vendor/masterpackage": "*#dev" but to no avail...
The way you experiment with it, it will not work.
The dependencies of depended packages cannot be influenced directly. So if your project prohibits development packages, you are out of luck.
You'd can add these indirect packages into your projects composer.json, adding them with the necessary #dev or dev-X surroundings. That way the will be required directly, allowing for development stability, and the master package requirement will also be fulfilled.
However, be warned that depending on branches is a very very bad habit and makes your dependencies very brittle. The commit id that has been used is recorded, but once you update and it goes wrong, you'll have a hard time juggling all the moving parts, i.e. all repositories that are only providing a branch.
I've found a way to get this working and thought it would be beneficial to post it as an answer for future reference.
Project's composer.json
{
"require": {
"wikimedia/composer-merge-plugin": "dev-master",
"vendorname/masterpackage": "*"
},
"merge-plugin": {
"require": [
"vendor/vendorname/masterpackage/dev-composer.json"
]
}
}
Master package's dev-composer.json
{
"require": {
"vendorname/package-1": "dev-master#dev",
"vendorname/package-2": "dev-master#dev"
}
}
The merge plugin makes this working since it treats dependencies of specified JSON files as if they are in the root composer.json

Nested dependencies and private repositories with composer

At the company I'm currently working we've recently started to move our code into different private repositories so that it's more maintainable and reusable (and also to make it easier to open-source it later).
Every PHP repository is also a Composer package that can be required in our project whenever we need it.
At the moment there's an issue with this approach: every time we need a package that depends on other packages we need to specify those also in the root composer.json.
For example, let's say that the in the root composer.json we need to require two packages company\b and company\c, and that the package company\c needs another package company\d. Then the resulting root composer.json will look like this:
{
"require": {
"company/b": "dev-master",
"company/c": "dev-master",
"company/d": "dev-master"
},
"autoload": {
"psr-4": {
"Company\\" : "src\Company"
}
},
"repositories": [
{
"type": "vcs",
"url": "git#bitbucket.org:company/b.git"
},
{
"type": "vcs",
"url": "git#bitbucket.org:company/c.git"
},
{
"type": "vcs",
"url": "git#bitbucket.org:company/d.git"
}
]
}
Is there a way to avoid specifying nested dependencies in the root composer.json and use the ones specified in the composer.json in every package?
Edit:
Everything I stated before is valid only for the private packages. If a package, let's say company\b, needs a public package that can be found on Packagist then that dependency CAN be specified in the company\b composer.json and it will be imported.
As you correctly found out, only the root package can add repository metadata to the collection of known packages.
I would suggest you take a look at Satis to create a local Composer repository. This would only require you to add this single repository to all your composer.json files of all packages, and it will be used as an updatable source of knowledge about all your private repositories. You no longer have to add a list of Git repos everywhere.
I am successfully hosting around 120 internal packages for our IT enterprise that way. Take this as a sign that once you start splitting isolated tasks into a package, you will get more of them pretty fast.
Also note that it is important to take versioning seriously. Stop depending on branches - tag your software, make releases, use semantic versioning. If you don't, things will break at some point, and people will curse you (correct) or Composer (incorrect) for not working or messing things up.
After a quick search and a look at the Composer documentation I discovered that the repositories can only be specified in the root composer.json.
Additionally it's possible to specify in the root composer.json whether to allow or not development versions of the packages using:
"minimum-stability": "dev",
"prefer-stable": true
Also this issue on GitHub was really useful.

Using composer to require private repos

I've probably misunderstood the docs (https://getcomposer.org) but is it possible to optimise the syntax for composer when including private repos. Ultimately; I want to step away from listing every repository and vendor pair when the vendor is the same...
In my projects composer.json I've got:
"repositories": [{
"type": "vcs",
"url": "git#bitbucket.org:{vendor}/{repo1}.git"
},{
"type": "vcs",
"url": "git#bitbucket.org:{vendor}/{repo2}.git"
},{
"type": "vcs",
"url": "git#bitbucket.org:{vendor}/{repo3}.git"
}]
...
"require": {
"{vendor}/{repo1}": "dev-master",
"{vendor}/{repo2}": "dev-master",
"{vendor}/{repo3}": "dev-master"
}
I figured; as the repositories is an array, then composer would search the repositories for a vendor/repo pair (or something) or if the vendor matches the vendor part of the repository url. It seems syntax heavy for a slight change...
But now I've confused myself by looking at package.json examples :s
Any kicks in the right direction would be great!
A repository does not have to have the same vendor/package name in every branch or tag - the name can change. So adding a repository simply extends the amount of knowledge Composer has about existing packages, while adding package names in require explicitly pinpoints them wherever they may be located.
If you use more than a handful of private repositories, I'd strongly suggest you create a packagist-like repository with either "Packagist", "Satis" or "Toran Proxy". That way you'd only add that one repo to all your composer.json files (not repeating all your private repos all over the place) and the packages you want to use. This greatly reduces the redundancy you feel, because you'd only deal with the package names everywhere, and with the private repository locations in the configuration file of your central repo solution.

composer.json not loading forked repo

I used How to require a fork with composer and https://getcomposer.org/doc/05-repositories.md#vcs to come up with the composer.json file below. I forked a lib to update the composer.json file and it is not loading mine. It is loading the original repo.
"repositories": [{
"type": "vcs",
"url": "https://github.com/Dylan-Buth/gopher"
}],
"require": {
"laravel/framework": "~5.0",
"indatus/gopher": "1.*"
},
Even after you fork the repository, composer will still try to resolve version 1.*. So it will get your forked repository, but it will look up the latest 1.* version. Even if you put * as the version requirement, it will still get the latest tag, not the latest commit.
If you want the latest commit, you can put dev-master as the required version string. Alternatively you could modify the composer.json in your forked package to "alias" the version you want:
{
"extra": {
"branch-alias": {
"dev-master": "1.1"
}
}
}

Resources