Unknown Image
Drazen

Drazen

Published 17th Sep 2024

Linking Private GitHub Repositories as Composer Dependencies

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.

New fine-grained personal access 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!

Repository access

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".

Permissions

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.

  1. Add the PAT to the GitHub Repository Secrets. I used the COMPOSER_AUTH key.

  2. In your workflow files, where you're running composer install, pass the following env:

    COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{secrets.COMPOSER_AUTH}}"} }'
    

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!

© Drazen Bebic — 2024. All Rights Reserved.

LinkedIndev.toGitHubMediumWordPress