When you work with multiple Composer-based repositories, you might find the need to share some PHP code between them. If these were public repositories, this article would be a lot shorter. However, since they're private, you can't just add them to the composer.json
and expect it to work. But don't worry—it's not that difficult to set up either.
Creating our Package
Let's get right into it and create the Composer package we want to share across our private repositories.
GitHub Repository
First, let's create a new Repository in GitHub. We'll call this one composer-package
. Original, I know. Make sure you set it to private. Clone the repository onto your machine and cd
into it.
Composer Initialization
The easiest way to setup a Composer-based PHP project is to run composer init
. You can either run that command as is or pass additional parameters to it (feel free to change them):
composer init \
--name="drazen-bebic/composer-package" \
--description="Private Composer Package" \
--author="Drazen Bebic <drazen@example.com>" \
--type=library \
--license=MIT \
--autoload=src/
Then just follow through with the prompts:
Run composer install
to get everything installed and the autoloader ready. After that, create a .gitignore
and add the vendor
directory to it. When you've done all that you should have exactly 5 things in your project:
.gitignore
composer.json
composer.lock
vendor
src
And if you look at your composer.json
file, it should look a little like this:
{
"name": "drazen-bebic/composer-package",
"description": "Private Composer Package",
"type": "library",
"license": "MIT",
"autoload": {
"psr-4": {
"DrazenBebic\\ComposerPackage\\": "src/"
}
},
"authors": [
{
"name": "Drazen Bebic",
"email": "drazen@example.com"
}
],
"require": {}
}
You surely noticed the autoload
key in your composer.json. This part tells the autoloader where, and under which namespace, it can find the Package's source files.
Versioning
Once you're done, commit and push your changes to GitHub. You're not done yet though! For an easy life, you'll want your Composer packages to be versioned. For them to be versioned, they need to have git tags. So let's add the v1.0.0
tag to our latest commit:
git tag v1.0.0
And now let's push the tag to GitHub:
git push origin tag v1.0.0
Now your package is ready to be consumed in its first ever release - v1.0.0. Instead of pushing tags, you could have also required your package using the branch name, but I find this a little bit easier to understand and it's not that much extra work.
If you really want to go all out on versioning, you could add something like the Semantic Release package and generate your versions automatically.
Consuming in a Public Repository
Let's do the easy one first. Let's say the Composer package is publicly available on GitHub and you want to add it to your project.
To do this, just add the following to your composer.json
:
{
"require": {
...
"drazen-bebic/composer-package": "^1.0.0",
...
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/drazenbebic/composer-package.git"
}
],
}
After that, all you have to do is run composer update
and that's it.
Consuming in a Private Repository
Now the part that you're actually here for. The steps are identical to when you're consuming the package in a public repository, except that there are also a couple of steps on top of that:
Create a GitHub PAT
First we will create a GitHub PAT, aka "Personal Access Token". This access token will be used to authenticate with GitHub and allow us to download the package from the private repository. Let's head over to GitHub and create our token.
We'll select the fine-grained token, give it a name, set the expiration date we want. Don't forget to scope it so that it only has access to the composer-package
repository!
And don't forget to set the correct permissions! All we actually need is the Contents
permission and we want to set it to "Read-only".
Now just hit the "Generate Token" button and you'll be greeted with the following screen:
Copy the token and store it in some sort of Password Manager or something similar because you'll never see the token again once you close this window. I mean, you can always create a new token, but just store it in a secure place. Trust me.
PS: I know. It's on purpose. By the time you're reading this it's already been deleted.
Local Authentication
Now you basically have everything you need. It's time to connect the last couple of dots. To be able to use this locally, on your machine, you need to register the PATH with Composer like so:
composer config -g github-oauth.github.com <YOUR_PAT>
Replace <YOUR_PAT>
with your actual PAT you've generated previously. And that's it! Now you can just run composer install
or composer update
and Composer will be able to install your package locally.
Workflow Authentication
So you've got this working locally, but what if you have a GitHub Workflow which needs to install this package in a GitHub Runner? No worries, it's just a couple of extra steps.
Add the PAT to the GitHub Repository Secrets. I used the
COMPOSER_AUTH
key.In your workflow files, where you're running
composer install
, pass the followingenv
:
Here's an excerpt from my deployment.yml
file:
name: 'Deployment'
on:
workflow_dispatch:
jobs:
deploy:
name: 'Deploy'
timeout-minutes: 20
runs-on: ubuntu-latest
steps:
- uses: shivammathur/setup-php@v2
with:
php-version: 8.3
tools: composer:v2
- name: Install dependencies
run: composer install
env:
COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{secrets.COMPOSER_AUTH}}"} }'
Of course there are other steps before and after, but these are the most important since they install PHP, Composer, and the Composer dependencies using our PAT.
Wrapping up
And that's pretty much it! Linking private GitHub repositories as Composer dependencies isn't as tricky as it might seem. With your package set up, a GitHub PAT in hand, and authentication configured both locally and in your workflows, you're all set to share code across your private repositories.
Here's the link to the Composer Package Repository on my GitHub and a virtual avocado 🥑 for your efforts. Happy Coding!
Top comments (0)