├── LICENSE ├── README.md ├── composer.json └── src ├── Api ├── AbstractApi.php ├── Credentials.php ├── Customers.php ├── Customers │ ├── MagentoLegacyKeys.php │ └── VendorBundles.php ├── Jobs.php ├── MirroredRepositories.php ├── Organization.php ├── Packages.php ├── Packages │ └── Artifacts.php ├── Projects.php ├── Projects │ ├── MirroredRepositories.php │ └── Packages.php ├── SecurityIssues.php ├── Suborganizations.php ├── Suborganizations │ ├── MirroredRepositories.php │ └── Packages.php ├── Subrepositories.php ├── Subrepositories │ ├── MirroredRepositories.php │ └── Packages.php ├── Synchronizations.php ├── Teams.php ├── Tokens.php ├── VendorBundles.php └── VendorBundles │ └── Packages.php ├── Client.php ├── Exception ├── ErrorException.php ├── ExceptionInterface.php ├── HttpTransportException.php ├── InvalidArgumentException.php ├── JobErrorException.php ├── JobTimeoutException.php ├── ResourceNotFoundException.php └── RuntimeException.php ├── HttpClient ├── HttpPluginClientBuilder.php ├── Message │ └── ResponseMediator.php └── Plugin │ ├── ExceptionThrower.php │ ├── PathPrepend.php │ └── RequestSignature.php ├── JobHelper.php ├── Payload ├── ArtifactPackageConfig.php ├── CustomPackageConfig.php └── VcsPackageConfig.php ├── TeamPermissions.php └── WebhookSignature.php /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright Packagist Conductors GmbH 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Private Packagist API Client 2 | 3 | ## Table of Contents 4 | 5 | * [Private Packagist API Client](#private-packagist-api-client) 6 | * [Table of Contents](#table-of-contents) 7 | * [Requirements](#requirements) 8 | * [Install](#install) 9 | * [Basic usage of private-packagist/api-client client](#basic-usage-of-private-packagistapi-client-client) 10 | * [Documentation](#documentation) 11 | * [Organization](#organization) 12 | * [Trigger a full synchronization](#trigger-a-full-synchronization) 13 | * [Team](#team) 14 | * [List an organization's teams](#list-an-organizations-teams) 15 | * [Create a New Team](#create-a-new-team) 16 | * [Show a Team](#show-a-team) 17 | * [Edit a Team](#edit-a-team) 18 | * [Grant All Package Access](#grant-all-package-access) 19 | * [Revoke All Package Access](#revoke-all-package-access) 20 | * [Delete a Team](#delete-a-team) 21 | * [Add Member to Team (by User ID)](#add-member-to-team-by-user-id) 22 | * [Remove Member from Team](#remove-member-from-team) 23 | * [List all private packages a team has access to](#list-all-private-packages-a-team-has-access-to) 24 | * [Grant a team access to a list of private packages](#grant-a-team-access-to-a-list-of-private-packages) 25 | * [Remove access for a package from a team](#remove-access-for-a-package-from-a-team) 26 | * [Authentication Tokens](#authentication-tokens) 27 | * [List an organization's team authentication tokens](#list-an-organizations-team-authentication-tokens) 28 | * [Create a new team authentication token](#create-a-new-team-authentication-token) 29 | * [Delete a team authentication token](#delete-a-team-authentication-token) 30 | * [Regenerate a team authentication token](#regenerate-a-team-authentication-token) 31 | * [Customer](#customer) 32 | * [List an organization's customers](#list-an-organizations-customers) 33 | * [Show a customer](#show-a-customer) 34 | * [Create a customer](#create-a-customer) 35 | * [Edit a customer](#edit-a-customer) 36 | * [Delete a customer](#delete-a-customer) 37 | * [Enable a customer](#enable-a-customer) 38 | * [Disable a customer](#disable-a-customer) 39 | * [List a customer's packages](#list-a-customers-packages) 40 | * [Show a customer's package](#show-a-customers-package) 41 | * [Grant a customer access to a package or edit the limitations](#grant-a-customer-access-to-a-package-or-edit-the-limitations) 42 | * [Revoke access to a package from a customer](#revoke-access-to-a-package-from-a-customer) 43 | * [Regenerate a customer's Composer repository token](#regenerate-a-customers-composer-repository-token) 44 | * [List a customer's vendor bundles](#list-a-customers-vendor-bundles) 45 | * [Grant a customer access to a vendor bundle or edit the limitations](#grant-a-customer-access-to-a-vendor-bundle-or-edit-the-limitations) 46 | * [Revoke access to a vendor bundle from a customer](#revoke-access-to-a-vendor-bundle-from-a-customer) 47 | * [Vendor Bundle](#vendor-bundle) 48 | * [List an organization's vendor bundles](#list-an-organizations-vendor-bundles) 49 | * [Show a vendor bundle](#show-a-vendor-bundle) 50 | * [Create a vendor bundle](#create-a-vendor-bundle) 51 | * [Edit a customer](#edit-a-customer-1) 52 | * [Delete a vendor bundle](#delete-a-vendor-bundle) 53 | * [List packages in a vendor bundle](#list-packages-in-a-vendor-bundle) 54 | * [Add one or more packages to a vendor bundle or edit their limitations](#add-one-or-more-packages-to-a-vendor-bundle-or-edit-their-limitations) 55 | * [Remove a package from a vendor bundle](#remove-a-package-from-a-vendor-bundle) 56 | * [Suborganization](#suborganization) 57 | * [List an organization's suborganizations](#list-an-organizations-suborganizations) 58 | * [Show a suborganization](#show-a-suborganization) 59 | * [Create a suborganization](#create-a-suborganization) 60 | * [Delete a suborganization](#delete-a-suborganization) 61 | * [List a suborganization's teams](#list-a-suborganizations-teams) 62 | * [Add a team to a suborganization or edit the permission](#add-a-team-to-a-suborganization-or-edit-the-permission) 63 | * [Remove a team from a suborganization](#remove-a-team-from-a-suborganization) 64 | * [List a suborganization's packages](#list-a-suborganizations-packages) 65 | * [Show a suborganization package](#show-a-suborganization-package) 66 | * [Create a vcs package in a suborganization](#create-a-vcs-package-in-a-suborganization) 67 | * [Create a vcs package with credentials in a suborganization](#create-a-vcs-package-with-credentials-in-a-suborganization) 68 | * [Create a custom package in a suborganization](#create-a-custom-package-in-a-suborganization) 69 | * [Create a custom package with credentials in a suborganization](#create-a-custom-package-with-credentials-in-a-suborganization) 70 | * [Edit a vcs package in a suborganization in a suborganization](#edit-a-vcs-package-in-a-suborganization-in-a-suborganization) 71 | * [Edit a custom package in a suborganization](#edit-a-custom-package-in-a-suborganization) 72 | * [Delete a package from a suborganization](#delete-a-package-from-a-suborganization) 73 | * [List all dependents of a suborganization package](#list-all-dependents-of-a-suborganization-package) 74 | * [List a suborganization's authentication tokens](#list-a-suborganizations-authentication-tokens) 75 | * [Create a suborganization authentication token](#create-a-suborganization-authentication-token) 76 | * [Delete a suborganization authentication token](#delete-a-suborganization-authentication-token) 77 | * [Regenerate a suborganization authentication token](#regenerate-a-suborganization-authentication-token) 78 | * [List a suborganization's mirrored repositories](#list-a-suborganizations-mirrored-repositories) 79 | * [Show a mirrored repository](#show-a-mirrored-repository) 80 | * [Add mirrored repositories to a suborganization](#add-mirrored-repositories-to-a-suborganization) 81 | * [Edit the mirroring behaviour of mirrored repository in a suborganization](#edit-the-mirroring-behaviour-of-mirrored-repository-in-a-suborganization) 82 | * [Delete a mirrored repository from a suborganization](#delete-a-mirrored-repository-from-a-suborganization) 83 | * [List all mirrored packages from a mirrored repository in a suborganization](#list-all-mirrored-packages-from-a-mirrored-repository-in-a-suborganization) 84 | * [Add mirrored packages from one mirrored repository to a suborganization](#add-mirrored-packages-from-one-mirrored-repository-to-a-suborganization) 85 | * [Remove all mirrored packages from one mirrored repository in a suborganization](#remove-all-mirrored-packages-from-one-mirrored-repository-in-a-suborganization) 86 | * [Package](#package) 87 | * [List an organization's packages](#list-an-organizations-packages) 88 | * [Show a package](#show-a-package) 89 | * [Create a vcs package](#create-a-vcs-package) 90 | * [Create a vcs package with credentials](#create-a-vcs-package-with-credentials) 91 | * [Create a vcs package with a specific type](#create-a-vcs-package-with-a-specific-type) 92 | * [Create a custom package](#create-a-custom-package) 93 | * [Create a custom package with credentials](#create-a-custom-package-with-credentials) 94 | * [Edit a vcs package](#edit-a-vcs-package) 95 | * [Edit a custom package](#edit-a-custom-package) 96 | * [Delete a package](#delete-a-package) 97 | * [List all dependents of a package](#list-all-dependents-of-a-package) 98 | * [List all customers with access to a package](#list-all-customers-with-access-to-a-package) 99 | * [List all security issues of a package](#list-all-security-issues-of-a-package) 100 | * [Show the security monitoring config of a package](#show-the-security-monitoring-config-of-a-package) 101 | * [Edit the security monitoring config of a package](#edit-the-security-monitoring-config-of-a-package) 102 | * [Create an artifact package file](#create-an-artifact-package-file) 103 | * [Create an artifact package](#create-an-artifact-package) 104 | * [Add an artifact file to an existing package](#add-an-artifact-file-to-an-existing-package) 105 | * [Update or replace artifact files of a package](#update-or-replace-artifact-files-of-a-package) 106 | * [Credential](#credential) 107 | * [List an organization's credentials](#list-an-organizations-credentials) 108 | * [Show a credential](#show-a-credential) 109 | * [Create a credential](#create-a-credential) 110 | * [Edit a credential](#edit-a-credential) 111 | * [Delete a credential](#delete-a-credential) 112 | * [Mirrored Repository](#mirrored-repository) 113 | * [List an organization's mirrored repositories](#list-an-organizations-mirrored-repositories) 114 | * [Show a mirrored repository](#show-a-mirrored-repository-1) 115 | * [Create a mirrored repository](#create-a-mirrored-repository) 116 | * [Edit a mirrored repository](#edit-a-mirrored-repository) 117 | * [Delete a mirrored repository](#delete-a-mirrored-repository) 118 | * [List all mirrored packages from one repository](#list-all-mirrored-packages-from-one-repository) 119 | * [Add mirrored packages from one repository](#add-mirrored-packages-from-one-repository) 120 | * [Remove all mirrored packages from one repository](#remove-all-mirrored-packages-from-one-repository) 121 | * [Job](#job) 122 | * [Show a job](#show-a-job) 123 | * [Wait for a job to finish](#wait-for-a-job-to-finish) 124 | * [Security Issue](#security-issue) 125 | * [List an organization's security issues](#list-an-organizations-security-issues) 126 | * [Magento legacy keys](#magento-legacy-keys) 127 | * [List all legacy keys for a customer](#list-all-legacy-keys-for-a-customer) 128 | * [Create a new legacy keys for a customer](#create-a-new-legacy-keys-for-a-customer) 129 | * [Delete a legacy keys from a customer](#delete-a-legacy-keys-from-a-customer) 130 | * [Validate incoming webhook payloads](#validate-incoming-webhook-payloads) 131 | * [License](#license) 132 | 133 | 134 | 135 | 136 | 137 | 138 | ## Requirements 139 | 140 | * PHP >= 7.2 141 | * [Guzzle](https://github.com/guzzle/guzzle) library, 142 | 143 | ## Install 144 | 145 | Via Composer: 146 | 147 | ```bash 148 | $ composer require private-packagist/api-client guzzlehttp/guzzle 149 | ``` 150 | 151 | Why do you need to require `guzzlehttp/guzzle`? We are decoupled from any HTTP messaging client with help by [HTTPlug](http://httplug.io/), so you can pick an HTTP client of your choice, guzzle is merely a recommendation. 152 | 153 | ## Basic usage of `private-packagist/api-client` client 154 | 155 | ```php 156 | authenticate('api-key', 'api-secret'); 163 | $packages = $client->packages()->all(); 164 | ``` 165 | 166 | From `$client` object, you can access the full Private Packagist API. 167 | 168 | ## Documentation 169 | 170 | Full documentation can be found in the [Private Packagist documentation](https://packagist.com/docs/api). 171 | 172 | ### Organization 173 | 174 | #### Trigger a full synchronization 175 | ```php 176 | $jobs = $client->organization()->sync(); 177 | ``` 178 | Returns an array of created jobs. One for every synchronization. 179 | 180 | ### Team 181 | 182 | The permissions available for a team are: 183 | - `canEditTeamPackages`: members of the team can edit and remove packages, assign package permissions (only applies to packages assigned to team). 184 | - `canAddPackages`: members of the team can add packages to organization; add, edit and remove credentials and mirrored third-party repositories. 185 | - `canCreateSuborganizations`: members of the team can create suborganizations. 186 | - `canViewVendorCustomers`: members of the team can view customers, their Composer information, their packages, and their install statistics. 187 | - `canManageVendorCustomers`: members of the team can create and delete customers, add and remove packages, update their settings, view Composer information and install statistics. 188 | 189 | ```php 190 | use PrivatePackagist\ApiClient\TeamPermissions; 191 | 192 | $permissions = new TeamPermissions; 193 | // Grant all permissions. 194 | $permissions->canEditTeamPackages = true; 195 | $permissions->canAddPackages = true; 196 | $permissions->canCreateSuborganizations = true; 197 | $permissions->canManageVendorCustomers = true; 198 | $permissions->canManageVendorCustomers = true; 199 | ``` 200 | 201 | The permissions model can also be constructed via flags: 202 | 203 | ```php 204 | use PrivatePackagist\ApiClient\TeamPermissions; 205 | 206 | $permissions = TeamPermissions::fromFlags( 207 | TeamPermissions::PERMISSION_CAN_EDIT_TEAM_PACKAGES | TeamPermissions::PERMISSION_CAN_ADD_PACKAGES, 208 | ); 209 | ``` 210 | 211 | Or from the permissions of an existing team: 212 | 213 | ```php 214 | use PrivatePackagist\ApiClient\TeamPermissions; 215 | 216 | $team = $client->teams()->all()[0]; 217 | $permissions = TeamPermissions::fromTeamResponse($team); 218 | ``` 219 | 220 | #### List an organization's teams 221 | ```php 222 | $teams = $client->teams()->all(); 223 | ``` 224 | Returns an array of teams. 225 | 226 | #### Create a New Team 227 | ```php 228 | use PrivatePackagist\ApiClient\TeamPermissions; 229 | 230 | $permissions = new TeamPermissions; 231 | $team = $client->teams()->create('New Team Name', $permissions); 232 | ``` 233 | Creates a team and sets permissions applied to team members. Returns the newly-created team. 234 | 235 | #### Show a Team 236 | ```php 237 | 238 | $team = $client->teams()->show($teamId); 239 | ``` 240 | Returns the team including all its members. 241 | 242 | 243 | #### Edit a Team 244 | ```php 245 | use PrivatePackagist\ApiClient\TeamPermissions; 246 | 247 | $permissions = new TeamPermissions; 248 | $team = $client->teams()->edit($teamId, 'Altered Team Name', $permissions); 249 | ``` 250 | Edits a team's name and permissions to be applied to team members. Returns the updated team. 251 | 252 | #### Grant All Package Access 253 | ```php 254 | $team = $client->teams()->grantAccessToAllPackages($teamId); 255 | ``` 256 | 257 | Granting a team access to all packages will give this team access to all current and future organization packages which do not have their permissions synchronized. 258 | 259 | #### Revoke All Package Access 260 | ```php 261 | $team = $client->teams()->revokeAccessToAllPackages($teamId); 262 | ``` 263 | 264 | Revoking a team's access to all packages will not remove access to packages the team can currently access, but will prevent access to new packages and allow revoking individual package access. 265 | 266 | #### Delete a Team 267 | ```php 268 | $client->teams()->remove($teamId); 269 | ``` 270 | 271 | #### Add Member to Team (by User ID) 272 | ```php 273 | $team = $client->teams()->addMember($teamId, $userId); 274 | ``` 275 | Returns the team the user was added to. 276 | 277 | #### Remove Member from Team 278 | ```php 279 | $client->teams()->removeMember($teamId, $userId); 280 | ``` 281 | 282 | #### List all private packages a team has access to 283 | ```php 284 | $teamId = 1; 285 | $packages = $client->teams()->packages($teamId); 286 | ``` 287 | Returns an array of packages. 288 | 289 | #### Grant a team access to a list of private packages 290 | 291 | You pass an array of packages to give access to. The values of the array can be either package ID or package name. 292 | 293 | ```php 294 | $teamId = 1; 295 | $packages = $client->teams()->addPackages($teamId, ['acme-website/package', 1]); 296 | ``` 297 | Returns an array of packages. 298 | 299 | #### Remove access for a package from a team 300 | 301 | You can use the package ID or package name as a reference. 302 | 303 | ```php 304 | $teamId = 1; 305 | $packages = $client->teams()->removePackage($teamId, 'acme-website/package'); 306 | ``` 307 | 308 | ### Authentication Tokens 309 | 310 | #### List an organization's team authentication tokens 311 | ```php 312 | $tokens = $client->tokens()->all(); 313 | ``` 314 | Returns an array of team tokens. 315 | 316 | #### Create a new team authentication token 317 | ```php 318 | // Create a new token with access to all packages 319 | $token = $client->tokens()->create([ 320 | 'description' => 'New Team Token', 321 | 'access' => 'read', 322 | 'accessToAllPackages' => true, 323 | ]); 324 | 325 | // Create a new token with access to packages a team has access to 326 | $token = $client->tokens()->create([ 327 | 'description' => 'New Team Token', 328 | 'access' => 'read', 329 | 'teamId' => 1, // Get teamId from the list of teams to determine to which packages the token has access to 330 | ]); 331 | ``` 332 | Returns the created token. 333 | 334 | #### Delete a team authentication token 335 | ```php 336 | $client->tokens()->remove($tokenId)); 337 | ``` 338 | 339 | #### Regenerate a team authentication token 340 | ```php 341 | $customerId = 42; 342 | $confirmation = [ 343 | 'IConfirmOldTokenWillStopWorkingImmediately' => true, 344 | ]; 345 | $token = $client->tokens()->regenerateToken($tokenId, $confirmation); 346 | ``` 347 | Returns the regenerated token. 348 | 349 | ### Customer 350 | 351 | #### List an organization's customers 352 | ```php 353 | $customers = $client->customers()->all(); 354 | ``` 355 | Returns an array of customers. 356 | 357 | #### Show a customer 358 | ```php 359 | $customerId = 42; 360 | $customer = $client->customers()->show($customerId); 361 | // or 362 | $customerUrlName = 'customer-url-name'; 363 | $customer = $client->customers()->show($customerUrlName); 364 | ``` 365 | Returns a single customer. 366 | 367 | #### Create a customer 368 | ```php 369 | $customer = $client->customers()->create('New customer name'); 370 | // or 371 | $customer = $client->customers()->create('New customer name', false, 'customer-url-name', 'beta', true); 372 | ``` 373 | Returns the customer. 374 | 375 | #### Edit a customer 376 | ```php 377 | $customerId = 42; 378 | $customerData = [ 379 | 'name' => $name, 380 | 'urlName' => 'customer', 381 | 'accessToVersionControlSource' => false, 382 | 'minimumAccessibleStability' => 'beta', 383 | 'assignAllPackages' => true, 384 | ]; 385 | $customer = $client->customers()->edit($customerId, $customerData); 386 | ``` 387 | Returns the customer. 388 | 389 | #### Delete a customer 390 | ```php 391 | $customerId = 42; 392 | $client->customers()->remove($customerId); 393 | ``` 394 | 395 | #### Enable a customer 396 | ```php 397 | $customerId = 42; 398 | $customer = $client->customers()->enable($customerId); 399 | ``` 400 | 401 | #### Disable a customer 402 | ```php 403 | $customerId = 42; 404 | $customer = $client->customers()->disable($customerId); 405 | ``` 406 | 407 | #### List a customer's packages 408 | ```php 409 | $customerId = 42; 410 | $packages = $client->customers()->listPackages($customerId); 411 | ``` 412 | Returns an array of customer packages. 413 | 414 | #### Show a customer's package 415 | ```php 416 | $customerId = 42; 417 | $package = $client->customers()->showPackage($customerId, $packageName); 418 | $accessibleVersions = $package['versions']; 419 | ``` 420 | Returns a customer's package, including the versions that the customer has been granted access to. 421 | 422 | #### Grant a customer access to a package or edit the limitations 423 | ```php 424 | $customerId = 42; 425 | $packages = [ 426 | [ 427 | 'name' => 'acme-website/package', 428 | 'versionConstraint' => '^1.0 | ^2.0', // optional version constraint to limit updates the customer receives 429 | 'expirationDate' => (new \DateTime())->add(new \DateInterval('P1Y'))->format('c'), // optional expiration date to limit updates the customer receives 430 | 'minimumAccessibleStability' => 'beta', // optional stability to restrict customers to specific package version stabilities like alpha, beta, or RC 431 | ], 432 | ]; 433 | $packages = $client->customers()->addOrEditPackages($customerId, $packages); 434 | ``` 435 | Returns an array of all added or edited customer packages. 436 | 437 | #### Revoke access to a package from a customer 438 | 439 | You can reference the package by its ID or name. 440 | 441 | ```php 442 | $customerId = 42; 443 | $packageName = 'acme-website/package'; 444 | $client->customers()->removePackage($customerId, $packageName); 445 | ``` 446 | 447 | #### Regenerate a customer's Composer repository token 448 | ```php 449 | $customerId = 42; 450 | $confirmation = [ 451 | 'IConfirmOldTokenWillStopWorkingImmediately' => true, 452 | ]; 453 | $composerRepository = $client->customers()->regenerateToken($customerId, $confirmation); 454 | ``` 455 | Returns the edited Composer repository. 456 | 457 | #### List a customer's vendor bundles 458 | ```php 459 | $customerId = 42; 460 | $packages = $client->customers()->vendorBundles()->listVendorBundles($customerId); 461 | ``` 462 | Returns an array of customer vendor bundles. 463 | 464 | #### Grant a customer access to a vendor bundle or edit the limitations 465 | ```php 466 | $customerId = 42; 467 | $vendorBundleId = 12; 468 | $expirationDate = (new \DateTime())->add(new \DateInterval('P1Y'))->format('c'), // optional expiration date to limit updates the customer receives 469 | $packages = $client->customers()->vendorBundles()->addOrEditVendorBundle($customerId, $vendorBundleId, $expirationDate); 470 | ``` 471 | Returns the added or edited customer vendor bundle. 472 | 473 | #### Revoke access to a vendor bundle from a customer 474 | ```php 475 | $customerId = 42; 476 | $vendorBundleId = 12; 477 | $client->customers()->vendorBundles()->removeVendorBundle($customerId, $vendorBundleId); 478 | ``` 479 | 480 | ### Vendor Bundle 481 | 482 | #### List an organization's vendor bundles 483 | ```php 484 | $vendorBundles = $client->vendorBundles()->all(); 485 | ``` 486 | Returns an array of vendor bundles. 487 | 488 | #### Show a vendor bundle 489 | ```php 490 | $vendorBundleId = 42; 491 | $vendorBundle = $client->vendorBundles()->show($vendorBundleId); 492 | ``` 493 | Returns a single vendor bundle. 494 | 495 | #### Create a vendor bundle 496 | ```php 497 | $vendorBundle = $client->vendorBundles()->create('New bundle name'); 498 | // or 499 | $vendorBundle = $client->vendorBundles()->create('New bundle name', 'dev', '^1.0', true, [123]); 500 | ``` 501 | Returns the vendor bundle. 502 | 503 | #### Edit a customer 504 | ```php 505 | $vendorBundleId = 42; 506 | $vendorBundleData = [ 507 | 'name' => 'Bundle name', 508 | 'minimumAccessibleStability' => 'dev', 509 | 'versionConstraint' => '^1.0', 510 | 'assignAllPackages' => true, 511 | 'synchronizationIds' => [123], // A list of synchronization ids for which new packages should automatically be added to the bundle. 512 | ]; 513 | $vendorBundle = $client->vendorBundles()->edit($vendorBundleId, $vendorBundleData); 514 | ``` 515 | Returns the vendor bundle. 516 | 517 | #### Delete a vendor bundle 518 | ```php 519 | $vendorBundleId = 42; 520 | $client->vendorBundles()->remove($vendorBundleId); 521 | ``` 522 | 523 | #### List packages in a vendor bundle 524 | ```php 525 | $vendorBundleId = 42; 526 | $packages = $client->vendorBundles()->packages()->listPackages($vendorBundleId); 527 | ``` 528 | Returns an array of vendor bundle packages. 529 | 530 | #### Add one or more packages to a vendor bundle or edit their limitations 531 | ```php 532 | $vendorBundleId = 42; 533 | $packages = [ 534 | [ 535 | 'name' => 'acme-website/package', 536 | 'versionConstraint' => '^1.0 | ^2.0', // optional version constraint to limit updates the customer receives 537 | 'minimumAccessibleStability' => 'beta', // optional stability to restrict customers to specific package version stabilities like alpha, beta, or RC 538 | ], 539 | ]; 540 | $packages = $client->vendorBundles()->packages()->addOrEditPackages($vendorBundleId, $packages); 541 | ``` 542 | Returns an array of all added or edited customer packages. 543 | 544 | #### Remove a package from a vendor bundle 545 | 546 | You can reference the package by its ID or name. 547 | 548 | ```php 549 | $vendorBundleId = 42; 550 | $packageName = 'acme-website/package'; 551 | $client->vendorBundles()->packages()->removePackage($vendorBundleId, $packageName); 552 | ``` 553 | 554 | ### Suborganization 555 | 556 | #### List an organization's suborganizations 557 | ```php 558 | $suborganizations = $client->suborganizations()->all(); 559 | ``` 560 | Returns an array of suborganizations. 561 | 562 | #### Show a suborganization 563 | ```php 564 | $suborganizationName = 'suborganization'; 565 | $suborganization = $client->suborganizations()->show($suborganizationName); 566 | ``` 567 | Returns a single suborganization. 568 | 569 | #### Create a suborganization 570 | ```php 571 | $suborganization = $client->suborganizations()->create('New suborganization name'); 572 | ``` 573 | Returns the suborganization. 574 | 575 | #### Delete a suborganization 576 | ```php 577 | $suborganizationName = 'suborganization'; 578 | $client->suborganizations()->remove($suborganizationName); 579 | ``` 580 | 581 | #### List a suborganization's teams 582 | ```php 583 | $suborganizationName = 'suborganization'; 584 | $teams = $client->suborganizations()->listTeams($suborganizationName); 585 | ``` 586 | Returns an array of suborganizations teams. 587 | 588 | #### Add a team to a suborganization or edit the permission 589 | ```php 590 | $suborganizationName = 'suborganization'; 591 | $teams = [ 592 | [ 593 | 'id' => 12, 594 | 'permission' => 'owner', 595 | ], 596 | ]; 597 | $teams = $client->suborganizations()->addOrEditTeams($suborganizationName, $teams); 598 | ``` 599 | Returns an array of added suborganization teams. 600 | 601 | 602 | #### Remove a team from a suborganization 603 | ```php 604 | $suborganizationName = 'suborganization'; 605 | $teamId = 12; 606 | $client->suborganizations()->removeTeam($suborganizationName, $teamId); 607 | ``` 608 | 609 | #### List a suborganization's packages 610 | ```php 611 | $suborganizationName = 'suborganization'; 612 | $packages = $client->suborganizations()->packages()->all($suborganizationName); 613 | ``` 614 | Returns an array of suborganizations packages. 615 | 616 | #### Show a suborganization package 617 | 618 | You can reference a package by its name or ID. 619 | 620 | ```php 621 | $suborganizationName = 'suborganization'; 622 | // Either use package name: 623 | $package = $client->suborganizations()->packages()->show($suborganizationName, 'acme-website/package'); 624 | // Or the package ID: 625 | $package = $client->suborganizations()->packages()->show($suborganizationName, 123); 626 | ``` 627 | Returns the package. 628 | 629 | #### Create a vcs package in a suborganization 630 | ```php 631 | $suborganizationName = 'suborganization'; 632 | $job = $client->suborganizations()->packages()->createVcsPackage($suborganizationName, 'https://github.com/acme-website/package'); 633 | ``` 634 | Returns a new job. 635 | 636 | #### Create a vcs package with credentials in a suborganization 637 | ```php 638 | $suborganizationName = 'suborganization'; 639 | $credentialId = 42; 640 | $job = $client->suborganizations()->packages()->createVcsPackage($suborganizationName,'https://github.com/acme-website/package', $credentialId); 641 | ``` 642 | Returns a new job. 643 | 644 | #### Create a custom package in a suborganization 645 | 646 | ```php 647 | $suborganizationName = 'suborganization'; 648 | $packageDefinition = '{...}'; 649 | $job = $client->suborganizations()->packages()->createCustomPackage($suborganizationName, $packageDefinition); 650 | ``` 651 | Returns a new job. 652 | 653 | #### Create a custom package with credentials in a suborganization 654 | ```php 655 | $suborganizationName = 'suborganization'; 656 | $packageDefinition = '{...}'; 657 | $credentialId = 42; 658 | $job = $client->suborganizations()->packages()->createCustomPackage($suborganizationName, $packageDefinition, $credentialId); 659 | ``` 660 | Returns a new job. 661 | 662 | #### Edit a vcs package in a suborganization in a suborganization 663 | ```php 664 | $suborganizationName = 'suborganization'; 665 | $job = $client->suborganizations()->packages()->editVcsPackage($suborganizationName, 'acme-website/package', 'https://github.com/acme-website/package'); 666 | ``` 667 | Returns a new job. 668 | 669 | #### Edit a custom package in a suborganization 670 | ```php 671 | $suborganizationName = 'suborganization'; 672 | $packageDefinition = '{...}'; 673 | $job = $client->suborganizations()->packages()->editCustomPackage($suborganizationName, 'acme-website/package', $packageDefinition); 674 | ``` 675 | Returns a new job. 676 | 677 | #### Delete a package from a suborganization 678 | ```php 679 | $suborganizationName = 'suborganization'; 680 | $client->suborganizations()->packages()->remove($suborganizationName, 'acme-website/package'); 681 | ``` 682 | 683 | #### List all dependents of a suborganization package 684 | ```php 685 | $suborganizationName = 'suborganization'; 686 | $client->suborganizations()->packages()->listDependents($suborganizationName, 'acme-website/package'); 687 | ``` 688 | Returns a list of packages. 689 | 690 | #### List a suborganization's authentication tokens 691 | ```php 692 | $suborganizationName = 'suborganization'; 693 | $tokens = $client->suborganizations()->listTokens($suborganizationName); 694 | ``` 695 | Returns an array of authentication tokens. 696 | 697 | #### Create a suborganization authentication token 698 | ```php 699 | $suborganizationName = 'suborganization'; 700 | $data = [ 701 | 'description' => 'Suborganization Token', 702 | 'access' => 'read', 703 | ]; 704 | $token = $client->suborganizations()->createToken($suborganizationName, $data); 705 | ``` 706 | Returns the authentication token. 707 | 708 | #### Delete a suborganization authentication token 709 | ```php 710 | $suborganizationName = 'suborganization'; 711 | $tokenId = 33; 712 | $client->suborganizations()->removeToken($suborganizationName, $tokenId); 713 | ``` 714 | 715 | #### Regenerate a suborganization authentication token 716 | ```php 717 | $suborganizationName = 'suborganization'; 718 | $tokenId = 33; 719 | $confirmation = [ 720 | 'IConfirmOldTokenWillStopWorkingImmediately' => true, 721 | ]; 722 | $token = $client->suborganizations()->regenerateToken($suborganizationName, $confirmation); 723 | ``` 724 | Returns the authentication token. 725 | 726 | #### List a suborganization's mirrored repositories 727 | ```php 728 | $suborganizationName = 'suborganization'; 729 | $mirroredRepositories = $client->suborganizations()->mirroredRepositories()->all($suborganizationName); 730 | ``` 731 | Returns an array of mirrored repositories. 732 | 733 | #### Show a mirrored repository 734 | ```php 735 | $suborganizationName = 'suborganization'; 736 | $mirroredRepositoryId = 42; 737 | $mirroredRepository = $client->suborganizations()->mirroredRepositories()->show($suborganizationName, $mirroredRepositoryId); 738 | ``` 739 | Returns the mirrored repository. 740 | 741 | #### Add mirrored repositories to a suborganization 742 | ```php 743 | $suborganizationName = 'suborganization'; 744 | $mirroredRepositoriesToAdd = [ 745 | ['id' => 12, 'mirroringBehavior' => 'add_on_use'], 746 | ]; 747 | $mirroredRepository = $client->suborganizations()->mirroredRepositories()->add($suborganizationName, $mirroredRepositoriesToAdd); 748 | ``` 749 | Returns a list of added mirrored repositories. 750 | 751 | #### Edit the mirroring behaviour of mirrored repository in a suborganization 752 | ```php 753 | $suborganizationName = 'suborganization'; 754 | $mirroredRepositoryId = 42; 755 | $mirroredRepository = $client->suborganizations()->mirroredRepositories()->create($suborganizationName, $mirroredRepositoryId, 'add_on_use'); 756 | ``` 757 | Returns the edited mirrored repository. 758 | 759 | #### Delete a mirrored repository from a suborganization 760 | ```php 761 | $suborganizationName = 'suborganization'; 762 | $mirroredRepositoryId = 42; 763 | $client->suborganizations()->mirroredRepositories()->remove($suborganizationName, $mirroredRepositoryId); 764 | ``` 765 | 766 | #### List all mirrored packages from a mirrored repository in a suborganization 767 | ```php 768 | $suborganizationName = 'suborganization'; 769 | $mirroredRepositoryId = 42; 770 | $packages = $client->suborganizations()->mirroredRepositories()->listPackages($suborganizationName, $mirroredRepositoryId); 771 | ``` 772 | Returns an array of packages. 773 | 774 | #### Add mirrored packages from one mirrored repository to a suborganization 775 | ```php 776 | $suborganizationName = 'suborganization'; 777 | $mirroredRepositoryId = 42; 778 | $packages = [ 779 | 'acme/cool-lib 780 | ]; 781 | $jobs = $client->suborganizations()->mirroredRepositories()->addPackages($suborganizationName, $mirroredRepositoryId, $packages); 782 | ``` 783 | Returns an array of jobs. 784 | 785 | #### Remove all mirrored packages from one mirrored repository in a suborganization 786 | ```php 787 | $suborganizationName = 'suborganization'; 788 | $mirroredRepositoryId = 42; 789 | $client->suborganizations()->mirroredRepositories()->removePackages($suborganizationName, $mirroredRepositoryId); 790 | ``` 791 | 792 | ### Package 793 | 794 | You can reference a package by its name or ID. 795 | 796 | #### List an organization's packages 797 | ```php 798 | $filters = [ 799 | 'origin' => \PrivatePackagist\ApiClient\Api\Packages::ORIGIN_PRIVATE, // optional filter to only receive packages that can be added to customers, 800 | 'security-issue-state' => \PrivatePackagist\ApiClient\Api\SecurityIssues::STATE_OPEN, // optional filter to filter packages with open security issues, 801 | ]; 802 | $packages = $client->packages()->all($filters); 803 | ``` 804 | Returns an array of packages. 805 | 806 | #### Show a package 807 | ```php 808 | // Either use package name: 809 | $package = $client->packages()->show('acme-website/package'); 810 | // Or the package ID: 811 | $package = $client->packages()->show(123); 812 | ``` 813 | Returns the package. 814 | 815 | #### Create a vcs package 816 | ```php 817 | $job = $client->packages()->createVcsPackage('https://github.com/acme-website/package'); 818 | ``` 819 | Returns a new job. 820 | 821 | #### Create a vcs package with credentials 822 | ```php 823 | $credentialId = 42; 824 | $job = $client->packages()->createVcsPackage('https://github.com/acme-website/package', $credentialId); 825 | ``` 826 | Returns a new job. 827 | 828 | #### Create a vcs package with a specific type 829 | ```php 830 | $job = $client->packages()->createVcsPackage('https://github.com/acme-website/package', null, 'git'); 831 | ``` 832 | Returns a new job. 833 | 834 | #### Create a custom package 835 | ```php 836 | $packageDefinition = '{...}'; 837 | $job = $client->packages()->createCustomPackage($packageDefinition); 838 | ``` 839 | Returns a new job. 840 | 841 | #### Create a custom package with credentials 842 | ```php 843 | $packageDefinition = '{...}'; 844 | $credentialId = 42; 845 | $job = $client->packages()->createCustomPackage($packageDefinition, $credentialId); 846 | ``` 847 | Returns a new job. 848 | 849 | #### Edit a vcs package 850 | ```php 851 | $job = $client->packages()->editVcsPackage('acme-website/package', 'https://github.com/acme-website/package'); 852 | ``` 853 | Returns a new job. 854 | 855 | #### Edit a custom package 856 | ```php 857 | $packageDefinition = '{...}'; 858 | $job = $client->packages()->editCustomPackage('acme-website/package', $packageDefinition); 859 | ``` 860 | Returns a new job. 861 | 862 | #### Delete a package 863 | ```php 864 | $client->packages()->remove('acme-website/package'); 865 | ``` 866 | 867 | #### List all dependents of a package 868 | ```php 869 | $client->packages()->listDependents('acme-website/package'); 870 | ``` 871 | Returns a list of packages. 872 | 873 | #### List all customers with access to a package 874 | 875 | Pass either package ID or package name as argument. 876 | 877 | ```php 878 | $client->packages()->listCustomers('acme-website/package'); 879 | ``` 880 | Returns a list of customers with access to the package. 881 | 882 | #### List all security issues of a package 883 | ```php 884 | $filters = [ 885 | 'security-issue-state' => \PrivatePackagist\ApiClient\Api\SecurityIssues::STATE_OPEN, 886 | ]; 887 | $client->packages()->listSecurityIssues('acme-website/package', $filters); 888 | ``` 889 | Returns a list of security issues. 890 | 891 | #### Show the security monitoring config of a package 892 | ```php 893 | $client->packages()->showSecurityMonitoringConfig('acme-website/package'); 894 | ``` 895 | Returns the security monitoring config of the package. 896 | 897 | #### Edit the security monitoring config of a package 898 | ```php 899 | $config = [ 900 | "monitorAllBranches" => false, // If set to true then monitoredBranches will be ignored and can be omitted 901 | "monitoredBranches" => [ 902 | "dev-main" 903 | ], 904 | ]; 905 | $client->packages()->editSecurityMonitoringConfig('acme-website/package', $config); 906 | ``` 907 | Returns the edited security monitoring config of the package. 908 | 909 | #### Create an artifact package file 910 | 911 | ```php 912 | $fileName = 'package1.zip'; // your package archive artifact containing a valid composer.json in root directory 913 | $file = file_get_contents($fileName); 914 | $client->packages()->artifacts()->create($file, 'application/zip', $fileName); 915 | ``` 916 | 917 | #### Create an artifact package 918 | 919 | ```php 920 | $fileName = 'package1.zip'; 921 | $file = file_get_contents($fileName); 922 | $response = $client->packages()->artifacts()->create($file, 'application/zip', $fileName); 923 | $artifactId = $response['id']; 924 | $client->packages()->createArtifactPackage([$artifactId]); 925 | ``` 926 | #### Add an artifact file to an existing package 927 | 928 | ```php 929 | $packageName = 'acme/artifact'; 930 | $fileName = 'package1.zip'; 931 | $file = file_get_contents($fileName); 932 | $client->packages()->artifacts()->add($packageName, $file, 'application/zip', $fileName); 933 | ``` 934 | #### Update or replace artifact files of a package 935 | 936 | ```php 937 | // in case you want to replace the artifact file with a newly uploaded one 938 | // 1. get current artifact ids 939 | $result = $client->packages()->artifacts()->showPackageArtifacts('acme-website/package'); 940 | $artifactIds = array_column($result, 'id'); // [41, 42] 941 | 942 | // 2. upload the new artifact file 943 | $fileName = 'package1.zip'; 944 | $file = file_get_contents($fileName); 945 | $response = $client->packages()->artifacts()->create($file, 'application/zip', $fileName); 946 | $newArtifactId = $response['id']; 947 | 948 | // 3. let's say we don't want to have the artifact file id = 41 and use the newly uploaded file instead 949 | $artifactIds = array_shift($artifactIds); 950 | $artifactIds[] = $newArtifactId; 951 | $client->packages()->editArtifactPackage('acme-website/package', $artifactIds); 952 | ``` 953 | 954 | ### Credential 955 | 956 | #### List an organization's credentials 957 | ```php 958 | $credentials = $client->credentials()->all(); 959 | ``` 960 | Returns an array of credentials. 961 | 962 | #### Show a credential 963 | ```php 964 | $credentialId = 42; 965 | $credential = $client->credentials()->show($credentialId); 966 | ``` 967 | Returns the credential. 968 | 969 | #### Create a credential 970 | ```php 971 | $type = \PrivatePackagist\ApiClient\Api\Credentials::TYPE_HTTP_BASIC; 972 | $credential = $client->credentials()->create('ACME http auth', $type, 'acme-website.com', 'username', 'password'); 973 | ``` 974 | Returns the new credential. 975 | 976 | #### Edit a credential 977 | ```php 978 | $credentialId = 42; 979 | $type = \PrivatePackagist\ApiClient\Api\Credentials::TYPE_HTTP_BASIC; 980 | $credential = $client->credentials()->edit($credentialId, $type, 'username', 'password'); 981 | ``` 982 | Returns the edited credential. 983 | 984 | #### Delete a credential 985 | ```php 986 | $credentialId = 42; 987 | $client->credentials()->remove($credentialId); 988 | ``` 989 | 990 | ### Mirrored Repository 991 | 992 | #### List an organization's mirrored repositories 993 | ```php 994 | $mirroredRepositories = $client->mirroredRepositories()->all(); 995 | ``` 996 | Returns an array of mirrored repositories. 997 | 998 | #### Show a mirrored repository 999 | ```php 1000 | $mirroredRepositoryId = 42; 1001 | $mirroredRepository = $client->mirroredRepositories()->show($mirroredRepositoryId); 1002 | ``` 1003 | Returns the mirrored repository. 1004 | 1005 | #### Create a mirrored repository 1006 | ```php 1007 | $mirroredRepository = $client->mirroredRepositories()->create('Mirrored Repository', 'https://composer.example.com', 'add_on_use', 543); 1008 | ``` 1009 | Returns the new mirrored repository. 1010 | 1011 | #### Edit a mirrored repository 1012 | ```php 1013 | $mirroredRepositoryId = 42; 1014 | $mirroredRepository = $client->mirroredRepositories()->create($mirroredRepositoryId, 'Mirrored Repository', 'https://composer.example.com', 'add_on_use', 543); 1015 | ``` 1016 | Returns the edited mirrored repository. 1017 | 1018 | #### Delete a mirrored repository 1019 | ```php 1020 | $mirroredRepositoryId = 42; 1021 | $client->mirroredRepositories()->remove($mirroredRepositoryId); 1022 | ``` 1023 | 1024 | #### List all mirrored packages from one repository 1025 | ```php 1026 | $mirroredRepositoryId = 42; 1027 | $packages = $client->mirroredRepositories()->listPackages($mirroredRepositoryId); 1028 | ``` 1029 | Returns an array of packages. 1030 | 1031 | #### Add mirrored packages from one repository 1032 | ```php 1033 | $mirroredRepositoryId = 42; 1034 | $packages = [ 1035 | 'acme/cool-lib 1036 | ]; 1037 | $jobs = $client->mirroredRepositories()->addPackages($mirroredRepositoryId, $packages); 1038 | ``` 1039 | Returns an array of jobs. 1040 | 1041 | #### Remove all mirrored packages from one repository 1042 | ```php 1043 | $mirroredRepositoryId = 42; 1044 | $client->mirroredRepositories()->removePackages($mirroredRepositoryId); 1045 | ``` 1046 | 1047 | ### Job 1048 | 1049 | #### Show a job 1050 | ```php 1051 | $job = $client->jobs()->show($jobId); 1052 | ``` 1053 | Returns the job. 1054 | 1055 | #### Wait for a job to finish 1056 | This will periodically poll the job status until the job either finished or the maximum wait time was reached 1057 | ```php 1058 | $numberOfSecondsToWait = 180; 1059 | $jobHelper = new \PrivatePackagist\ApiClient\JobHelper($client); 1060 | try { 1061 | $job = $jobHelper->waitForJob($jobId, $numberOfSecondsToWait); 1062 | } catch (\PrivatePackagist\ApiClient\Exception\JobTimeoutException $e) { 1063 | // Job didn't finish within the specified time 1064 | } catch (\PrivatePackagist\ApiClient\Exception\JobErrorException $e) { 1065 | // Job finished with an error. See the message for more information 1066 | echo $e->getMessage(); 1067 | } 1068 | 1069 | 1070 | 1071 | ``` 1072 | Returns the job. 1073 | 1074 | ### Security Issue 1075 | 1076 | #### List an organization's security issues 1077 | 1078 | ```php 1079 | $filters = [ 1080 | 'security-issue-state' => \PrivatePackagist\ApiClient\Api\SecurityIssues::STATE_OPEN, // optional filter to filter packages with open security issues, 1081 | ]; 1082 | $packages = $client->securityIssues()->all($filters); 1083 | ``` 1084 | Returns an array of security issues. 1085 | 1086 | ### Magento legacy keys 1087 | 1088 | #### List all legacy keys for a customer 1089 | ```php 1090 | $customerId = 42; 1091 | $legacyKeys = $client->customers()->magentoLegacyKeys()->all($customerId); 1092 | ``` 1093 | Returns a list of Magento legacy keys. 1094 | 1095 | #### Create a new legacy keys for a customer 1096 | ```php 1097 | $legacyKey = $client->customers()->magentoLegacyKeys()->create($customerId, $publicKey, $privateKey); 1098 | ``` 1099 | Returns the new Magento legacy key. 1100 | 1101 | #### Delete a legacy keys from a customer 1102 | ```php 1103 | $client->customers()->magentoLegacyKeys()->remove($customerId, $publicKey); 1104 | ``` 1105 | 1106 | ### Validate incoming webhook payloads 1107 | 1108 | When you create or update a webhook in Private Packagist an optional secret can be set. This secret gets used to create a signature which is sent with each request in the headers as `Packagist-Signature`. The secret and signature can then be used on your server to validate that the request was made by Private Packagist. If no secret is set then no signature is sent. 1109 | 1110 | ```php 1111 | $request = /** any Psr7 request */; 1112 | $secret = 'webhook-secret'; 1113 | $webhookSignature = new \PrivatePackagist\ApiClient\WebhookSignature($secret); 1114 | $requestSignature = $request->hasHeader('Packagist-Signature') ? $request->getHeader('Packagist-Signature')[0] : null; 1115 | $webhookSignature->validate($requestSignature, (string) $request->getBody()); 1116 | ``` 1117 | 1118 | ## License 1119 | 1120 | `private-packagist/api-client` is licensed under the MIT License 1121 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "private-packagist/api-client", 3 | "description": "Private Packagist API Client", 4 | "keywords": ["private packagist", "composer", "api"], 5 | "type": "library", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Packagist Conductors GmbH", 10 | "email": "contact@packagist.com" 11 | } 12 | ], 13 | "require": { 14 | "php": "^7.2 || ^8.0", 15 | "ext-json": "*", 16 | "composer-runtime-api": "^2.0", 17 | "php-http/client-common": "^1.9 || ^2.0", 18 | "php-http/discovery": "^1.0", 19 | "psr/http-client-implementation": "^1.0", 20 | "php-http/message-factory": "^1.0", 21 | "psr/http-message-implementation": "^1.0" 22 | }, 23 | "require-dev": { 24 | "friendsofphp/php-cs-fixer": "^3.0", 25 | "guzzlehttp/guzzle": "^7.0", 26 | "php-http/mock-client": "^1.0", 27 | "phpstan/phpstan": "^1.2", 28 | "phpunit/phpunit": "^8.0 || ^9.0" 29 | }, 30 | "autoload": { 31 | "psr-4": { "PrivatePackagist\\ApiClient\\": "src/" } 32 | }, 33 | "autoload-dev": { 34 | "psr-4": { "PrivatePackagist\\ApiClient\\": "tests/"} 35 | }, 36 | "scripts": { 37 | "toc": "./gh-md-toc --insert README.md" 38 | }, 39 | "config": { 40 | "allow-plugins": { 41 | "php-http/discovery": true 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Api/AbstractApi.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api; 11 | 12 | use PrivatePackagist\ApiClient\Client; 13 | use PrivatePackagist\ApiClient\HttpClient\Message\ResponseMediator; 14 | 15 | abstract class AbstractApi 16 | { 17 | /** @var Client */ 18 | protected $client; 19 | /** @var ResponseMediator */ 20 | private $responseMediator; 21 | 22 | public function __construct(Client $client, ?ResponseMediator $responseMediator = null) 23 | { 24 | $this->client = $client; 25 | $this->responseMediator = $responseMediator ?: new ResponseMediator(); 26 | } 27 | 28 | /** 29 | * @param string $path 30 | * @param array $parameters 31 | * @param array $headers 32 | * @return array|string 33 | */ 34 | protected function get($path, array $parameters = [], array $headers = []) 35 | { 36 | if (count($parameters) > 0) { 37 | $path .= '?'.http_build_query($parameters); 38 | } 39 | $response = $this->client->getHttpClient()->get( 40 | $path, 41 | array_merge($headers, [ 42 | 'Accept' => 'application/json', 43 | 'Content-Type' => 'application/json', 44 | ]) 45 | ); 46 | 47 | return $this->responseMediator->getContent($response); 48 | } 49 | 50 | /** 51 | * @param string $path 52 | * @param array $parameters 53 | * @param array $headers 54 | * @return array|string 55 | */ 56 | protected function post($path, array $parameters = [], array $headers = []) 57 | { 58 | $response = $this->client->getHttpClient()->post( 59 | $path, 60 | array_merge($headers, [ 61 | 'Accept' => 'application/json', 62 | 'Content-Type' => 'application/json', 63 | ]), 64 | $this->createJsonBody($parameters) 65 | ); 66 | 67 | return $this->responseMediator->getContent($response); 68 | } 69 | 70 | protected function postFile($path, $rawFileContent, array $headers = []) 71 | { 72 | $response = $this->client->getHttpClient()->post( 73 | $path, 74 | array_merge($headers, [ 75 | 'Accept' => 'application/json', 76 | ]), 77 | $rawFileContent 78 | ); 79 | 80 | return $this->responseMediator->getContent($response); 81 | } 82 | 83 | /** 84 | * @param string $path 85 | * @param array $parameters 86 | * @param array $headers 87 | * @return array|string 88 | */ 89 | protected function put($path, array $parameters = [], array $headers = []) 90 | { 91 | $response = $this->client->getHttpClient()->put( 92 | $path, 93 | array_merge($headers, [ 94 | 'Accept' => 'application/json', 95 | 'Content-Type' => 'application/json', 96 | ]), 97 | $this->createJsonBody($parameters) 98 | ); 99 | 100 | return $this->responseMediator->getContent($response); 101 | } 102 | 103 | /** 104 | * @param string $path 105 | * @param array $parameters 106 | * @param array $headers 107 | * @return array|string 108 | */ 109 | protected function delete($path, array $parameters = [], array $headers = []) 110 | { 111 | $response = $this->client->getHttpClient()->delete( 112 | $path, 113 | array_merge($headers, [ 114 | 'Accept' => 'application/json', 115 | 'Content-Type' => 'application/json', 116 | ]), 117 | $this->createJsonBody($parameters) 118 | ); 119 | 120 | return $this->responseMediator->getContent($response); 121 | } 122 | /** 123 | * @param array $parameters 124 | * @return null|string 125 | */ 126 | protected function createJsonBody(array $parameters) 127 | { 128 | return (count($parameters) === 0) ? null : json_encode($parameters); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/Api/Credentials.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api; 11 | 12 | class Credentials extends AbstractApi 13 | { 14 | const TYPE_BITBUCKET_APP_PW = 'bitbucket-app-pw'; 15 | const TYPE_GITHUB_OAUTH = 'github-oauth'; 16 | const TYPE_GITLAB_TOKEN = 'gitlab-token'; 17 | const TYPE_HTTP_BASIC = 'http-basic'; 18 | const TYPE_MAGENTO = 'magento'; 19 | const TYPE_HTTP_HEADER = 'http-header'; 20 | const TYPE_SSH_KEY = 'ssh-key'; 21 | 22 | public function all() 23 | { 24 | return $this->get('/credentials/'); 25 | } 26 | 27 | public function show($credentialId) 28 | { 29 | return $this->get(sprintf('/credentials/%s/', $credentialId)); 30 | } 31 | 32 | public function create($description, $type, $domain, $username, $credential) 33 | { 34 | return $this->post('/credentials/', [ 35 | 'description' => $description, 36 | 'type' => $type, 37 | 'domain' => $domain, 38 | 'username' => $username, 39 | 'credential' => $credential, 40 | ]); 41 | } 42 | 43 | /** 44 | * @deprecated Use edit instead 45 | */ 46 | #[\Deprecated('Use Credentials::edit instead', '1.11.0')] 47 | public function update($credentialId, $type, $username, $credential) 48 | { 49 | return $this->edit($credentialId, $type, $username, $credential); 50 | } 51 | 52 | public function edit($credentialId, $type, $username, $credential) 53 | { 54 | return $this->put(sprintf('/credentials/%s/', $credentialId), [ 55 | 'username' => $username, 56 | 'credential' => $credential, 57 | 'type' => $type, 58 | ]); 59 | } 60 | 61 | public function remove($credentialId) 62 | { 63 | return $this->delete(sprintf('/credentials/%s/', $credentialId)); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Api/Customers.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api; 11 | 12 | use PrivatePackagist\ApiClient\Api\Customers\MagentoLegacyKeys; 13 | use PrivatePackagist\ApiClient\Exception\InvalidArgumentException; 14 | 15 | class Customers extends AbstractApi 16 | { 17 | public function all() 18 | { 19 | return $this->get('/customers/'); 20 | } 21 | 22 | public function show($customerIdOrUrlName) 23 | { 24 | return $this->get(sprintf('/customers/%s/', $customerIdOrUrlName)); 25 | } 26 | 27 | public function create($name, $accessToVersionControlSource = false, $urlName = null, $minimumAccessibleStability = null, $assignAllPackages = false) 28 | { 29 | $parameters = [ 30 | 'name' => $name, 31 | 'accessToVersionControlSource' => $accessToVersionControlSource, 32 | 'minimumAccessibleStability' => $minimumAccessibleStability, 33 | 'assignAllPackages' => $assignAllPackages, 34 | ]; 35 | if ($urlName) { 36 | $parameters['urlName'] = $urlName; 37 | } 38 | 39 | return $this->post('/customers/', $parameters); 40 | } 41 | 42 | /** 43 | * @deprecated Use edit instead 44 | */ 45 | #[\Deprecated('Use Customers::edit instead', '1.11.0')] 46 | public function update($customerIdOrUrlName, array $customer) 47 | { 48 | return $this->edit($customerIdOrUrlName, $customer); 49 | } 50 | 51 | public function edit($customerIdOrUrlName, array $customer) 52 | { 53 | return $this->put(sprintf('/customers/%s/', $customerIdOrUrlName), $customer); 54 | } 55 | 56 | public function remove($customerIdOrUrlName) 57 | { 58 | return $this->delete(sprintf('/customers/%s/', $customerIdOrUrlName)); 59 | } 60 | 61 | public function enable($customerIdOrUrlName) 62 | { 63 | return $this->put(sprintf('/customers/%s/enable', $customerIdOrUrlName)); 64 | } 65 | 66 | public function disable($customerIdOrUrlName) 67 | { 68 | return $this->put(sprintf('/customers/%s/disable', $customerIdOrUrlName)); 69 | } 70 | 71 | public function listPackages($customerIdOrUrlName) 72 | { 73 | return $this->get(sprintf('/customers/%s/packages/', $customerIdOrUrlName)); 74 | } 75 | 76 | public function showPackage($customerIdOrUrlName, $packageIdOrName) 77 | { 78 | return $this->get(sprintf('/customers/%s/packages/%s/', $customerIdOrUrlName, $packageIdOrName)); 79 | } 80 | 81 | /** 82 | * @deprecated Use addOrEditPackages instead 83 | */ 84 | #[\Deprecated('Use Customers::addOrEditPackages instead', '1.11.0')] 85 | public function addOrUpdatePackages($customerIdOrUrlName, array $packages) 86 | { 87 | return $this->addOrEditPackages($customerIdOrUrlName, $packages); 88 | } 89 | 90 | public function addOrEditPackages($customerIdOrUrlName, array $packages) 91 | { 92 | foreach ($packages as $package) { 93 | if (!isset($package['name'])) { 94 | throw new InvalidArgumentException('Parameter "name" is required.'); 95 | } 96 | } 97 | 98 | return $this->post(sprintf('/customers/%s/packages/', $customerIdOrUrlName), $packages); 99 | } 100 | 101 | /** 102 | * @deprecated Use addOrEditPackages instead 103 | */ 104 | #[\Deprecated('Use Customers::addOrEditPackages instead', '1.11.0')] 105 | public function addPackages($customerIdOrUrlName, array $packages) 106 | { 107 | return $this->addOrEditPackages($customerIdOrUrlName, $packages); 108 | } 109 | 110 | public function removePackage($customerIdOrUrlName, $packageIdOrName) 111 | { 112 | return $this->delete(sprintf('/customers/%s/packages/%s/', $customerIdOrUrlName, $packageIdOrName)); 113 | } 114 | 115 | public function regenerateToken($customerIdOrUrlName, array $confirmation) 116 | { 117 | if (!isset($confirmation['IConfirmOldTokenWillStopWorkingImmediately'])) { 118 | throw new InvalidArgumentException('Confirmation is required to regenerate the Composer repository token.'); 119 | } 120 | 121 | return $this->post(sprintf('/customers/%s/token/regenerate', $customerIdOrUrlName), $confirmation); 122 | } 123 | 124 | public function magentoLegacyKeys() 125 | { 126 | return new MagentoLegacyKeys($this->client); 127 | } 128 | 129 | public function vendorBundles() 130 | { 131 | return new \PrivatePackagist\ApiClient\Api\Customers\VendorBundles($this->client); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/Api/Customers/MagentoLegacyKeys.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api\Customers; 11 | 12 | use PrivatePackagist\ApiClient\Api\AbstractApi; 13 | 14 | class MagentoLegacyKeys extends AbstractApi 15 | { 16 | public function all($customerIdOrUrlName) 17 | { 18 | return $this->get(sprintf('/api/customers/%s/magento-legacy-keys/', $customerIdOrUrlName)); 19 | } 20 | 21 | public function create($customerIdOrUrlName, $publicKey, $privateKey) 22 | { 23 | return $this->post(sprintf('/api/customers/%s/magento-legacy-keys/', $customerIdOrUrlName), [ 24 | 'publicKey' => $publicKey, 25 | 'privateKey' => $privateKey, 26 | ]); 27 | } 28 | 29 | public function remove($customerIdOrUrlName, $publicKey) 30 | { 31 | return $this->delete(sprintf('/api/customers/%s/magento-legacy-keys/%s/', $customerIdOrUrlName, $publicKey)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Api/Customers/VendorBundles.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api\Customers; 11 | 12 | use PrivatePackagist\ApiClient\Api\AbstractApi; 13 | 14 | class VendorBundles extends AbstractApi 15 | { 16 | public function listVendorBundles($customerIdOrUrlName) 17 | { 18 | return $this->get(sprintf('/customers/%s/vendor-bundles/', $customerIdOrUrlName)); 19 | } 20 | 21 | /** 22 | * @param int|string $customerIdOrUrlName 23 | * @param int $vendorBundleId 24 | * @param null|string $expirationDate 25 | */ 26 | public function addOrEditVendorBundle($customerIdOrUrlName, $vendorBundleId, $expirationDate = null) 27 | { 28 | return $this->post(sprintf('/customers/%s/vendor-bundles/', $customerIdOrUrlName), [ 29 | 'vendorBundleId' => $vendorBundleId, 30 | 'expirationDate' => $expirationDate, 31 | ]); 32 | } 33 | 34 | /** 35 | * @param int|string $customerIdOrUrlName 36 | * @param int $vendorBundleId 37 | */ 38 | public function removeVendorBundle($customerIdOrUrlName, $vendorBundleId) 39 | { 40 | return $this->delete(sprintf('/customers/%s/vendor-bundles/%s/', $customerIdOrUrlName, $vendorBundleId)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Api/Jobs.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api; 11 | 12 | class Jobs extends AbstractApi 13 | { 14 | public function show($jobId) 15 | { 16 | return $this->get(sprintf('/jobs/%s', $jobId)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Api/MirroredRepositories.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api; 11 | 12 | class MirroredRepositories extends AbstractApi 13 | { 14 | public function all() 15 | { 16 | return $this->get('/mirrored-repositories/'); 17 | } 18 | 19 | public function create($name, $url, $mirroringBehavior, $credentials = null) 20 | { 21 | return $this->post('/mirrored-repositories/', [ 22 | 'name' => $name, 23 | 'url' => $url, 24 | 'mirroringBehavior' => $mirroringBehavior, 25 | 'credentials' => $credentials, 26 | ]); 27 | } 28 | 29 | public function show($mirroredRepositoryId) 30 | { 31 | return $this->get(sprintf('/mirrored-repositories/%s/', $mirroredRepositoryId)); 32 | } 33 | 34 | public function edit($mirroredRepositoryId, $name, $url, $mirroringBehavior, $credentials = null) 35 | { 36 | return $this->put(sprintf('/mirrored-repositories/%s/', $mirroredRepositoryId), [ 37 | 'name' => $name, 38 | 'url' => $url, 39 | 'mirroringBehavior' => $mirroringBehavior, 40 | 'credentials' => $credentials, 41 | ]); 42 | } 43 | 44 | public function remove($mirroredRepositoryId) 45 | { 46 | return $this->delete(sprintf('/mirrored-repositories/%s/', $mirroredRepositoryId)); 47 | } 48 | 49 | public function listPackages($mirroredRepositoryId) 50 | { 51 | return $this->get(sprintf('/mirrored-repositories/%s/packages/', $mirroredRepositoryId)); 52 | } 53 | 54 | public function addPackages($mirroredRepositoryId, array $packages) 55 | { 56 | return $this->post(sprintf('/mirrored-repositories/%s/packages/', $mirroredRepositoryId), $packages); 57 | } 58 | 59 | public function removePackages($mirroredRepositoryId) 60 | { 61 | return $this->delete(sprintf('/mirrored-repositories/%s/packages/', $mirroredRepositoryId)); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Api/Organization.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api; 11 | 12 | class Organization extends AbstractApi 13 | { 14 | public function sync() 15 | { 16 | return $this->post('/organization/sync'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Api/Packages.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api; 11 | 12 | use PrivatePackagist\ApiClient\Api\Packages\Artifacts; 13 | use PrivatePackagist\ApiClient\Exception\InvalidArgumentException; 14 | use PrivatePackagist\ApiClient\Payload\ArtifactPackageConfig; 15 | use PrivatePackagist\ApiClient\Payload\CustomPackageConfig; 16 | use PrivatePackagist\ApiClient\Payload\VcsPackageConfig; 17 | 18 | class Packages extends AbstractApi 19 | { 20 | /** 21 | * Packages that are mirrored from a public mirrored third party repository like packagist.org. 22 | */ 23 | const ORIGIN_PUBLIC_MIRROR = 'public-mirror'; 24 | 25 | /** 26 | * Packages that are mirrored from a private mirrored third party repository requiring authentication like repo.magento.com. 27 | */ 28 | const ORIGIN_PRIVATE_MIRROR = 'private-mirror'; 29 | 30 | /** 31 | * All other packages from a VCS repository or a custom JSON definition. 32 | */ 33 | const ORIGIN_PRIVATE = 'private'; 34 | 35 | /** 36 | * @deprecated Use Packages::ORIGIN_PUBLIC_MIRROR instead 37 | */ 38 | #[\Deprecated('Use Packages::ORIGIN_PUBLIC_MIRROR instead', '1.13.0')] 39 | const ORIGIN_PUBLIC_PROXY = self::ORIGIN_PUBLIC_MIRROR; 40 | 41 | /** 42 | * @deprecated Use Packages::ORIGIN_PRIVATE_MIRROR instead 43 | */ 44 | #[\Deprecated('Use Packages::ORIGIN_PRIVATE_MIRROR instead', '1.13.0')] 45 | const ORIGIN_PRIVATE_PROXY = self::ORIGIN_PRIVATE_MIRROR; 46 | 47 | const AVAILABLE_ORIGINS = [self::ORIGIN_PUBLIC_MIRROR, self::ORIGIN_PRIVATE_MIRROR, self::ORIGIN_PRIVATE, 'public-proxy', 'private-proxy']; 48 | 49 | public function all(array $filters = []) 50 | { 51 | if (isset($filters['origin']) && !in_array($filters['origin'], self::AVAILABLE_ORIGINS, true)) { 52 | throw new InvalidArgumentException('Filter "origin" has to be one of: "' . implode('", "', self::AVAILABLE_ORIGINS) . '".'); 53 | } 54 | 55 | return $this->get('/packages/', $filters); 56 | } 57 | 58 | public function show($packageIdOrName) 59 | { 60 | return $this->get(sprintf('/packages/%s/', $packageIdOrName)); 61 | } 62 | 63 | public function createVcsPackage($url, $credentialId = null, $type = 'vcs', $defaultSubrepositoryAccess = null) 64 | { 65 | $data = new VcsPackageConfig($url, $credentialId, $type, $defaultSubrepositoryAccess); 66 | 67 | return $this->post('/packages/', $data->toParameters()); 68 | } 69 | 70 | public function createCustomPackage($customJson, $credentialId = null, $defaultSubrepositoryAccess = null) 71 | { 72 | $data = new CustomPackageConfig($customJson, $credentialId, $defaultSubrepositoryAccess); 73 | 74 | return $this->post('/packages/', $data->toParameters()); 75 | } 76 | 77 | public function createArtifactPackage(array $artifactPackageFileIds, $defaultSubrepositoryAccess = null) 78 | { 79 | $data = new ArtifactPackageConfig($artifactPackageFileIds, $defaultSubrepositoryAccess); 80 | 81 | return $this->post('/packages/', $data->toParameters()); 82 | } 83 | 84 | /** 85 | * @deprecated Use editVcsPackage instead 86 | */ 87 | #[\Deprecated('Use Packages::editVcsPackage instead', '1.11.0')] 88 | public function updateVcsPackage($packageName, $url, $credentialId = null) 89 | { 90 | return $this->editVcsPackage($packageName, $url, $credentialId); 91 | } 92 | 93 | public function editVcsPackage($packageIdOrName, $url, $credentialId = null, $type = 'vcs', $defaultSubrepositoryAccess = null) 94 | { 95 | $data = new VcsPackageConfig($url, $credentialId, $type, $defaultSubrepositoryAccess); 96 | 97 | return $this->put(sprintf('/packages/%s/', $packageIdOrName), $data->toParameters()); 98 | } 99 | 100 | public function editArtifactPackage($packageIdOrName, array $artifactPackageFileIds, $defaultSubrepositoryAccess = null) 101 | { 102 | $data = new ArtifactPackageConfig($artifactPackageFileIds, $defaultSubrepositoryAccess); 103 | 104 | return $this->put(sprintf('/packages/%s/', $packageIdOrName), $data->toParameters()); 105 | } 106 | 107 | /** 108 | * @deprecated Use editCustomPackage instead 109 | */ 110 | #[\Deprecated('Use Packages::editCustomPackage instead', '1.11.0')] 111 | public function updateCustomPackage($packageName, $customJson, $credentialId = null) 112 | { 113 | return $this->editCustomPackage($packageName, $customJson, $credentialId); 114 | } 115 | 116 | public function editCustomPackage($packageIdOrName, $customJson, $credentialId = null, $defaultSubrepositoryAccess = null) 117 | { 118 | $data = new CustomPackageConfig($customJson, $credentialId, $defaultSubrepositoryAccess); 119 | 120 | return $this->put(sprintf('/packages/%s/', $packageIdOrName), $data->toParameters()); 121 | } 122 | 123 | public function remove($packageIdOrName) 124 | { 125 | return $this->delete(sprintf('/packages/%s/', $packageIdOrName)); 126 | } 127 | 128 | public function listCustomers($packageIdOrName) 129 | { 130 | return $this->get(sprintf('/packages/%s/customers/', $packageIdOrName)); 131 | } 132 | 133 | public function listDependents($packageName) 134 | { 135 | return $this->get(sprintf('/packages/%s/dependents/', $packageName)); 136 | } 137 | 138 | public function listSecurityIssues($packageIdOrName, array $filters = []) 139 | { 140 | return $this->get(sprintf('/packages/%s/security-issues/', $packageIdOrName), $filters); 141 | } 142 | 143 | public function showSecurityMonitoringConfig($packageIdOrName) 144 | { 145 | return $this->get(sprintf('/packages/%s/security-monitoring/', $packageIdOrName)); 146 | } 147 | 148 | public function editSecurityMonitoringConfig($packageIdOrName, array $config) 149 | { 150 | return $this->put(sprintf('/packages/%s/security-monitoring/', $packageIdOrName), $config); 151 | } 152 | 153 | public function artifacts() 154 | { 155 | return new Artifacts($this->client, $this->client->getResponseMediator()); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/Api/Packages/Artifacts.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api\Packages; 11 | 12 | use PrivatePackagist\ApiClient\Api\AbstractApi; 13 | 14 | class Artifacts extends AbstractApi 15 | { 16 | public function create($file, $contentType, $fileName) 17 | { 18 | return $this->postFile('/packages/artifacts/', $file, array_filter([ 19 | 'Content-Type' => $contentType, 20 | 'X-FILENAME' => $fileName 21 | ])); 22 | } 23 | 24 | public function add($packageIdOrName, $file, $contentType, $fileName) 25 | { 26 | return $this->postFile('/packages/'.$packageIdOrName.'/artifacts/', $file, array_filter([ 27 | 'Content-Type' => $contentType, 28 | 'X-FILENAME' => $fileName 29 | ])); 30 | } 31 | 32 | public function show($artifactId) 33 | { 34 | return $this->get(sprintf('/packages/artifacts/%s/', $artifactId)); 35 | } 36 | 37 | public function showPackageArtifacts($packageIdOrName) 38 | { 39 | return $this->get(sprintf('/packages/%s/artifacts/', $packageIdOrName)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Api/Projects.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api; 11 | 12 | /** 13 | * @deprecated Use the Suborganizations API instead 14 | */ 15 | class Projects extends Subrepositories 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /src/Api/Projects/MirroredRepositories.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api\Projects; 11 | 12 | /** 13 | * @deprecated Use \PrivatePackagist\ApiClient\Api\Suborganizations\MirroredRepositories instead 14 | */ 15 | class MirroredRepositories extends \PrivatePackagist\ApiClient\Api\Subrepositories\MirroredRepositories 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /src/Api/Projects/Packages.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api\Projects; 11 | 12 | /** 13 | * @deprecated Use \PrivatePackagist\ApiClient\Api\Suborganizations\Packages instead 14 | */ 15 | class Packages extends \PrivatePackagist\ApiClient\Api\Subrepositories\Packages 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /src/Api/SecurityIssues.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api; 11 | 12 | class SecurityIssues extends AbstractApi 13 | { 14 | /** 15 | * Security issue that is still open 16 | */ 17 | const STATE_OPEN = 'open'; 18 | 19 | /** 20 | * Security issue where a fix is in progress 21 | */ 22 | const STATE_IN_PROGRESS = 'in-progress'; 23 | 24 | /** 25 | * Security issue that doesn't affect the project 26 | */ 27 | const STATE_NOT_AFFECTED = 'not-affected'; 28 | 29 | /** 30 | * Security issue that is incorrect 31 | */ 32 | const STATE_INCORRECT = 'incorrect'; 33 | 34 | /** 35 | * Security issue where there is no capacity to fix the issue 36 | */ 37 | const STATE_NO_CAPACITY = 'no-capacity'; 38 | 39 | /** 40 | * Security issue that can be ignored 41 | */ 42 | const STATE_IGNORE = 'ignore'; 43 | 44 | /** 45 | * Security issue that has been resolved 46 | */ 47 | const STATE_RESOLVED = 'resolved'; 48 | 49 | public function all(array $filters = []) 50 | { 51 | return $this->get('/security-issues/', $filters); 52 | } 53 | 54 | public function show(int $issueId): array 55 | { 56 | return $this->get('/security-issues/' . $issueId); 57 | } 58 | 59 | public function open(int $issueId): array 60 | { 61 | return $this->post('/security-issues/' . $issueId . '/open'); 62 | } 63 | 64 | public function close(int $issueId, string $state): array 65 | { 66 | return $this->post('/security-issues/' . $issueId . '/close/' . $state); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Api/Suborganizations.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api; 11 | 12 | use PrivatePackagist\ApiClient\Exception\InvalidArgumentException; 13 | 14 | class Suborganizations extends AbstractApi 15 | { 16 | public function all() 17 | { 18 | return $this->get('/suborganizations/'); 19 | } 20 | 21 | public function show($suborganizationName) 22 | { 23 | return $this->get(sprintf('/suborganizations/%s/', $suborganizationName)); 24 | } 25 | 26 | public function create($name) 27 | { 28 | return $this->post('/suborganizations/', ['name' => $name]); 29 | } 30 | 31 | public function remove($suborganizationName) 32 | { 33 | return $this->delete(sprintf('/suborganizations/%s/', $suborganizationName)); 34 | } 35 | 36 | public function listTeams($suborganizationName) 37 | { 38 | return $this->get(sprintf('/suborganizations/%s/teams/', $suborganizationName)); 39 | } 40 | 41 | public function addOrEditTeams($suborganizationName, array $teams) 42 | { 43 | foreach ($teams as $team) { 44 | if (!isset($team['id'])) { 45 | throw new InvalidArgumentException('Parameter "id" is required.'); 46 | } 47 | 48 | if (!isset($team['permission'])) { 49 | throw new InvalidArgumentException('Parameter "permission" is required.'); 50 | } 51 | } 52 | 53 | return $this->post(sprintf('/suborganizations/%s/teams/', $suborganizationName), $teams); 54 | } 55 | 56 | public function removeTeam($suborganizationName, $teamId) 57 | { 58 | return $this->delete(sprintf('/suborganizations/%s/teams/%s/', $suborganizationName, $teamId)); 59 | } 60 | 61 | public function listTokens($suborganizationName) 62 | { 63 | return $this->get(sprintf('/suborganizations/%s/tokens/', $suborganizationName)); 64 | } 65 | 66 | public function createToken($suborganizationName, array $tokenData) 67 | { 68 | return $this->post(sprintf('/suborganizations/%s/tokens/', $suborganizationName), $tokenData); 69 | } 70 | 71 | public function removeToken($suborganizationName, $tokenId) 72 | { 73 | return $this->delete(sprintf('/suborganizations/%s/tokens/%s/', $suborganizationName, $tokenId)); 74 | } 75 | 76 | public function regenerateToken($suborganizationName, $tokenId, array $confirmation) 77 | { 78 | if (!isset($confirmation['IConfirmOldTokenWillStopWorkingImmediately'])) { 79 | throw new InvalidArgumentException('Confirmation is required to regenerate the Composer repository token.'); 80 | } 81 | 82 | return $this->post(sprintf('/suborganizations/%s/tokens/%s/regenerate', $suborganizationName, $tokenId), $confirmation); 83 | } 84 | 85 | public function packages() 86 | { 87 | return new Suborganizations\Packages($this->client); 88 | } 89 | 90 | public function mirroredRepositories() 91 | { 92 | return new Suborganizations\MirroredRepositories($this->client); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/Api/Suborganizations/MirroredRepositories.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api\Suborganizations; 11 | 12 | use PrivatePackagist\ApiClient\Api\AbstractApi; 13 | use PrivatePackagist\ApiClient\Exception\InvalidArgumentException; 14 | 15 | class MirroredRepositories extends AbstractApi 16 | { 17 | public function all($suborganizationName) 18 | { 19 | return $this->get(sprintf('/suborganizations/%s/mirrored-repositories/', $suborganizationName)); 20 | } 21 | 22 | public function add($suborganizationName, array $mirroredRepositories) 23 | { 24 | foreach ($mirroredRepositories as $mirroredRepository) { 25 | if (!isset($mirroredRepository['id'], $mirroredRepository['mirroringBehavior'])) { 26 | throw new InvalidArgumentException('The "id" and the "mirroringBehavior" are required to add a mirrored repository to a project'); 27 | } 28 | } 29 | 30 | return $this->post(sprintf('/suborganizations/%s/mirrored-repositories/', $suborganizationName), $mirroredRepositories); 31 | } 32 | 33 | public function show($suborganizationName, $mirroredRepositoryId) 34 | { 35 | return $this->get(sprintf('/suborganizations/%s/mirrored-repositories/%s/', $suborganizationName, $mirroredRepositoryId)); 36 | } 37 | 38 | public function edit($suborganizationName, $mirroredRepositoryId, $mirroringBehavior) 39 | { 40 | return $this->put(sprintf('/suborganizations/%s/mirrored-repositories/%s/', $suborganizationName, $mirroredRepositoryId), [ 41 | 'mirroringBehavior' => $mirroringBehavior, 42 | ]); 43 | } 44 | 45 | public function remove($suborganizationName, $mirroredRepositoryId) 46 | { 47 | return $this->delete(sprintf('/suborganizations/%s/mirrored-repositories/%s/', $suborganizationName, $mirroredRepositoryId)); 48 | } 49 | 50 | public function listPackages($suborganizationName, $mirroredRepositoryId) 51 | { 52 | return $this->get(sprintf('/suborganizations/%s/mirrored-repositories/%s/packages/', $suborganizationName, $mirroredRepositoryId)); 53 | } 54 | 55 | public function addPackages($suborganizationName, $mirroredRepositoryId, array $packages) 56 | { 57 | return $this->post(sprintf('/suborganizations/%s/mirrored-repositories/%s/packages/', $suborganizationName, $mirroredRepositoryId), $packages); 58 | } 59 | 60 | public function removePackages($suborganizationName, $mirroredRepositoryId) 61 | { 62 | return $this->delete(sprintf('/suborganizations/%s/mirrored-repositories/%s/packages/', $suborganizationName, $mirroredRepositoryId)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Api/Suborganizations/Packages.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api\Suborganizations; 11 | 12 | use PrivatePackagist\ApiClient\Api\AbstractApi; 13 | use PrivatePackagist\ApiClient\Exception\InvalidArgumentException; 14 | use PrivatePackagist\ApiClient\Payload\CustomPackageConfig; 15 | use PrivatePackagist\ApiClient\Payload\VcsPackageConfig; 16 | 17 | class Packages extends AbstractApi 18 | { 19 | public function all($suborganizationName, array $filters = []) 20 | { 21 | if (isset($filters['origin']) && !in_array($filters['origin'], \PrivatePackagist\ApiClient\Api\Packages::AVAILABLE_ORIGINS, true)) { 22 | throw new InvalidArgumentException('Filter "origin" has to be one of: "' . implode('", "', \PrivatePackagist\ApiClient\Api\Packages::AVAILABLE_ORIGINS) . '".'); 23 | } 24 | 25 | return $this->get(sprintf('/suborganizations/%s/packages/', $suborganizationName), $filters); 26 | } 27 | 28 | public function show($suborganizationName, $packageIdOrName) 29 | { 30 | return $this->get(sprintf('/suborganizations/%s/packages/%s', $suborganizationName, $packageIdOrName)); 31 | } 32 | 33 | public function createVcsPackage($suborganizationName, $url, $credentialId = null, $type = 'vcs', $defaultSuborganizationAccess = null) 34 | { 35 | $data = new VcsPackageConfig($url, $credentialId, $type, $defaultSuborganizationAccess); 36 | 37 | return $this->post(sprintf('/suborganizations/%s/packages/', $suborganizationName), $data->toParameters()); 38 | } 39 | 40 | public function createCustomPackage($suborganizationName, $customJson, $credentialId = null, $defaultSuborganizationAccess = null) 41 | { 42 | $data = new CustomPackageConfig($customJson, $credentialId, $defaultSuborganizationAccess); 43 | 44 | return $this->post(sprintf('/suborganizations/%s/packages/', $suborganizationName), $data->toParameters()); 45 | } 46 | 47 | public function editVcsPackage($suborganizationName, $packageIdOrName, $url, $credentialId = null, $type = 'vcs', $defaultSuborganizationAccess = null) 48 | { 49 | $data = new VcsPackageConfig($url, $credentialId, $type, $defaultSuborganizationAccess); 50 | 51 | return $this->put(sprintf('/suborganizations/%s/packages/%s/', $suborganizationName, $packageIdOrName), $data->toParameters()); 52 | } 53 | 54 | public function editCustomPackage($suborganizationName, $packageIdOrName, $customJson, $credentialId = null, $defaultSuborganizationAccess = null) 55 | { 56 | $data = new CustomPackageConfig($customJson, $credentialId, $defaultSuborganizationAccess); 57 | 58 | return $this->put(sprintf('/suborganizations/%s/packages/%s/', $suborganizationName, $packageIdOrName), $data->toParameters()); 59 | } 60 | 61 | public function remove($suborganizationName, $packageIdOrName) 62 | { 63 | return $this->delete(sprintf('/suborganizations/%s/packages/%s/', $suborganizationName, $packageIdOrName)); 64 | } 65 | 66 | public function listDependents($suborganizationName, $packageIdOrName) 67 | { 68 | return $this->get(sprintf('/suborganizations/%s/packages/%s/dependents/', $suborganizationName, $packageIdOrName)); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Api/Subrepositories.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api; 11 | 12 | use PrivatePackagist\ApiClient\Exception\InvalidArgumentException; 13 | 14 | /** 15 | * @deprecated Use the Suborganizations API instead 16 | */ 17 | class Subrepositories extends AbstractApi 18 | { 19 | public function all() 20 | { 21 | return $this->get('/subrepositories/'); 22 | } 23 | 24 | public function show($subrepositoryName) 25 | { 26 | return $this->get(sprintf('/subrepositories/%s/', $subrepositoryName)); 27 | } 28 | 29 | public function create($name) 30 | { 31 | return $this->post('/subrepositories/', ['name' => $name]); 32 | } 33 | 34 | public function remove($subrepositoryName) 35 | { 36 | return $this->delete(sprintf('/subrepositories/%s/', $subrepositoryName)); 37 | } 38 | 39 | public function listTeams($subrepositoryName) 40 | { 41 | return $this->get(sprintf('/subrepositories/%s/teams/', $subrepositoryName)); 42 | } 43 | 44 | /** 45 | * @deprecated Use addOrEditTeams instead 46 | */ 47 | #[\Deprecated('Use Subrepositories::addOrEditTeams instead', '1.10.0')] 48 | public function addOrUpdateTeams($subrepositoryName, array $teams) 49 | { 50 | return $this->addOrEditTeams($subrepositoryName, $teams); 51 | } 52 | 53 | public function addOrEditTeams($subrepositoryName, array $teams) 54 | { 55 | foreach ($teams as $team) { 56 | if (!isset($team['id'])) { 57 | throw new InvalidArgumentException('Parameter "id" is required.'); 58 | } 59 | 60 | if (!isset($team['permission'])) { 61 | throw new InvalidArgumentException('Parameter "permission" is required.'); 62 | } 63 | } 64 | 65 | return $this->post(sprintf('/subrepositories/%s/teams/', $subrepositoryName), $teams); 66 | } 67 | 68 | public function removeTeam($subrepositoryName, $teamId) 69 | { 70 | return $this->delete(sprintf('/subrepositories/%s/teams/%s/', $subrepositoryName, $teamId)); 71 | } 72 | 73 | /** 74 | * @deprecated use packages()->all() 75 | */ 76 | #[\Deprecated('Use Subrepositories::packages()->all() instead', '1.16.1')] 77 | public function listPackages($subrepositoryName) 78 | { 79 | return $this->packages()->all($subrepositoryName); 80 | } 81 | 82 | public function listTokens($subrepositoryName) 83 | { 84 | return $this->get(sprintf('/subrepositories/%s/tokens/', $subrepositoryName)); 85 | } 86 | 87 | public function createToken($subrepositoryName, array $tokenData) 88 | { 89 | return $this->post(sprintf('/subrepositories/%s/tokens/', $subrepositoryName), $tokenData); 90 | } 91 | 92 | public function removeToken($subrepositoryName, $tokenId) 93 | { 94 | return $this->delete(sprintf('/subrepositories/%s/tokens/%s/', $subrepositoryName, $tokenId)); 95 | } 96 | 97 | public function regenerateToken($subrepositoryName, $tokenId, array $confirmation) 98 | { 99 | if (!isset($confirmation['IConfirmOldTokenWillStopWorkingImmediately'])) { 100 | throw new InvalidArgumentException('Confirmation is required to regenerate the Composer repository token.'); 101 | } 102 | 103 | return $this->post(sprintf('/subrepositories/%s/tokens/%s/regenerate', $subrepositoryName, $tokenId), $confirmation); 104 | } 105 | 106 | public function packages() 107 | { 108 | return new Subrepositories\Packages($this->client); 109 | } 110 | 111 | public function mirroredRepositories() 112 | { 113 | return new Subrepositories\MirroredRepositories($this->client); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/Api/Subrepositories/MirroredRepositories.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api\Subrepositories; 11 | 12 | use PrivatePackagist\ApiClient\Api\AbstractApi; 13 | use PrivatePackagist\ApiClient\Exception\InvalidArgumentException; 14 | 15 | /** 16 | * @deprecated Use \PrivatePackagist\ApiClient\Api\Suborganizations\MirroredRepositories instead 17 | */ 18 | class MirroredRepositories extends AbstractApi 19 | { 20 | public function all($subrepositoryName) 21 | { 22 | return $this->get(sprintf('/subrepositories/%s/mirrored-repositories/', $subrepositoryName)); 23 | } 24 | 25 | public function add($subrepositoryName, array $mirroredRepositories) 26 | { 27 | foreach ($mirroredRepositories as $mirroredRepository) { 28 | if (!isset($mirroredRepository['id'], $mirroredRepository['mirroringBehavior'])) { 29 | throw new InvalidArgumentException('The "id" and the "mirroringBehavior" are required to add a mirrored repository to a project'); 30 | } 31 | } 32 | 33 | return $this->post(sprintf('/subrepositories/%s/mirrored-repositories/', $subrepositoryName), $mirroredRepositories); 34 | } 35 | 36 | public function show($subrepositoryName, $mirroredRepositoryId) 37 | { 38 | return $this->get(sprintf('/subrepositories/%s/mirrored-repositories/%s/', $subrepositoryName, $mirroredRepositoryId)); 39 | } 40 | 41 | public function edit($subrepositoryName, $mirroredRepositoryId, $mirroringBehavior) 42 | { 43 | return $this->put(sprintf('/subrepositories/%s/mirrored-repositories/%s/', $subrepositoryName, $mirroredRepositoryId), [ 44 | 'mirroringBehavior' => $mirroringBehavior, 45 | ]); 46 | } 47 | 48 | public function remove($subrepositoryName, $mirroredRepositoryId) 49 | { 50 | return $this->delete(sprintf('/subrepositories/%s/mirrored-repositories/%s/', $subrepositoryName, $mirroredRepositoryId)); 51 | } 52 | 53 | public function listPackages($subrepositoryName, $mirroredRepositoryId) 54 | { 55 | return $this->get(sprintf('/subrepositories/%s/mirrored-repositories/%s/packages/', $subrepositoryName, $mirroredRepositoryId)); 56 | } 57 | 58 | public function addPackages($subrepositoryName, $mirroredRepositoryId, array $packages) 59 | { 60 | return $this->post(sprintf('/subrepositories/%s/mirrored-repositories/%s/packages/', $subrepositoryName, $mirroredRepositoryId), $packages); 61 | } 62 | 63 | public function removePackages($subrepositoryName, $mirroredRepositoryId) 64 | { 65 | return $this->delete(sprintf('/subrepositories/%s/mirrored-repositories/%s/packages/', $subrepositoryName, $mirroredRepositoryId)); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Api/Subrepositories/Packages.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api\Subrepositories; 11 | 12 | use PrivatePackagist\ApiClient\Api\AbstractApi; 13 | use PrivatePackagist\ApiClient\Exception\InvalidArgumentException; 14 | use PrivatePackagist\ApiClient\Payload\CustomPackageConfig; 15 | use PrivatePackagist\ApiClient\Payload\VcsPackageConfig; 16 | 17 | /** 18 | * @deprecated Use \PrivatePackagist\ApiClient\Api\Suborganizations\Packages instead 19 | */ 20 | class Packages extends AbstractApi 21 | { 22 | public function all($subrepositoryName, array $filters = []) 23 | { 24 | if (isset($filters['origin']) && !in_array($filters['origin'], \PrivatePackagist\ApiClient\Api\Packages::AVAILABLE_ORIGINS, true)) { 25 | throw new InvalidArgumentException('Filter "origin" has to be one of: "' . implode('", "', \PrivatePackagist\ApiClient\Api\Packages::AVAILABLE_ORIGINS) . '".'); 26 | } 27 | 28 | return $this->get(sprintf('/subrepositories/%s/packages/', $subrepositoryName), $filters); 29 | } 30 | 31 | public function show($subrepositoryName, $packageIdOrName) 32 | { 33 | return $this->get(sprintf('/subrepositories/%s/packages/%s', $subrepositoryName, $packageIdOrName)); 34 | } 35 | 36 | public function createVcsPackage($subrepositoryName, $url, $credentialId = null, $type = 'vcs', $defaultSubrepositoryAccess = null) 37 | { 38 | $data = new VcsPackageConfig($url, $credentialId, $type, $defaultSubrepositoryAccess); 39 | 40 | return $this->post(sprintf('/subrepositories/%s/packages/', $subrepositoryName), $data->toParameters()); 41 | } 42 | 43 | public function createCustomPackage($subrepositoryName, $customJson, $credentialId = null, $defaultSubrepositoryAccess = null) 44 | { 45 | $data = new CustomPackageConfig($customJson, $credentialId, $defaultSubrepositoryAccess); 46 | 47 | return $this->post(sprintf('/subrepositories/%s/packages/', $subrepositoryName), $data->toParameters()); 48 | } 49 | 50 | public function editVcsPackage($subrepositoryName, $packageIdOrName, $url, $credentialId = null, $type = 'vcs', $defaultSubrepositoryAccess = null) 51 | { 52 | $data = new VcsPackageConfig($url, $credentialId, $type, $defaultSubrepositoryAccess); 53 | 54 | return $this->put(sprintf('/subrepositories/%s/packages/%s/', $subrepositoryName, $packageIdOrName), $data->toParameters()); 55 | } 56 | 57 | public function editCustomPackage($subrepositoryName, $packageIdOrName, $customJson, $credentialId = null, $defaultSubrepositoryAccess = null) 58 | { 59 | $data = new CustomPackageConfig($customJson, $credentialId, $defaultSubrepositoryAccess); 60 | 61 | return $this->put(sprintf('/subrepositories/%s/packages/%s/', $subrepositoryName, $packageIdOrName), $data->toParameters()); 62 | } 63 | 64 | public function remove($subrepositoryName, $packageIdOrName) 65 | { 66 | return $this->delete(sprintf('/subrepositories/%s/packages/%s/', $subrepositoryName, $packageIdOrName)); 67 | } 68 | 69 | public function listDependents($subrepositoryName, $packageIdOrName) 70 | { 71 | return $this->get(sprintf('/subrepositories/%s/packages/%s/dependents/', $subrepositoryName, $packageIdOrName)); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Api/Synchronizations.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api; 11 | 12 | class Synchronizations extends AbstractApi 13 | { 14 | public function all() 15 | { 16 | return $this->get('/synchronizations/'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Api/Teams.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api; 11 | 12 | use PrivatePackagist\ApiClient\TeamPermissions; 13 | 14 | class Teams extends AbstractApi 15 | { 16 | public function all() 17 | { 18 | return $this->get('/teams/'); 19 | } 20 | 21 | public function create(string $name, TeamPermissions $permissions): array 22 | { 23 | $parameters = [ 24 | 'name' => $name, 25 | 'permissions' => [ 26 | 'canEditTeamPackages' => (bool) $permissions->canEditTeamPackages, 27 | 'canAddPackages' => (bool) $permissions->canAddPackages, 28 | 'canCreateSuborganizations' => $permissions->canCreateSuborganizations || $permissions->canCreateSubrepositories, 29 | 'canViewVendorCustomers' => (bool) $permissions->canViewVendorCustomers, 30 | 'canManageVendorCustomers' => (bool) $permissions->canManageVendorCustomers, 31 | ], 32 | ]; 33 | 34 | return $this->post('/teams/', $parameters); 35 | } 36 | 37 | public function show($teamId) 38 | { 39 | return $this->get(sprintf('/teams/%s/', $teamId)); 40 | } 41 | 42 | public function edit($teamId, string $name, TeamPermissions $permissions): array 43 | { 44 | $parameters = [ 45 | 'name' => $name, 46 | 'permissions' => [ 47 | 'canEditTeamPackages' => (bool) $permissions->canEditTeamPackages, 48 | 'canAddPackages' => (bool) $permissions->canAddPackages, 49 | 'canCreateSuborganizations' => $permissions->canCreateSuborganizations || $permissions->canCreateSubrepositories, 50 | 'canViewVendorCustomers' => (bool) $permissions->canViewVendorCustomers, 51 | 'canManageVendorCustomers' => (bool) $permissions->canManageVendorCustomers, 52 | ], 53 | ]; 54 | 55 | return $this->put(sprintf('/teams/%s/', $teamId), $parameters); 56 | } 57 | 58 | public function grantAccessToAllPackages($teamId): array 59 | { 60 | return $this->put(sprintf('/teams/%s/all-package-access/grant', $teamId)); 61 | } 62 | 63 | public function revokeAccessToAllPackages($teamId): array 64 | { 65 | return $this->put(sprintf('/teams/%s/all-package-access/revoke', $teamId)); 66 | } 67 | 68 | public function remove($teamId): array 69 | { 70 | return $this->delete(sprintf('/teams/%s/', $teamId)); 71 | } 72 | 73 | public function addMember($teamId, $userId): array 74 | { 75 | return $this->put(sprintf('/teams/%s/members/%s/', $teamId, $userId)); 76 | } 77 | 78 | public function removeMember($teamId, $userId): array 79 | { 80 | return $this->delete(sprintf('/teams/%s/members/%s/', $teamId, $userId)); 81 | } 82 | 83 | public function packages($teamId) 84 | { 85 | return $this->get(sprintf('/teams/%s/packages/', $teamId)); 86 | } 87 | 88 | public function addPackages($teamId, array $packages) 89 | { 90 | return $this->post(sprintf('/teams/%s/packages/', $teamId), $packages); 91 | } 92 | 93 | public function removePackage($teamId, $packageName) 94 | { 95 | return $this->delete(sprintf('/teams/%s/packages/%s/', $teamId, $packageName)); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Api/Tokens.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api; 11 | 12 | use PrivatePackagist\ApiClient\Exception\InvalidArgumentException; 13 | 14 | class Tokens extends AbstractApi 15 | { 16 | public function all() 17 | { 18 | return $this->get('/tokens/'); 19 | } 20 | 21 | public function create(array $tokenData) 22 | { 23 | if (isset($tokenData['teamId'], $tokenData['accessToAllPackages'])) { 24 | throw new InvalidArgumentException('Only set either "accessToAllPackages" or "teamId"'); 25 | } 26 | 27 | return $this->post('/tokens/', $tokenData); 28 | } 29 | 30 | public function remove($tokenId) 31 | { 32 | return $this->delete(sprintf('/tokens/%s/', $tokenId)); 33 | } 34 | 35 | public function regenerate($tokenId, array $confirmation) 36 | { 37 | if (!isset($confirmation['IConfirmOldTokenWillStopWorkingImmediately'])) { 38 | throw new InvalidArgumentException('Confirmation is required to regenerate the Composer repository token.'); 39 | } 40 | 41 | return $this->post(sprintf('/tokens/%s/regenerate', $tokenId), $confirmation); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Api/VendorBundles.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api; 11 | 12 | class VendorBundles extends AbstractApi 13 | { 14 | /** 15 | * @return array[] 16 | */ 17 | public function all() 18 | { 19 | return $this->get('/vendor-bundles/'); 20 | } 21 | 22 | /** 23 | * @param int $vendorBundleId 24 | * @return array 25 | */ 26 | public function show($vendorBundleId) 27 | { 28 | return $this->get(sprintf('/vendor-bundles/%s/', $vendorBundleId)); 29 | } 30 | 31 | /** 32 | * @param string $name 33 | * @param string|null $minimumAccessibleStability 34 | * @param string|null $versionConstraint 35 | * @param bool $assignAllPackages 36 | * @param int[] $synchronizationIds 37 | */ 38 | public function create($name, $minimumAccessibleStability = null, $versionConstraint = null, $assignAllPackages = false, array $synchronizationIds = []) 39 | { 40 | return $this->post('/vendor-bundles/', [ 41 | 'name' => $name, 42 | 'minimumAccessibleStability' => $minimumAccessibleStability, 43 | 'versionConstraint' => $versionConstraint, 44 | 'assignAllPackages' => $assignAllPackages, 45 | 'synchronizationIds' => $synchronizationIds, 46 | ]); 47 | } 48 | 49 | /** 50 | * @param int $vendorBundleId 51 | * @param array{name: string, minimumAccessibleStability?: string, versionConstraint?: string, assignAllPackages: bool, synchronizationIds?: int[]} $bundle 52 | * @return array 53 | */ 54 | public function edit($vendorBundleId, array $bundle) 55 | { 56 | return $this->put(sprintf('/vendor-bundles/%s/', $vendorBundleId), $bundle); 57 | } 58 | 59 | /** 60 | * @param int $vendorBundleId 61 | */ 62 | public function remove($vendorBundleId) 63 | { 64 | return $this->delete(sprintf('/vendor-bundles/%s/', $vendorBundleId)); 65 | } 66 | 67 | public function packages(): \PrivatePackagist\ApiClient\Api\VendorBundles\Packages 68 | { 69 | return new \PrivatePackagist\ApiClient\Api\VendorBundles\Packages($this->client); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Api/VendorBundles/Packages.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Api\VendorBundles; 11 | 12 | use PrivatePackagist\ApiClient\Api\AbstractApi; 13 | use PrivatePackagist\ApiClient\Exception\InvalidArgumentException; 14 | 15 | class Packages extends AbstractApi 16 | { 17 | /** 18 | * @param int $vendorBundleIds 19 | * @return array[] 20 | */ 21 | public function listPackages($vendorBundleIds) 22 | { 23 | return $this->get(sprintf('/vendor-bundles/%s/packages/', $vendorBundleIds)); 24 | } 25 | 26 | /** 27 | * @param int $vendorBundleId 28 | * @param array{name: string, versionConstraint?: string, minimumAccessibleStability?: string}[] $packages 29 | * @return array[] 30 | */ 31 | public function addOrEditPackages($vendorBundleId, array $packages) 32 | { 33 | foreach ($packages as $package) { 34 | if (!isset($package['name'])) { // @phpstan-ignore-line 35 | throw new InvalidArgumentException('Parameter "name" is required.'); 36 | } 37 | } 38 | 39 | return $this->post(sprintf('/vendor-bundles/%s/packages/', $vendorBundleId), $packages); 40 | } 41 | 42 | /** 43 | * @param int $vendorBundleId 44 | * @param string|int $packageIdOrName 45 | */ 46 | public function removePackage($vendorBundleId, $packageIdOrName) 47 | { 48 | return $this->delete(sprintf('/vendor-bundles/%s/packages/%s/', $vendorBundleId, $packageIdOrName)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Client.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient; 11 | 12 | use Http\Client\Common\Plugin; 13 | use Http\Discovery\Psr17FactoryDiscovery; 14 | use PrivatePackagist\ApiClient\HttpClient\HttpPluginClientBuilder; 15 | use PrivatePackagist\ApiClient\HttpClient\Message\ResponseMediator; 16 | use PrivatePackagist\ApiClient\HttpClient\Plugin\ExceptionThrower; 17 | use PrivatePackagist\ApiClient\HttpClient\Plugin\PathPrepend; 18 | use PrivatePackagist\ApiClient\HttpClient\Plugin\RequestSignature; 19 | 20 | class Client 21 | { 22 | /** @var HttpPluginClientBuilder */ 23 | private $httpClientBuilder; 24 | /** @var ResponseMediator */ 25 | private $responseMediator; 26 | 27 | /** @param string $privatePackagistUrl */ 28 | public function __construct(?HttpPluginClientBuilder $httpClientBuilder = null, $privatePackagistUrl = null, ?ResponseMediator $responseMediator = null) 29 | { 30 | $this->httpClientBuilder = $builder = $httpClientBuilder ?: new HttpPluginClientBuilder(); 31 | $privatePackagistUrl = $privatePackagistUrl ? : 'https://packagist.com'; 32 | $this->responseMediator = $responseMediator ? : new ResponseMediator(); 33 | 34 | $builder->addPlugin(new Plugin\AddHostPlugin(Psr17FactoryDiscovery::findUriFactory()->createUri($privatePackagistUrl))); 35 | $builder->addPlugin(new PathPrepend('/api')); 36 | $builder->addPlugin(new Plugin\RedirectPlugin()); 37 | $headers = [ 38 | 'User-Agent' => 'php-private-packagist-api (https://github.com/packagist/private-packagist-api-client)', 39 | ]; 40 | if ($apiClientVersion = $this->getApiClientVersion()) { 41 | $headers['API-CLIENT-VERSION'] = $apiClientVersion; 42 | } 43 | $builder->addPlugin(new Plugin\HeaderDefaultsPlugin($headers)); 44 | $builder->addPlugin(new ExceptionThrower($this->responseMediator)); 45 | } 46 | 47 | /** 48 | * @param string $key 49 | * @param string $secret 50 | */ 51 | public function authenticate( 52 | #[\SensitiveParameter] 53 | $key, 54 | #[\SensitiveParameter] 55 | $secret 56 | ) { 57 | $this->httpClientBuilder->removePlugin(RequestSignature::class); 58 | $this->httpClientBuilder->addPlugin(new RequestSignature($key, $secret)); 59 | } 60 | 61 | public function credentials() 62 | { 63 | return new Api\Credentials($this, $this->responseMediator); 64 | } 65 | 66 | public function teams() 67 | { 68 | return new Api\Teams($this, $this->responseMediator); 69 | } 70 | 71 | public function customers() 72 | { 73 | return new Api\Customers($this, $this->responseMediator); 74 | } 75 | 76 | /** 77 | * @deprecated Use Client::suborganizations instead 78 | */ 79 | #[\Deprecated('Use Client::suborganizations instead', '1.16.1')] 80 | public function projects() 81 | { 82 | return new Api\Subrepositories($this, $this->responseMediator); 83 | } 84 | 85 | /** 86 | * @deprecated Use Client::suborganizations instead 87 | */ 88 | #[\Deprecated('Use Client::suborganizations instead', '1.38.0')] 89 | public function subrepositories() 90 | { 91 | return new Api\Subrepositories($this, $this->responseMediator); 92 | } 93 | 94 | public function suborganizations() 95 | { 96 | return new Api\Suborganizations($this, $this->responseMediator); 97 | } 98 | 99 | public function organization() 100 | { 101 | return new Api\Organization($this, $this->responseMediator); 102 | } 103 | 104 | public function packages() 105 | { 106 | return new Api\Packages($this, $this->responseMediator); 107 | } 108 | 109 | public function securityIssues() 110 | { 111 | return new Api\SecurityIssues($this, $this->responseMediator); 112 | } 113 | 114 | public function jobs() 115 | { 116 | return new Api\Jobs($this, $this->responseMediator); 117 | } 118 | 119 | public function mirroredRepositories() 120 | { 121 | return new Api\MirroredRepositories($this, $this->responseMediator); 122 | } 123 | 124 | public function tokens() 125 | { 126 | return new Api\Tokens($this, $this->responseMediator); 127 | } 128 | 129 | public function synchronizations() 130 | { 131 | return new Api\Synchronizations($this, $this->responseMediator); 132 | } 133 | 134 | public function vendorBundles() 135 | { 136 | return new Api\VendorBundles($this, $this->responseMediator); 137 | } 138 | 139 | public function getHttpClient() 140 | { 141 | return $this->getHttpClientBuilder()->getHttpClient(); 142 | } 143 | 144 | public function getResponseMediator() 145 | { 146 | return $this->responseMediator; 147 | } 148 | 149 | protected function getHttpClientBuilder() 150 | { 151 | return $this->httpClientBuilder; 152 | } 153 | 154 | private function getApiClientVersion() 155 | { 156 | try { 157 | return \Composer\InstalledVersions::getVersion('private-packagist/api-client'); 158 | } catch (\OutOfBoundsException $exception) { 159 | return null; 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/Exception/ErrorException.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Exception; 11 | 12 | class ErrorException extends \ErrorException implements ExceptionInterface 13 | { 14 | } 15 | -------------------------------------------------------------------------------- /src/Exception/ExceptionInterface.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Exception; 11 | 12 | interface ExceptionInterface 13 | { 14 | } 15 | -------------------------------------------------------------------------------- /src/Exception/HttpTransportException.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Exception; 11 | 12 | use Throwable; 13 | 14 | class HttpTransportException extends RuntimeException 15 | { 16 | private $requestUri; 17 | 18 | public function __construct($message = "", $code = 0, $requestUri = "", ?Throwable $previous = null) 19 | { 20 | $this->requestUri = $requestUri; 21 | parent::__construct($message, $code, $previous); 22 | } 23 | 24 | /** 25 | * @return string 26 | */ 27 | public function getRequestUri() 28 | { 29 | return $this->requestUri; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Exception/InvalidArgumentException.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Exception; 11 | 12 | class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface 13 | { 14 | } 15 | -------------------------------------------------------------------------------- /src/Exception/JobErrorException.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Exception; 11 | 12 | class JobErrorException extends RuntimeException 13 | { 14 | /** @var array */ 15 | private $job; 16 | 17 | public function __construct(array $job) 18 | { 19 | $this->job = $job; 20 | 21 | parent::__construct($job['message']); 22 | } 23 | 24 | /** 25 | * @return array 26 | */ 27 | public function getJob() 28 | { 29 | return $this->job; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Exception/JobTimeoutException.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Exception; 11 | 12 | class JobTimeoutException extends RuntimeException 13 | { 14 | } 15 | -------------------------------------------------------------------------------- /src/Exception/ResourceNotFoundException.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Exception; 11 | 12 | class ResourceNotFoundException extends HttpTransportException 13 | { 14 | } 15 | -------------------------------------------------------------------------------- /src/Exception/RuntimeException.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Exception; 11 | 12 | class RuntimeException extends \RuntimeException implements ExceptionInterface 13 | { 14 | } 15 | -------------------------------------------------------------------------------- /src/HttpClient/HttpPluginClientBuilder.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\HttpClient; 11 | 12 | use Http\Client\Common\HttpMethodsClient; 13 | use Http\Client\Common\Plugin; 14 | use Http\Client\Common\PluginClient; 15 | use Http\Discovery\Psr17FactoryDiscovery; 16 | use Http\Discovery\Psr18ClientDiscovery; 17 | use Http\Message\RequestFactory; 18 | use Psr\Http\Client\ClientInterface; 19 | use Psr\Http\Message\RequestFactoryInterface; 20 | use Psr\Http\Message\StreamFactoryInterface; 21 | 22 | class HttpPluginClientBuilder 23 | { 24 | /** @var ClientInterface */ 25 | private $httpClient; 26 | /** @var HttpMethodsClient|null */ 27 | private $pluginClient; 28 | /** @var RequestFactory|RequestFactoryInterface */ 29 | private $requestFactory; 30 | /** @var StreamFactoryInterface */ 31 | private $streamFactory; 32 | /** @var Plugin[] */ 33 | private $plugins = []; 34 | 35 | /** 36 | * @param RequestFactory|RequestFactoryInterface|null $requestFactory 37 | * @param StreamFactoryInterface|null $streamFactory 38 | */ 39 | public function __construct( 40 | ?ClientInterface $httpClient = null, 41 | $requestFactory = null, 42 | ?StreamFactoryInterface $streamFactory= null 43 | ) { 44 | $requestFactory = $requestFactory ?? Psr17FactoryDiscovery::findRequestFactory(); 45 | if ($requestFactory instanceof RequestFactory) { 46 | // Use same format as symfony/deprecation-contracts. 47 | @trigger_error(sprintf( 48 | 'Since %s %s: %s is deprecated, use %s instead.', 49 | 'private-packagist/api-client', 50 | '1.36.0', 51 | RequestFactory::class, 52 | RequestFactoryInterface::class 53 | ), \E_USER_DEPRECATED); 54 | } elseif (!$requestFactory instanceof RequestFactoryInterface) { 55 | /** @var mixed $requestFactory value unknown; set to mixed, prevent PHPStan complaining about guard clauses */ 56 | throw new \TypeError(sprintf( 57 | '%s::__construct(): Argument #2 ($requestFactory) must be of type %s|%s, %s given', 58 | self::class, 59 | RequestFactory::class, 60 | RequestFactoryInterface::class, 61 | is_object($requestFactory) ? get_class($requestFactory) : gettype($requestFactory) 62 | )); 63 | } 64 | 65 | $this->httpClient = $httpClient ?? Psr18ClientDiscovery::find(); 66 | $this->requestFactory = $requestFactory; 67 | $this->streamFactory = $streamFactory ?? Psr17FactoryDiscovery::findStreamFactory(); 68 | } 69 | 70 | public function addPlugin(Plugin $plugin) 71 | { 72 | $this->plugins[] = $plugin; 73 | $this->pluginClient = null; 74 | } 75 | 76 | /** 77 | * @param class-string $pluginClass 78 | */ 79 | public function removePlugin($pluginClass) 80 | { 81 | foreach ($this->plugins as $idx => $plugin) { 82 | if ($plugin instanceof $pluginClass) { 83 | unset($this->plugins[$idx]); 84 | $this->pluginClient = null; 85 | } 86 | } 87 | } 88 | 89 | public function getHttpClient() 90 | { 91 | if (!$this->pluginClient) { 92 | $this->pluginClient = new HttpMethodsClient( 93 | new PluginClient($this->httpClient, $this->plugins), 94 | $this->requestFactory, 95 | $this->streamFactory 96 | ); 97 | } 98 | 99 | return $this->pluginClient; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/HttpClient/Message/ResponseMediator.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\HttpClient\Message; 11 | 12 | use Psr\Http\Message\ResponseInterface; 13 | 14 | class ResponseMediator 15 | { 16 | /** 17 | * @return mixed|string 18 | */ 19 | public function getContent(ResponseInterface $response) 20 | { 21 | $body = $response->getBody()->__toString(); 22 | if (strpos($response->getHeaderLine('Content-Type'), 'application/json') === 0) { 23 | $content = json_decode($body, true); 24 | if (JSON_ERROR_NONE === json_last_error()) { 25 | return $content; 26 | } 27 | } 28 | 29 | return $body; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/HttpClient/Plugin/ExceptionThrower.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\HttpClient\Plugin; 11 | 12 | use Http\Client\Common\Plugin; 13 | use PrivatePackagist\ApiClient\Exception\ErrorException; 14 | use PrivatePackagist\ApiClient\Exception\HttpTransportException; 15 | use PrivatePackagist\ApiClient\Exception\ResourceNotFoundException; 16 | use PrivatePackagist\ApiClient\HttpClient\Message\ResponseMediator; 17 | use Psr\Http\Message\RequestInterface; 18 | use Psr\Http\Message\ResponseInterface; 19 | 20 | class ExceptionThrower implements Plugin 21 | { 22 | use Plugin\VersionBridgePlugin; 23 | 24 | /** @var ResponseMediator */ 25 | private $responseMediator; 26 | 27 | public function __construct(?ResponseMediator $responseMediator = null) 28 | { 29 | $this->responseMediator = $responseMediator ? : new ResponseMediator(); 30 | } 31 | 32 | protected function doHandleRequest(RequestInterface $request, callable $next, callable $first) 33 | { 34 | return $next($request)->then(function (ResponseInterface $response) use ($request) { 35 | if ($response->getStatusCode() < 400 || $response->getStatusCode() > 600) { 36 | return $response; 37 | } 38 | 39 | $content = $this->responseMediator->getContent($response); 40 | if (is_array($content) && isset($content['message'])) { 41 | if ($response->getStatusCode() === 400) { 42 | throw new ErrorException($content['message'], $response->getStatusCode()); 43 | } 44 | 45 | if ($response->getStatusCode() === 404) { 46 | throw new ResourceNotFoundException($content['message'], $response->getStatusCode(), $request->getUri()); 47 | } 48 | } 49 | 50 | if (isset($content['message'])) { 51 | $message = $content['message']; 52 | } elseif (is_string($content)) { 53 | $message = $content; 54 | } else { 55 | $message = json_encode($content); 56 | } 57 | 58 | throw new HttpTransportException($message, $response->getStatusCode(), $request->getUri()); 59 | }); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/HttpClient/Plugin/PathPrepend.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\HttpClient\Plugin; 11 | 12 | use Http\Client\Common\Plugin; 13 | use Psr\Http\Message\RequestInterface; 14 | 15 | class PathPrepend implements Plugin 16 | { 17 | use Plugin\VersionBridgePlugin; 18 | 19 | /** @var string */ 20 | private $path; 21 | 22 | /** 23 | * @param string $path 24 | */ 25 | public function __construct($path) 26 | { 27 | $this->path = $path; 28 | } 29 | 30 | /** 31 | * {@inheritdoc} 32 | */ 33 | protected function doHandleRequest(RequestInterface $request, callable $next, callable $first) 34 | { 35 | $uri = $request->getUri(); 36 | 37 | if (strpos($uri->getPath(), $this->path) !== 0) { 38 | $request = $request->withUri($uri->withPath($this->path . $uri->getPath())); 39 | } 40 | 41 | return $next($request); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/HttpClient/Plugin/RequestSignature.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\HttpClient\Plugin; 11 | 12 | use Http\Client\Common\Plugin; 13 | use Psr\Http\Message\RequestInterface; 14 | 15 | class RequestSignature implements Plugin 16 | { 17 | use Plugin\VersionBridgePlugin; 18 | 19 | /** @var string */ 20 | private $key; 21 | /** @var string */ 22 | private $secret; 23 | 24 | /** 25 | * @param string $key 26 | * @param string $secret 27 | */ 28 | public function __construct( 29 | #[\SensitiveParameter] 30 | $key, 31 | #[\SensitiveParameter] 32 | $secret 33 | ) { 34 | if (!$key || !$secret) { 35 | throw new \InvalidArgumentException('$key and $secret must be set'); 36 | } 37 | 38 | $this->key = $key; 39 | $this->secret = $secret; 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | protected function doHandleRequest(RequestInterface $request, callable $next, callable $first) 46 | { 47 | $params = [ 48 | 'key' => $this->key, 49 | 'timestamp' => $this->getTimestamp(), 50 | 'cnonce' => $this->getNonce(), 51 | ]; 52 | 53 | $content = (string) $request->getBody(); 54 | if ($content) { 55 | $params['body'] = $content; 56 | } 57 | 58 | $request = $request->withHeader('Authorization', sprintf( 59 | 'PACKAGIST-HMAC-SHA256 Key=%s, Timestamp=%s, Cnonce=%s, Signature=%s', 60 | $params['key'], 61 | $params['timestamp'], 62 | $params['cnonce'], 63 | $this->generateSignature($request, $params) 64 | )); 65 | 66 | return $next($request); 67 | } 68 | 69 | protected function getTimestamp() 70 | { 71 | return (int) gmdate('U'); 72 | } 73 | 74 | protected function getNonce() 75 | { 76 | return bin2hex(random_bytes(20)); 77 | } 78 | 79 | private function generateSignature(RequestInterface $request, array $params) 80 | { 81 | $data = $request->getMethod() . "\n" 82 | . $request->getUri()->getHost() . "\n" 83 | . $request->getUri()->getPath() . "\n" 84 | . $this->normalizeParameters($params); 85 | 86 | return \base64_encode( 87 | \hash_hmac('sha256', $data, $this->secret, true) 88 | ); 89 | } 90 | 91 | private function normalizeParameters(array $params) 92 | { 93 | uksort($params, 'strcmp'); 94 | 95 | return http_build_query($params, '', '&', PHP_QUERY_RFC3986); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/JobHelper.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient; 11 | 12 | use PrivatePackagist\ApiClient\Exception\JobErrorException; 13 | use PrivatePackagist\ApiClient\Exception\JobTimeoutException; 14 | 15 | class JobHelper 16 | { 17 | /** @var Client */ 18 | private $packagistClient; 19 | 20 | public function __construct(Client $packagistClient) 21 | { 22 | $this->packagistClient = $packagistClient; 23 | } 24 | 25 | /** 26 | * @param string $jobId 27 | * @param int $maxWaitSeconds 28 | * @param int $waitInterval 29 | * @return array 30 | */ 31 | public function waitForJob($jobId, $maxWaitSeconds = 180, $waitInterval = 5) 32 | { 33 | $maxWaitTime = new \DateTimeImmutable(sprintf('+%s seconds', $maxWaitSeconds)); 34 | while ($maxWaitTime> new \DateTimeImmutable()) { 35 | $job = $this->packagistClient->jobs()->show($jobId); 36 | 37 | if ($job['status'] === 'success') { 38 | return $job; 39 | } 40 | 41 | if ($job['status'] === 'error') { 42 | throw new JobErrorException($job); 43 | } 44 | 45 | sleep($waitInterval); 46 | } 47 | 48 | throw new JobTimeoutException(sprintf('Job has not finish after %s seconds', $maxWaitSeconds)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Payload/ArtifactPackageConfig.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Payload; 11 | 12 | /** 13 | * @internal 14 | * @final 15 | */ 16 | class ArtifactPackageConfig 17 | { 18 | /** @var int[] */ 19 | private $artifactPackageFileIds; 20 | /** @var ?string */ 21 | private $defaultSubrepositoryAccess; 22 | 23 | /** 24 | * @param int[] $artifactPackageFileIds 25 | * @param ?string $defaultSubrepositoryAccess 26 | */ 27 | public function __construct(array $artifactPackageFileIds, $defaultSubrepositoryAccess) 28 | { 29 | $this->artifactPackageFileIds = $artifactPackageFileIds; 30 | $this->defaultSubrepositoryAccess = $defaultSubrepositoryAccess; 31 | } 32 | 33 | /** 34 | * @return array{repoType: string, artifactIds: int[], defaultSubrepositoryAccess?: string} 35 | */ 36 | public function toParameters(): array 37 | { 38 | $data = [ 39 | 'repoType' => 'artifact', 40 | 'artifactIds' => $this->artifactPackageFileIds, 41 | ]; 42 | 43 | if ($this->defaultSubrepositoryAccess) { 44 | $data['defaultSubrepositoryAccess'] = $this->defaultSubrepositoryAccess; 45 | } 46 | 47 | return $data; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Payload/CustomPackageConfig.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Payload; 11 | 12 | /** 13 | * @internal 14 | * @final 15 | */ 16 | class CustomPackageConfig 17 | { 18 | /** @var string */ 19 | private $customJson; 20 | /** @var ?int */ 21 | private $credentialId; 22 | /** @var ?string */ 23 | private $defaultSubrepositoryAccess; 24 | 25 | /** 26 | * @param string|array|object $customJson 27 | * @param ?int $credentialId 28 | * @param ?string $defaultSubrepositoryAccess 29 | */ 30 | public function __construct($customJson, $credentialId, $defaultSubrepositoryAccess) 31 | { 32 | if (is_array($customJson) || is_object($customJson)) { 33 | $customJson = json_encode($customJson); 34 | } 35 | 36 | $this->customJson = $customJson; 37 | $this->credentialId = $credentialId; 38 | $this->defaultSubrepositoryAccess = $defaultSubrepositoryAccess; 39 | } 40 | 41 | /** 42 | * @return array{repoType: string, repoConfig: string, credentials: ?int, defaultSubrepositoryAccess?: string} 43 | */ 44 | public function toParameters(): array 45 | { 46 | $data = [ 47 | 'repoType' => 'package', 48 | 'repoConfig' => $this->customJson, 49 | 'credentials' => $this->credentialId, 50 | ]; 51 | 52 | if ($this->defaultSubrepositoryAccess) { 53 | $data['defaultSubrepositoryAccess'] = $this->defaultSubrepositoryAccess; 54 | } 55 | 56 | return $data; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Payload/VcsPackageConfig.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient\Payload; 11 | 12 | /** 13 | * @internal 14 | * @final 15 | */ 16 | class VcsPackageConfig 17 | { 18 | /** @var string */ 19 | private $url; 20 | /** @var ?int */ 21 | private $credentialId; 22 | /** @var string */ 23 | private $type; 24 | /** @var ?string */ 25 | private $defaultSubrepositoryAccess; 26 | 27 | /** 28 | * @param string $url 29 | * @param ?int $credentialId 30 | * @param string $type 31 | * @param ?string $defaultSubrepositoryAccess 32 | */ 33 | public function __construct($url, $credentialId, $type, $defaultSubrepositoryAccess) 34 | { 35 | $this->url = $url; 36 | $this->credentialId = $credentialId; 37 | $this->type = $type; 38 | $this->defaultSubrepositoryAccess = $defaultSubrepositoryAccess; 39 | } 40 | 41 | /** 42 | * @return array{repoType: string, repoUrl: string, credentials: ?int, defaultSubrepositoryAccess?: string} 43 | */ 44 | public function toParameters(): array 45 | { 46 | $data = [ 47 | 'repoType' => $this->type, 48 | 'repoUrl' => $this->url, 49 | 'credentials' => $this->credentialId, 50 | ]; 51 | 52 | if ($this->defaultSubrepositoryAccess) { 53 | $data['defaultSubrepositoryAccess'] = $this->defaultSubrepositoryAccess; 54 | } 55 | 56 | return $data; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/TeamPermissions.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient; 11 | 12 | final class TeamPermissions 13 | { 14 | public const PERMISSION_CAN_EDIT_TEAM_PACKAGES = 1 << 0; 15 | public const PERMISSION_CAN_ADD_PACKAGES = 1 << 1; 16 | /** @deprecated Use PERMISSION_CAN_CREATE_SUBORGANIZATIONS instead */ 17 | #[\Deprecated('Use TeamPermissions::PERMISSION_CAN_CREATE_SUBORGANIZATIONS instead', '1.38.0')] 18 | public const PERMISSION_CAN_CREATE_SUBREPOSITORIES = 1 << 2; 19 | public const PERMISSION_CAN_CREATE_SUBORGANIZATIONS = 1 << 2; 20 | public const PERMISSION_CAN_VIEW_VENDOR_CUSTOMERS = 1 << 3; 21 | public const PERMISSION_CAN_MANAGE_VENDOR_CUSTOMERS = 1 << 4; 22 | 23 | /** @var bool */ 24 | public $canEditTeamPackages = false; 25 | /** @var bool */ 26 | public $canAddPackages = false; 27 | /** 28 | * @var bool 29 | * @deprecated Use $canCreateSuborganizations instead 30 | */ 31 | public $canCreateSubrepositories = false; 32 | public $canCreateSuborganizations = false; 33 | /** @var bool */ 34 | public $canViewVendorCustomers = false; 35 | /** @var bool */ 36 | public $canManageVendorCustomers = false; 37 | 38 | public static function fromFlags(int $flags): self 39 | { 40 | $permissions = new self; 41 | $permissions->canEditTeamPackages = ($flags & self::PERMISSION_CAN_EDIT_TEAM_PACKAGES) > 0; 42 | $permissions->canAddPackages = ($flags & self::PERMISSION_CAN_ADD_PACKAGES) > 0; 43 | $permissions->canCreateSubrepositories = ($flags & self::PERMISSION_CAN_CREATE_SUBORGANIZATIONS) > 0; 44 | $permissions->canCreateSuborganizations = ($flags & self::PERMISSION_CAN_CREATE_SUBORGANIZATIONS) > 0; 45 | $permissions->canViewVendorCustomers = ($flags & self::PERMISSION_CAN_VIEW_VENDOR_CUSTOMERS) > 0; 46 | $permissions->canManageVendorCustomers = ($flags & self::PERMISSION_CAN_MANAGE_VENDOR_CUSTOMERS) > 0; 47 | return $permissions; 48 | } 49 | 50 | public static function fromTeamResponse(array $team): self 51 | { 52 | $canCreateSuborganizations = isset($team['permissions']['canCreateSuborganizations']) && $team['permissions']['canCreateSuborganizations'] || isset($team['permissions']['canCreateSubrepositories']) && $team['permissions']['canCreateSubrepositories']; 53 | 54 | $permissions = new self; 55 | $permissions->canEditTeamPackages = isset($team['permissions']['canEditTeamPackages']) && $team['permissions']['canEditTeamPackages']; 56 | $permissions->canAddPackages = isset($team['permissions']['canAddPackages']) && $team['permissions']['canAddPackages']; 57 | $permissions->canCreateSubrepositories = $canCreateSuborganizations; 58 | $permissions->canCreateSuborganizations = $canCreateSuborganizations; 59 | $permissions->canViewVendorCustomers = isset($team['permissions']['canViewVendorCustomers']) && $team['permissions']['canViewVendorCustomers']; 60 | $permissions->canManageVendorCustomers = isset($team['permissions']['canManageVendorCustomers']) && $team['permissions']['canManageVendorCustomers']; 61 | return $permissions; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/WebhookSignature.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | namespace PrivatePackagist\ApiClient; 11 | 12 | class WebhookSignature 13 | { 14 | /** @var string */ 15 | private $secret; 16 | 17 | public function __construct( 18 | #[\SensitiveParameter] 19 | $secret 20 | ) { 21 | $this->secret = $secret; 22 | } 23 | 24 | /** 25 | * @param string $signature 26 | * @param ?string $payload 27 | * @return bool 28 | */ 29 | public function validate($signature, $payload) 30 | { 31 | $payloadSignature = 'sha1='.hash_hmac('sha1', $payload ?? '', $this->secret); 32 | 33 | return hash_equals($payloadSignature, (string) $signature); 34 | } 35 | } 36 | --------------------------------------------------------------------------------