Working with Composer (PHP)
CodeScoring.Save works as a Composer repository (the composer type) and is compatible with Composer 2.x. You can create:
- a proxy repository — a caching proxy in front of Packagist or another Composer repository (Private Packagist, Satis, Nexus, Artifactory, GitLab, another Save);
- a hosted repository — storage for the company's internal packages.
Composer 1 is not supported.
Creating a Repository in the Web Interface
-
In the sidebar, choose Projects and open the project.
-
Click Create repository.
-
Fill in the common fields Name, Key, Description, and Color — the same way as for other formats (see Repository management).
-
In the Format field, choose PHP / Composer.
-
In the Type field, choose Proxy or Hosted.
-
For Proxy, fill in the additional fields:
-
Proxy URL — the URL of the Composer repository where its
packages.jsonis available: -
Cache TTL, seconds — a required field: how many seconds Save keeps data received from upstream before checking it again. For Packagist,
86400(one day) is enough. -
Authentication — how Save authenticates to upstream. For Packagist, leave
none.Once saved, the password and the token are never shown in the UI or returned by the API: on the edit form, a stored value appears as
********— leave it as is to keep it. Save sends the credentials only to the host from Proxy URL (for details, see Upstream access for proxy repositories).
-
-
Click Create repository.
On the page of the created repository, the chain-link icon button shows ready-made commands for connecting Composer to this particular repository.
The same can be done with an API request. Set format to php and pass the upstream credentials in the auth block:
For a hosted repository, "repository_type": "hosted" without remote_url and auth is enough.
- Package archives are cached on the first download; subsequent installs take them from Save.
- Save does not cache package metadata yet and asks upstream on every request. If upstream is unavailable, Composer can install only what is already in its own cache.
- Packagist package archives are stored on GitHub, so Save needs outbound access to
api.github.comandcodeload.github.com. - Versions that have no zip archive in upstream (source code in git only) cannot be installed through a proxy.
URL Scheme
All paths below are relative to the repository URL https://save.example.com/cs-save/php/<project>/<repository>:
All links inside packages.json and p2/... are absolute: Save builds them from the URL the client used to reach it (taking the X-Forwarded-Host and X-Forwarded-Proto headers into account).
Connecting Composer
The repository URL has the form https://save.example.com/cs-save/php/<project>/<repository>. Add it to your project as a composer type repository and disable packagist.org so that every package goes through Save:
The same in composer.json:
Save accepts http-basic — the Save user's username and password:
From then on, Composer works as usual: composer require, composer install, composer update.
For CI/CD, you can use a robot account: composer config http-basic.save.example.com 'sa$<robot-login>' '<api-key>'. In CI, it is convenient to pass the credentials through the COMPOSER_AUTH environment variable instead of committing auth.json to the repository.
For details on robot accounts, see Authentication.
By default, Composer works over https only. For an environment without TLS, run composer config secure-http false.
Publishing Packages to a Hosted Repository
Composer has no built-in publish command: packages usually reach Packagist or Satis from a git repository. Private registries (Nexus, Artifactory, GitLab) accept a zip archive of the package over HTTP instead. Save accepts the archive the same way Nexus does, so tools that can publish to Nexus work with Save too.
With the composer push Command
The elendev/composer-push plugin adds the composer push command to Composer: it builds a zip archive from the current project (without vendor/, VCS directories, and hidden files) and uploads it.
-
Install the plugin in the package project:
-
Specify the hosted repository URL in
composer.json: -
The plugin takes the username and password from
auth.jsonfor the Save host — the same ones you set withcomposer config http-basic...above. -
Publish the version:
If the version is set in
composer.json, you can omit it.
--src-type, --src-url, and --src-ref
With these options, the plugin sends the archive in a different format, and Save responds with 400. A link to the git source is not needed for packages from Save: Composer downloads them as archives.
From CI Without PHP
If there is no PHP in CI, upload the archive with curl. The --upload-file option sends the file with a PUT request. The package name and the version are part of the URL:
You can also upload the archive to the repository URL itself — the name and the version are then taken from composer.json inside the archive. If composer.json has no version, pass it in the ?version= parameter:
Building the Archive
The easiest way is the composer archive command. It respects archive.exclude and export-ignore from .gitattributes:
git archive --format=zip -o acme-demo-1.0.0.zip v1.0.0 works as well. When publishing with composer push, you do not need to build the archive.
Package Requirements
Save validates the archive before storing it, so nothing is written on error:
- the archive is a zip file, and
composer.jsonis in its root or in a single top-level folder (as in GitHub and GitLab archives); nameincomposer.jsonhas thevendor/packageformat. If the name is also given in the upload URL, it must matchcomposer.json;- the version follows the Composer rules. You can set it in
versionincomposer.jsonor pass it on upload. If it is present in both places, the values must match (v1.0.0and1.0.0are the same version). A branch with a slash in its name (dev-feature/x) cannot be uploaded; - the archive size does not exceed
HOST_PHP_MAX_FILE_SIZE(256 MB by default); otherwise Save responds with413.
A published version cannot be overwritten: uploading it again returns 409. To replace a version, delete it first.
Deleting a Version (hosted)
A version can be deleted in the web interface like any other artifact. There are two ways:
- tick the checkbox to the left of the artifact in the repository tree and click Delete in the panel that appears above the tree. This way you can delete several versions at once;
- click the artifact in the repository tree and, in the right pane, choose Delete artifact in the three-dot menu (next to Download).
Or through the API:
The change is visible in the metadata immediately.
Repository URL Migration
Use case: migrating a Composer repository from Nexus / Artifactory to CodeScoring.Save.
The upload URL packages/upload/<vendor>/<package>/<version> is the same as in Nexus, so composer push and publishing scripts only need the new URL. After changing the URL, run composer update so that composer.lock gets the new archive links.
Troubleshooting
Which Requests Composer Makes
Run Composer with the -vvv option — it shows every URL it requests:
All requests must go to the Save URL. If the links start with http:// although Save is served over https, check that the ingress passes the X-Forwarded-Proto and X-Forwarded-Host headers.
Checking Package Metadata
A 404 means the package exists neither in Save nor in upstream.
