8. Fork(copy) composer package. Gitlab, github, local. How to add changes to composer package

Video version
(Leave your feedback on YouTube)

Situations where you need to edit a composer dependency for development arise frequently. This could be a simple change in the PHP version requirement that the package maintainer hasn't addressed yet, or unique changes that, for various reasons, aren't included in the package. This also includes packages that are no longer maintained or are in an uncertain state.

GitHub Fork

The vast majority of composer packages host their source code on GitHub. It's easiest to make a copy of the repository for your needs from GitHub with a single click of the "fork" button. A simple form, and you have your own copy of the library.

Here is just one piece of advice - do not edit the main branch of your fork. GitHub allows you to easily sync the original with your fork, which is not so easy when you have conflicts in the main or master branch.

So, the very simple algorithm is to fork the repository, create your own branch, edit it, and add the repository in composer with a link to the fork:

composer.json
{
  "repositories": {
    "github": {
      "type": "vcs",
      "url": "https://github.com/your-github-name/fork-package"
    }
  }
}

And update the package with the version in the format dev-branchname.

The prefix dev- is mandatory, branchname is the name of your branch:

cli
composer req package/name:dev-branchname

GitLab Fork

GitLab supports fully cloning repositories from GitHub (and others). It's important to understand that this functionality is more about project migration rather than forking. But if your project is on GitLab, it makes sense to store all third-party libraries there.

When creating a project (in a group or subgroup where the package will be used), select Import project => Repository by URL. If you are a Premium user, select Mirror repository - and you will automatically receive updates (though for all branches). Be prepared that GitLab will pull all branches and tags.

The recommendation is the same as for GitHub: do not edit the main branch.

Before using the code as a composer package, it needs to be placed in the Package registry.

.gitlab-ci.yml
stages:
  - deploy

deploy_composer:
  image: alpine:3.20.0
  stage: deploy
  before_script:
    - apk add curl
  script:
    - 'curl --header "Job-Token: ${CI_JOB_TOKEN}" --data tag=$CI_COMMIT_TAG "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/composer"'
  rules:
    - if: '$CI_COMMIT_TAG =~ /^(\d+\.)?(\d+\.)?(\*|\d+)-dev$/'

This script will run for all tags in the format semantic version + -dev. The suffix -dev is not mandatory, but I advise adding it to avoid conflicts with the original tags.

Deploy => Package registry will show a list of available packages.

It's important to understand that access to the package repository is implemented through the group; it doesn't work without the group. In the group, you can go to Deploy => Package registry to a specific project and get the command for automatic configuration in composer:

cli
composer config repositories.gitlab.com/pakage_group_id '{"type": "composer", "url": "https://gitlab.com/api/v4/group/PACKAGE_GROUP_ID/-/packages/composer/packages.json"}'

This will create a repository that you can manually add to:

composer.json
{
  "repositories": {
    "gitlab.com": {
      "type": "composer",
      "url": "https://gitlab.com/api/v4/group/pakage_group_id/-/packages/composer/packages.json"
    }
  }
}

This will provide access to all packages in the group:

cli
composer req package/name:tagname

Access to packages is closed by default. Two options for operation:

  1. Allow everyone read access: Settings => General => Visibility, project features, permissions => Package registry => Allow anyone to pull from Package Registry.
  2. Authenticate. For local work - authenticate using username and token with read_api access. Use the command:
cli
composer config gitlab-token.gitlab.com token __token__

This will create an auth.json file - make sure it's in .gitignore.

For a private project CI/CD, make sure: Settings => CI/CD => Token Access => Limit access to this project. Add group or project, add the name of the project or group (subgroup) using the package. And add authentication as a step before installing dependencies:

.gitlab-ci.yml
before_script:
  - docker-compose exec app composer config -- gitlab-token.gitlab.com gitlab-ci-token "${CI_JOB_TOKEN}"

Locally (Docker)

To test the package locally, add the repository:

composer.json
{
  "repositories": {
    "local": {
      "type": "path",
      "url": "/absolute/path_to_package_directory"
    }
  }
}

And update with the command:

cli
composer req package/name:@dev

@dev is mandatory; it tells composer to create a link to the directory with the local package.

If you are working in Docker for local work, the link from the host to the container will not be created. So, it makes sense to create a volume and specify the path to the directory in the container in repositories.local.url. Don't forget to create the directory in the container manually; the volume does not create directories in the container. Example for Docker Compose:

cli
docker compose exec mkdir some_dir

.gitlab-ci.yml
your_service:
  volumes:
    - /absolute/path_to_package_directory:/some_dir

composer.json
{
  "repositories": {
    "local": {
      "type": "path",
      "url": "/some_dir"
    }
  }
}

None of this goes into git! Only for local work.