Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for composer.json extra attribute #29

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ Alternatively you can add an entry to your **`.env`** file:
ACF_PRO_KEY=Your-Key-Here
```

Or you can add an entry to your **`composer.json`** file:

```json
{
"extra": {
"advanced-custom-fields-pro-key": "Your-Key-Here"
}
}
```

**3. Require ACF PRO**

```sh
Expand Down
17 changes: 2 additions & 15 deletions src/ACFProInstaller/Exceptions/MissingKeyException.php
Original file line number Diff line number Diff line change
@@ -1,21 +1,8 @@
<?php namespace PhilippBaschke\ACFProInstaller\Exceptions;

/**
* Exception thrown if the ACF PRO key is not available in the environment
* Exception thrown if the ACF PRO key is not available.
*/
class MissingKeyException extends \Exception
abstract class MissingKeyException extends \Exception
{
public function __construct(
$message = '',
$code = 0,
\Exception $previous = null
) {
parent::__construct(
'Could not find a key for ACF PRO. ' .
'Please make it available via the environment variable ' .
$message,
$code,
$previous
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php namespace PhilippBaschke\ACFProInstaller\Exceptions;

/**
* Exception thrown if the ACF PRO key is not available in the composer extra section.
*/
class MissingKeyFromComposerExtraException extends MissingKeyException
{
public function __construct(
$message = '',
$code = 0,
\Exception $previous = null
) {
parent::__construct(
'Could not find a key for ACF PRO. ' .
'Please make it available via the composer extra section\'s ' .
$message,
$code,
$previous
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php namespace PhilippBaschke\ACFProInstaller\Exceptions;

/**
* Exception thrown if the ACF PRO key is not available in the environment.
*/
class MissingKeyFromEnvironmentException extends MissingKeyException
{
public function __construct(
$message = '',
$code = 0,
\Exception $previous = null
) {
parent::__construct(
'Could not find a key for ACF PRO. ' .
'Please make it available via the environment variable ' .
$message,
$code,
$previous
);
}
}
52 changes: 48 additions & 4 deletions src/ACFProInstaller/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
use Composer\Plugin\PluginInterface;
use Composer\Plugin\PreFileDownloadEvent;
use Dotenv\Dotenv;
use PhilippBaschke\ACFProInstaller\Exceptions\MissingKeyException;
use PhilippBaschke\ACFProInstaller\Exceptions\MissingKeyFromEnvironmentException;
use PhilippBaschke\ACFProInstaller\Exceptions\MissingKeyFromComposerExtraException;

/**
* A composer plugin that makes installing ACF PRO possible
Expand All @@ -32,6 +33,7 @@ class Plugin implements PluginInterface, EventSubscriberInterface
* where the ACF PRO key should be stored.
*/
const KEY_ENV_VARIABLE = 'ACF_PRO_KEY';
const KEY_COMPOSER_EXTRA_VARIABLE = 'advanced-custom-fields-pro-key';

/**
* The name of the ACF PRO package
Expand Down Expand Up @@ -141,7 +143,7 @@ public function addKey(PreFileDownloadEvent $event)
$this->addParameterToUrl(
$processedUrl,
'k',
$this->getKeyFromEnv()
$this->getKey()
),
$this->io,
$this->composer->getConfig(),
Expand Down Expand Up @@ -209,6 +211,22 @@ protected function isAcfProPackageUrl($url)
return strpos($url, self::ACF_PRO_PACKAGE_URL) !== false;
}

/**
* Get the ACF PRO key from the composer extra section or from the environment
*
* @access protected
* @return string The key from the composer extra section or from the environment
* @throws PhilippBaschke\ACFProInstaller\Exceptions\MissingKeyException
*/
protected function getKey()
{
try {
return $this->getKeyFromEnv();
} catch (MissingKeyFromEnvironmentException $e) {
return $this->getKeyFromComposerExtra();
}
}

/**
* Get the ACF PRO key from the environment
*
Expand All @@ -219,15 +237,15 @@ protected function isAcfProPackageUrl($url)
*
* @access protected
* @return string The key from the environment
* @throws PhilippBaschke\ACFProInstaller\Exceptions\MissingKeyException
* @throws PhilippBaschke\ACFProInstaller\Exceptions\MissingKeyFromEnvironmentException
*/
protected function getKeyFromEnv()
{
$this->loadDotEnv();
$key = getenv(self::KEY_ENV_VARIABLE);

if (!$key) {
throw new MissingKeyException(self::KEY_ENV_VARIABLE);
throw new MissingKeyFromEnvironmentException(self::KEY_ENV_VARIABLE);
}

return $key;
Expand All @@ -248,6 +266,32 @@ protected function loadDotEnv()
}
}

/**
* Get the ACF PRO key from the composer extra section
*
* Checks if there is a key avaiable in the composer.json extra section
* and gets the key from the variable KEY_COMPOSER_EXTRA_VARIABLE.
* Already set environment variable will not be overwritten by composer.json
*
* @access protected
* @return string The key from the environment
* @throws PhilippBaschke\ACFProInstaller\Exceptions\MissingKeyFromComposerExtraException
*/
protected function getKeyFromComposerExtra()
{
if ($this->composer) {
if ($package = $this->composer->getPackage()) {
if ($extra = $package->getExtra()) {
if (isset($extra[self::KEY_COMPOSER_EXTRA_VARIABLE])) {
return $extra[self::KEY_COMPOSER_EXTRA_VARIABLE];
}
}
}
}

throw new MissingKeyFromComposerExtraException(self::KEY_COMPOSER_EXTRA_VARIABLE);
}

/**
* Add a parameter to the given url
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php namespace PhilippBaschke\ACFProInstaller\Test\Exceptions;

use PhilippBaschke\ACFProInstaller\Exceptions\MissingKeyFromComposerExtraException;

class MissingKeyFromComposerExtraExceptionTest extends \PHPUnit_Framework_TestCase
{
public function testMessage()
{
$message = 'FIELD';
$e = new MissingKeyFromComposerExtraException($message);
$this->assertEquals(
'Could not find a key for ACF PRO. ' .
'Please make it available via the composer extra section\'s ' .
$message,
$e->getMessage()
);
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<?php namespace PhilippBaschke\ACFProInstaller\Test\Exceptions;

use PhilippBaschke\ACFProInstaller\Exceptions\MissingKeyException;
use PhilippBaschke\ACFProInstaller\Exceptions\MissingKeyFromEnvironmentException;

class MissingKeyExceptionTest extends \PHPUnit_Framework_TestCase
class MissingKeyFromEnvironmentExceptionTest extends \PHPUnit_Framework_TestCase
{
public function testMessage()
{
$message = 'FIELD';
$e = new MissingKeyException($message);
$e = new MissingKeyFromEnvironmentException($message);
$this->assertEquals(
'Could not find a key for ACF PRO. ' .
'Please make it available via the environment variable ' .
Expand Down
107 changes: 105 additions & 2 deletions tests/ACFProInstaller/PluginTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class PluginTest extends \PHPUnit_Framework_TestCase
const REPO_URL =
'https://connect.advancedcustomfields.com/index.php?p=pro&a=download';
const KEY_ENV_VARIABLE = 'ACF_PRO_KEY';
const KEY_COMPOSER_EXTRA_VARIABLE = 'advanced-custom-fields-pro-key';

protected function tearDown()
{
Expand Down Expand Up @@ -966,12 +967,114 @@ function ($rfs) use ($key) {
$plugin->addKey($event);
}

public function testAddKeyFromComposerExtra()
{
$key = 'COMPOSER_EXTRA_KEY';
$extra = [self::KEY_COMPOSER_EXTRA_VARIABLE => $key];

// Mock a Package
$package = $this
->getMockBuilder('Composer\Package\PackageInterface')
->setMethods(['getExtra'])
->getMockForAbstractClass();

$package
->expects($this->once())
->method('getExtra')
->willReturn($extra);

// Mock Config
$config = $this
->getMockBuilder('Composer\Config')
->getMock();

// Mock Composer
$composer = $this
->getMockBuilder('Composer\Composer')
->setMethods([
'getConfig',
'getPackage'
])
->getMock();

$composer
->expects($this->once())
->method('getConfig')
->willReturn($config);

$composer
->expects($this->once())
->method('getPackage')
->willReturn($package);

// Mock a RemoteFilesystem
$rfs = $this
->getMockBuilder('Composer\Util\RemoteFilesystem')
->disableOriginalConstructor()
->setMethods(['getOptions', 'isTlsDisabled'])
->getMock();

$rfs
->expects($this->once())
->method('getOptions')
->willReturn([]);

$rfs
->expects($this->once())
->method('isTlsDisabled')
->willReturn(true);

// Mock IOInterface
$io = $this
->getMockBuilder('Composer\IO\IOInterface')
->getMock();

// Mock an Event
$event = $this
->getMockBuilder('Composer\Plugin\PreFileDownloadEvent')
->disableOriginalConstructor()
->setMethods([
'getProcessedUrl',
'getRemoteFilesystem',
'setRemoteFilesystem'
])
->getMock();

$event
->expects($this->once())
->method('getProcessedUrl')
->willReturn(self::REPO_URL);

$event
->expects($this->once())
->method('getRemoteFilesystem')
->willReturn($rfs);

$event
->expects($this->once())
->method('setRemoteFilesystem')
->with($this->callback(
function ($rfs) use ($key) {
$this->assertAttributeContains(
"&k=$key",
'acfFileUrl',
$rfs
);
return true;
}
));

// Call addKey
$plugin = new Plugin();
$plugin->activate($composer, $io);
$plugin->addKey($event);
}

public function testThrowExceptionWhenKeyIsMissing()
{
// Expect an Exception
$this->setExpectedException(
'PhilippBaschke\ACFProInstaller\Exceptions\MissingKeyException',
'ACF_PRO_KEY'
'PhilippBaschke\ACFProInstaller\Exceptions\MissingKeyException'
);

// Mock a RemoteFilesystem
Expand Down