Private Composer Packages with Gemfury
Hopefully you’re familiar with Composer, the latest – and probably greatest – PHP package manager. If not, check out Alexander’s introduction, and I’ve no doubt you’ll be sold on it immediately. You’ll need a working knowledge of it to get the most out of this article.
Composer works effectively and seamlessly in conjunction with Packagist, a comprehensive repository of public packages.
However, sooner or later the time will come when you’ve written your own package which, for whatever reason, cannot be open-sourced and shared freely via Packagist.
There are a few options for hosting these private packages. You can configure your projects’ composer.json
file by adding your packages’ repositories individually. Or, Satis allows you to generate your own static repositories. Alternatively, Toran Proxy allows you to create a self-hosted private version of Packagist, which once set up is much easier to manage than by specifying repositories in your composer.json
.
Gemfury is a PaaS alternative. Aside from the peace-of-mind that comes from a hosted solution – albeit one which comes at a price – one huge advantage is that it supports not just PHP Composer packages, but Ruby Gems, Node.js npm, Python PyPi, APT, Yum and Nu-Get. Great if you have a number of languages under your belt.
Let’s dive in and look at how to use it.
Setting up your Account
To begin with, you’ll need an account. There is a 14-day trial, a free account limited to one collaborator and a single hosted package, as well as a range of other plans starting at US $9 per month.
You can either register using your email address, or with your Github account. Head to the website to sign up.
Creating your First Package
In order to demonstrate how to use Gemfury for private Composer packages, let’s go through the process of creating a package from scratch, which we’ll later submit to the service for use in other projects.
The simplest way to create a new package is to use the following command:
composer init
It will ask you a series of questions; here’s an example transcript of the process:
Welcome to the Composer config generator
This command will guide you through creating your composer.json config.
Package name (<vendor>/<name>) [your-username/package]: your-username/coupon
Description []: Generates a discount coupon code using a super-secret algorithm
Author [Your Name <your-username@example.com>]:
Minimum Stability []: dev
License []: MIT
Define your dependencies.
Would you like to define your dependencies (require) interactively [yes]? yes
Search for a package []: faker
Found 15 packages matching faker
[0] fzaninotto/faker
[1] fzaninotto/faker
[2] bobthecow/faker
[3] tomaj/faker
[4] typo3/faker
[5] yiisoft/yii2-faker
[6] willdurand/faker-bundle
[7] denheck/faker-context
[8] coduo/tutu-faker-extension
[9] davidbadura/faker-bundle
[10] kphoen/faker-service-provider
[11] vegas-cmf/faker
[12] burriko/cake-faker
[13] bit3/faker-cli
[14] emanueleminotto/faker-service-provider
Enter package # to add, or the complete package name if it is not listed []: 0
Enter the version constraint to require []: *
Search for a package []:
Would you like to define your dev dependencies (require-dev) interactively [yes]? no
{
"name": "your-username/coupon",
"description": "Generates a coupon code",
"require": {
"fzaninotto/faker": "*"
},
"license": "MIT",
"authors": [
{
"name": "Your Name",
"email": "your-username@example.com"
}
],
"minimum-stability": "dev"
}
Do you confirm generation [yes]? yes
As you can see, we’re creating a simple package with one dependency, Faker.
Next, let’s add a line to the newly-created composer.json
to tell it where to look for the package’s source code.
"autoload": {
"psr-0": {
"Acme\\": "src/"
}
},
Now let’s create the package itself. We’re going to create a class with a single purpose; to employ a complex, top-secret proprietary algorithm to generate a discount coupon code for an e-commerce platform.
In your working directory, create the src
and src/Acme
directories, then the following file named Coupon.php
:
<?php namespace Acme;
use Faker\Factory;
class Coupon {
public static function generate($percent)
{
$faker = Factory::create();
return sprintf('%s-%s-%d',
strtoupper(date('M')),
strtoupper($faker->word()),
intval($percent));
}
}
Now run composer install
to load our only dependency and to configure the autoloader.
That’s our package built. Now to upload it to Gemfury.
To continue, you’ll need your API key. If you go to your Dashboard, you’ll find it under Settings.
The simplest way to build and upload a package is simply to use Git, and let Gemfury take care of the rest.
Start by creating a .gitignore
file with the following contents:
vendor/
composer.lock
Now initialize the repository:
git init
Add the files:
git add src
git add composer.json
Now we’ll add a Git remote. You can find the relevant URL by selecting Get Started on the Gemfury dashboard, then selecting the “PHP Composer” tab. It will look a little like this:
https://your-username@git.fury.io/your-username/<package-name>.git
Be sure to substitute your-username
with your Gemfury username – if you signed up using Github, it’ll be the same as your Github username – and add it as a remote:
git remote add fury https://your-username@git.fury.io/your-username/coupon.git
At this point, you have two options. The first is to use explicit versioning, where you specify the version in your composer.json
file, like so:
{
"name": "your-username/coupon",
"description": "Generates a coupon code",
"version": "1.0.0",
...
It’s important that you use semantic versioning. Otherwise your package may not build properly; this can also result in some strangely worded error messages.
Alternatively, you can use Git tags. For example, create a new version using a tag as follows:
git tag -a 1.0.0 -m "Version 1.0.0"
Whichever approach you take, the next step is to commit:
git commit -a -m "Initial commit"
Finally, run the following command:
git push fury master --tags
This will push your code up to Gemfury, which will then automatically build it as a package for you.
Now, if you go to your dashboard you should see your new repository listed. Next up, let’s look at how you might use it in a project.
Using a Private Package
If you go back to your dashboard and select “Repos” on the left-hand side, you’ll find your private repo URL. This should remain private, so keep it safe. It’ll look a little like this:
https://php.fury.io/SECRET-CODE/your-username/
It’s the SECRET-CODE
which makes it un-guessable, and therefore effectively private.
Now add it your your project’s composer.json
:
"repositories": [{
"type": "composer",
"url": "https://php.fury.io/SECRET-CODE/your-username/"
}],
You only need add this one repository in order to use any of the private Composer packages you create with Gemfury. No need to add separate repositories each time you want to use a package.
Now you can require
your private packages as if they were on Packagist. Here’s a complete example of a project’s composer.json
:
{
"name": "your-username/my-ecommerce-platform",
"authors": [
{
"name": "Your Name",
"email": "your-username@example.com"
}
],
"repositories": [{
"type": "composer",
"url": "https://php.fury.io/SECRET-CODE/your-username/"
}],
"require": {
"your-username/coupon": "1.0.1"
}
}
Other Approaches
Personally, I believe using Git and tags is the simplest and most effective way to manage your packages.
Alternatively, should you prefer, you can build it yourself by zipping up your package’s source code and uploading it via the Gemfury dashboard.
The Command Line Tool
Gemfury also provides a command-line tool. To install it:
sudo gem install gemfury
To list your packages, you can use the following command:
fury list
Too see the versions of a specific package:
fury versions package-name
For more information about the CLI, visit the relevant section of the documentation.
Summary
In this article I’ve looked at Gemfury, one of a number of options for managing private repositories. As a PaaS solution, it comes without the additional burden of a self-hosted option such as Toran, and it’s simpler to use than Satis. It also has the great benefit of supporting packages across various languages, from PHP Composer packages to Ruby Gems and Node.js npm. Of course, being a PaaS solution, it does come at a cost – but why not try it out using the free trial or the free single-package plan, and see if it works for you.