Private composer packages - no valid composer.json was found

James picture James · Nov 12, 2013 · Viewed 16.4k times · Source

I'm trying to load a library I have hosted on BitBucket using composer as explained both in the official documentation and here, but keep receiving the following error:

[Composer\Repository\InvalidRepositoryException]
No valid composer.json was found in any branch or tag of [repository URL], could not load a package from it.

Here is my project composer.json:

{
    "name": "Project name",
    "require": {
        "my-vendor/my-package": "dev-master"
    },
    "repositories": [
        {
            "type": "vcs",
            "url": [repository URL]
        }
    ]
}

And here is the composer.json in my remote repository (that apparently can't be found):

{
    "name": "my-vendor/my-package",
    "version": "0.3",
    "autoload": {
        "psr-0": {
            "NS_": "src"
        }
    }
}

I should mention that both composer.json files are in the root directory as they should be.

Some other things to note:

I've also tried the "non-composer package" approach, whereby I specify the package information in my project composer.json, and omit the composer.json from my remote repository, as outlined in the documentation. This successfully clones the master branch but then results in the following error:

[RuntimeException]
Failed to execute git checkout "master" && git reset --hard "master"

fatal: Not a git repository (or any of the parent directories): .git

However, the package is downloaded to /vendor as expected, so I'm not sure why it's trying to checkout master again.

This is not the way I wish to solve this problem (as I'd rather make use of a composer.json in the remote repository), but it might help identify an issue elsewhere.

Thanks for any help.

EDIT

I've managed to get it working by referencing a package.json over HTTP:

"repositories": [
    {
        "type": "composer",
        "url": "http://localhost/packages.json"
    }
]

The packages.json looks like:

{
    "packages": {
        "vendor/my-package": {
            "dev-master": {
                "name": "vendor/my-package",
                "version": "dev-master",
                "source": {
                    "url": [repository URL],
                    "type": "git",
                    "reference": "master"
                }
            }
        }
    }
}

Is this the only way to get this working? It seems a bit overkill to host my own packages.json file if I'm only going to be using one or two in-house packages.

Regardless, this is giving me the same Git error as I mentioned previously.

EDIT 2

Forcing an error (invalid SSH passphrase) gives this:

[RuntimeException]
Failed to execute git clone "[repository URL]" "C:\workspace\DFv3\vendor\vendor/my-package" && cd /D "C:\workspace\DFv3\vendor\vendor/my-package" && git remote add composer "[repository URL]" && git fetch composer

So I can clearly see what it's doing here. However, it seems after this command runs it cds into the .git directory and tries running:

git checkout "master" && git reset --hard "master"

Presumably to get rid of the composer instance it pulled. However, it's running this in the wrong directory and I can't figure out why..

Answer

Sven picture Sven · Nov 13, 2013

You must not include a version specification in your library's composer.json if it is actually managed by a supported source control system. Currently you are saying that your master branch IS version 0.3 (which is a stable version), but you are trying to include "dev-master" (which is an unstable version). Composer might get confused if that software really is "dev-master" or "version 0.3".

If you actually are developing new releases for the 0.3.x series in your master branch, you should define a branch alias instead. Add this to your current development branch for versions 0.3.x:

"extra": {
    "branch-alias": {
        "dev-master": "0.3.x-dev"
    }
}

If you want to move on to version 0.4 or 1.0, you'd branch at the "last" state of the 0.3 series with a branch named "0.3.x" and then update the composer.json in the master branch to point dev-master to a new alias (like "dev-master": "0.4.x-dev"). You could also name your old 0.3 branch anyway you like and then add an alias for THAT branch.

Doing this will enable you to require the latest development version of 0.3.x like this:

"require": {
    "my-vendor/my-package": "0.3.*@dev"
}

This will pull the latest 0.3 version - which currently would be the latest commit in the master branch because of the defined alias.

The way you are currently set up forces you to explicitly include version 0.3, which is a moving target without making that fact explicitly known.

Giving an explicit version tag should only be done if there is no version control system available that is able to give Composer the version number, i.e. there are no tags available, or the tags do not comply with Composer's requirement for version numbers. Since you seem to be in control of that vcs, it probably is a good idea to make the tags conform to Composers standard instead of making it troublesome to release a new version.

After you fixed this, I do expect your installation to NOT require that package.json file anymore, because that file now repairs the trouble you created with that version declaration. You'd then also not need that composer reference anymore, but can revert back to mentioning the original repository like you did.

If you feel you are using too many private repositories which are all requiring more private repositories, and are sick of mentioning them all in a long list, you could think about using Satis to create such a list of found packages instead of manually creating them.