1
0
Fork 0

Add funding field to composer.json

You can specify a list of funding options each with a type and URL. The
type is used to specify the kind of funding or the platform through
which funding is possible.
pull/8453/head
Nils Adermann 2019-11-28 22:34:29 +01:00 committed by Jordi Boggiano
parent 8fd70d2dc4
commit 5c4f524d6a
No known key found for this signature in database
GPG Key ID: 7BBD42C429EC80BC
12 changed files with 136 additions and 0 deletions

View File

@ -258,6 +258,38 @@ An example:
Optional.
### funding
A list of URLs to provide funding to the package authors for maintenance and
development of new functionality.
Each entry consists of the following
* **type:** The type of funding or the platform through which funding can be provided, e.g. patreon, opencollective, tidelift or github.
* **url:** URL to a website with details and a way to fund the package.
An example:
```json
{
"funding": [
{
"type": "patreon",
"url": "https://www.patreon.com/phpdoctrine"
},
{
"type": "tidelift",
"url": "https://tidelift.com/subscription/pkg/packagist-doctrine_doctrine-bundle"
},
{
"type": "other",
"url": "https://www.doctrine-project.org/sponsorship.html"
}
}
```
Optional.
### Package links
All of the following take an object which maps package names to

View File

@ -522,6 +522,24 @@
}
}
},
"funding": {
"type": "array",
"description": "A list of options to fund the development and maintenance of the package.",
"items": {
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "Type of funding or platform through which funding is possible."
},
"url": {
"type": "string",
"description": "URL to a website with details on funding and a way to fund the package.",
"format": "uri"
}
}
}
},
"non-feature-branches": {
"type": ["array"],
"description": "A set of string or regex patterns for non-numeric branch names that will not be handled as feature branches.",

View File

@ -377,6 +377,11 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
return $this->aliasOf->getSupport();
}
public function getFunding()
{
return $this->aliasOf->getFunding();
}
public function getNotificationUrl()
{
return $this->aliasOf->getNotificationUrl();

View File

@ -27,6 +27,7 @@ class CompletePackage extends Package implements CompletePackageInterface
protected $homepage;
protected $scripts = array();
protected $support = array();
protected $funding = array();
protected $abandoned = false;
/**
@ -171,6 +172,24 @@ class CompletePackage extends Package implements CompletePackageInterface
return $this->support;
}
/**
* Set the funding
*
* @param array $funding
*/
public function setFunding(array $funding)
{
$this->funding = $funding;
}
/**
* {@inheritDoc}
*/
public function getFunding()
{
return $this->funding;
}
/**
* @return bool
*/

View File

@ -79,6 +79,15 @@ interface CompletePackageInterface extends PackageInterface
*/
public function getSupport();
/**
* Returns an array of funding options for the package
*
* Each item will contain type and url keys
*
* @return array
*/
public function getFunding();
/**
* Returns if the package is abandoned or not
*

View File

@ -104,6 +104,7 @@ class ArrayDumper
'keywords',
'repositories',
'support',
'funding',
);
$data = $this->dumpValues($package, $keys, $data);

View File

@ -198,6 +198,10 @@ class ArrayLoader implements LoaderInterface
$package->setSupport($config['support']);
}
if (!empty($config['funding']) && is_array($config['funding'])) {
$package->setFunding($config['funding']);
}
if (isset($config['abandoned'])) {
$package->setAbandoned($config['abandoned']);
}

View File

@ -193,6 +193,32 @@ class ValidatingArrayLoader implements LoaderInterface
}
}
if ($this->validateArray('funding') && !empty($this->config['funding'])) {
foreach ($this->config['funding'] as $key => $fundingOption) {
if (!is_array($fundingOption)) {
$this->errors[] = 'funding.'.$key.' : should be an array, '.gettype($fundingOption).' given';
unset($this->config['funding'][$key]);
continue;
}
foreach (array('type', 'url') as $fundingData) {
if (isset($fundingOption[$fundingData]) && !is_string($fundingOption[$fundingData])) {
$this->errors[] = 'funding.'.$key.'.'.$fundingData.' : invalid value, must be a string';
unset($this->config['funding'][$key][$fundingData]);
}
}
if (isset($fundingOption['url']) && !$this->filterUrl($fundingOption['url'])) {
$this->warnings[] = 'funding.'.$key.'.url : invalid value ('.$fundingOption['url'].'), must be an http/https URL';
unset($this->config['funding'][$key]['url']);
}
if (empty($this->config['funding'][$key])) {
unset($this->config['funding'][$key]);
}
}
if (empty($this->config['funding'])) {
unset($this->config['funding']);
}
}
$unboundConstraint = new Constraint('=', $this->versionParser->normalize('dev-master'));
$stableConstraint = new Constraint('=', '1.0.0');

View File

@ -21,6 +21,12 @@
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/composer/issues"
},
"funding": [
{
"type": "service-subscription",
"url": "https://packagist.com"
}
],
"require": {
"php": ">=5.3.2",
"justinrainbow/json-schema": "~1.4",

View File

@ -191,6 +191,10 @@ class ArrayDumperTest extends TestCase
'support',
array('foo' => 'bar'),
),
array(
'funding',
array('type' => 'foo', 'url' => 'https://example.com'),
),
array(
'require',
array(new Link('foo', 'foo/bar', new Constraint('=', '1.0.0.0'), 'requires', '1.0.0'), new Link('bar', 'bar/baz', new Constraint('=', '1.0.0.0'), 'requires', '1.0.0')),

View File

@ -97,6 +97,9 @@ class ArrayLoaderTest extends TestCase
'authors' => array(
array('name' => 'Bob', 'email' => 'bob@example.org', 'homepage' => 'example.org', 'role' => 'Developer'),
),
'funding' => array(
array('type' => 'example', 'url' => 'https://example.org/fund'),
),
'require' => array(
'foo/bar' => '1.0',
),

View File

@ -73,6 +73,15 @@ class ValidatingArrayLoaderTest extends TestCase
'rss' => 'http://example.org/rss',
'chat' => 'http://example.org/chat',
),
'funding' => array(
array(
'type' => 'example',
'url' => 'https://example.org/fund'
),
array(
'url' => 'https://example.org/fund'
),
),
'require' => array(
'a/b' => '1.*',
'b/c' => '~2',