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
parent
8fd70d2dc4
commit
5c4f524d6a
|
@ -258,6 +258,38 @@ An example:
|
||||||
|
|
||||||
Optional.
|
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
|
### Package links
|
||||||
|
|
||||||
All of the following take an object which maps package names to
|
All of the following take an object which maps package names to
|
||||||
|
|
|
@ -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": {
|
"non-feature-branches": {
|
||||||
"type": ["array"],
|
"type": ["array"],
|
||||||
"description": "A set of string or regex patterns for non-numeric branch names that will not be handled as feature branches.",
|
"description": "A set of string or regex patterns for non-numeric branch names that will not be handled as feature branches.",
|
||||||
|
|
|
@ -377,6 +377,11 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
|
||||||
return $this->aliasOf->getSupport();
|
return $this->aliasOf->getSupport();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFunding()
|
||||||
|
{
|
||||||
|
return $this->aliasOf->getFunding();
|
||||||
|
}
|
||||||
|
|
||||||
public function getNotificationUrl()
|
public function getNotificationUrl()
|
||||||
{
|
{
|
||||||
return $this->aliasOf->getNotificationUrl();
|
return $this->aliasOf->getNotificationUrl();
|
||||||
|
|
|
@ -27,6 +27,7 @@ class CompletePackage extends Package implements CompletePackageInterface
|
||||||
protected $homepage;
|
protected $homepage;
|
||||||
protected $scripts = array();
|
protected $scripts = array();
|
||||||
protected $support = array();
|
protected $support = array();
|
||||||
|
protected $funding = array();
|
||||||
protected $abandoned = false;
|
protected $abandoned = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -171,6 +172,24 @@ class CompletePackage extends Package implements CompletePackageInterface
|
||||||
return $this->support;
|
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
|
* @return bool
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -79,6 +79,15 @@ interface CompletePackageInterface extends PackageInterface
|
||||||
*/
|
*/
|
||||||
public function getSupport();
|
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
|
* Returns if the package is abandoned or not
|
||||||
*
|
*
|
||||||
|
|
|
@ -104,6 +104,7 @@ class ArrayDumper
|
||||||
'keywords',
|
'keywords',
|
||||||
'repositories',
|
'repositories',
|
||||||
'support',
|
'support',
|
||||||
|
'funding',
|
||||||
);
|
);
|
||||||
|
|
||||||
$data = $this->dumpValues($package, $keys, $data);
|
$data = $this->dumpValues($package, $keys, $data);
|
||||||
|
|
|
@ -198,6 +198,10 @@ class ArrayLoader implements LoaderInterface
|
||||||
$package->setSupport($config['support']);
|
$package->setSupport($config['support']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($config['funding']) && is_array($config['funding'])) {
|
||||||
|
$package->setFunding($config['funding']);
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($config['abandoned'])) {
|
if (isset($config['abandoned'])) {
|
||||||
$package->setAbandoned($config['abandoned']);
|
$package->setAbandoned($config['abandoned']);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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'));
|
$unboundConstraint = new Constraint('=', $this->versionParser->normalize('dev-master'));
|
||||||
$stableConstraint = new Constraint('=', '1.0.0');
|
$stableConstraint = new Constraint('=', '1.0.0');
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,12 @@
|
||||||
"irc": "irc://irc.freenode.org/composer",
|
"irc": "irc://irc.freenode.org/composer",
|
||||||
"issues": "https://github.com/composer/composer/issues"
|
"issues": "https://github.com/composer/composer/issues"
|
||||||
},
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "service-subscription",
|
||||||
|
"url": "https://packagist.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.3.2",
|
"php": ">=5.3.2",
|
||||||
"justinrainbow/json-schema": "~1.4",
|
"justinrainbow/json-schema": "~1.4",
|
||||||
|
|
|
@ -191,6 +191,10 @@ class ArrayDumperTest extends TestCase
|
||||||
'support',
|
'support',
|
||||||
array('foo' => 'bar'),
|
array('foo' => 'bar'),
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'funding',
|
||||||
|
array('type' => 'foo', 'url' => 'https://example.com'),
|
||||||
|
),
|
||||||
array(
|
array(
|
||||||
'require',
|
'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')),
|
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')),
|
||||||
|
|
|
@ -97,6 +97,9 @@ class ArrayLoaderTest extends TestCase
|
||||||
'authors' => array(
|
'authors' => array(
|
||||||
array('name' => 'Bob', 'email' => 'bob@example.org', 'homepage' => 'example.org', 'role' => 'Developer'),
|
array('name' => 'Bob', 'email' => 'bob@example.org', 'homepage' => 'example.org', 'role' => 'Developer'),
|
||||||
),
|
),
|
||||||
|
'funding' => array(
|
||||||
|
array('type' => 'example', 'url' => 'https://example.org/fund'),
|
||||||
|
),
|
||||||
'require' => array(
|
'require' => array(
|
||||||
'foo/bar' => '1.0',
|
'foo/bar' => '1.0',
|
||||||
),
|
),
|
||||||
|
|
|
@ -73,6 +73,15 @@ class ValidatingArrayLoaderTest extends TestCase
|
||||||
'rss' => 'http://example.org/rss',
|
'rss' => 'http://example.org/rss',
|
||||||
'chat' => 'http://example.org/chat',
|
'chat' => 'http://example.org/chat',
|
||||||
),
|
),
|
||||||
|
'funding' => array(
|
||||||
|
array(
|
||||||
|
'type' => 'example',
|
||||||
|
'url' => 'https://example.org/fund'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'url' => 'https://example.org/fund'
|
||||||
|
),
|
||||||
|
),
|
||||||
'require' => array(
|
'require' => array(
|
||||||
'a/b' => '1.*',
|
'a/b' => '1.*',
|
||||||
'b/c' => '~2',
|
'b/c' => '~2',
|
||||||
|
|
Loading…
Reference in New Issue