Skip to content

Commit

Permalink
Fix GitHub rate limit with cache (#55)
Browse files Browse the repository at this point in the history
* add cache compontent

* feat: TailwindBuilder - add cache for storing latest version from github

* test: inject cache to TailwindBinary instances

* dependency: deprecated Extension class from HttpKernel

* style: php-cs-fix
  • Loading branch information
eminjk authored May 21, 2024
1 parent e13e544 commit 1c075f2
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 17 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"symfony/asset-mapper": "^6.3|^7.0",
"symfony/console": "^5.4|^6.3|^7.0",
"symfony/http-client": "^5.4|^6.3|^7.0",
"symfony/process": "^5.4|^6.3|^7.0"
"symfony/process": "^5.4|^6.3|^7.0",
"symfony/cache": "^6.3|^7.0"
},
"require-dev": {
"symfony/filesystem": "^6.3|^7.0",
Expand Down
5 changes: 5 additions & 0 deletions config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,16 @@

return static function (ContainerConfigurator $container): void {
$container->services()
->set('cache.symfonycasts.tailwind_bundle')
->parent('cache.system')
->tag('cache.pool')

->set('tailwind.builder', TailwindBuilder::class)
->args([
param('kernel.project_dir'),
abstract_arg('path to source Tailwind CSS file'),
param('kernel.project_dir').'/var/tailwind',
service('cache.symfonycasts.tailwind_bundle'),
abstract_arg('path to tailwind binary'),
abstract_arg('Tailwind binary version'),
abstract_arg('path to Tailwind CSS config file'),
Expand Down
8 changes: 4 additions & 4 deletions src/DependencyInjection/TailwindExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;

class TailwindExtension extends Extension implements ConfigurationInterface
{
Expand All @@ -29,9 +29,9 @@ public function load(array $configs, ContainerBuilder $container): void

$container->findDefinition('tailwind.builder')
->replaceArgument(1, $config['input_css'])
->replaceArgument(3, $config['binary'])
->replaceArgument(4, $config['binary_version'])
->replaceArgument(5, $config['config_file'])
->replaceArgument(4, $config['binary'])
->replaceArgument(5, $config['binary_version'])
->replaceArgument(6, $config['config_file'])
;
}

Expand Down
22 changes: 14 additions & 8 deletions src/TailwindBinary.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@

namespace Symfonycasts\TailwindBundle;

use Psr\Cache\CacheItemInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\Process\Process;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;

/**
Expand All @@ -29,8 +31,9 @@ public function __construct(
private string $cwd,
private ?string $binaryPath,
private ?string $binaryVersion,
private CacheInterface $cache,
private ?SymfonyStyle $output = null,
?HttpClientInterface $httpClient = null,
?HttpClientInterface $httpClient = null
) {
$this->httpClient = $httpClient ?? HttpClient::create();
}
Expand Down Expand Up @@ -97,13 +100,16 @@ private function getVersion(): string

private function getLatestVersion(): string
{
try {
$response = $this->httpClient->request('GET', 'https://api.github.com/repos/tailwindlabs/tailwindcss/releases/latest');

return $response->toArray()['name'] ?? throw new \Exception('Cannot get the latest version name from response JSON.');
} catch (\Throwable $e) {
throw new \Exception('Cannot determine latest Tailwind CLI binary version. Please specify a version in the configuration.', previous: $e);
}
return $this->cache->get('latestVersion', function (CacheItemInterface $item) {
$item->expiresAfter(3600);
try {
$response = $this->httpClient->request('GET', 'https://api.github.com/repos/tailwindlabs/tailwindcss/releases/latest');

return $response->toArray()['name'] ?? throw new \Exception('Cannot get the latest version name from response JSON.');
} catch (\Throwable $e) {
throw new \Exception('Cannot determine latest Tailwind CLI binary version. Please specify a version in the configuration.', previous: $e);
}
});
}

/**
Expand Down
6 changes: 4 additions & 2 deletions src/TailwindBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Process\InputStream;
use Symfony\Component\Process\Process;
use Symfony\Contracts\Cache\CacheInterface;

/**
* Manages the process of executing Tailwind on the input file.
Expand All @@ -29,9 +30,10 @@ public function __construct(
private readonly string $projectRootDir,
string $inputPath,
private readonly string $tailwindVarDir,
private CacheInterface $cache,
private readonly ?string $binaryPath = null,
private readonly ?string $binaryVersion = null,
private readonly string $configPath = 'tailwind.config.js',
private readonly string $configPath = 'tailwind.config.js'
) {
if (is_file($inputPath)) {
$this->inputPath = $inputPath;
Expand Down Expand Up @@ -122,6 +124,6 @@ public function getOutputCssContent(): string

private function createBinary(): TailwindBinary
{
return new TailwindBinary($this->tailwindVarDir, $this->projectRootDir, $this->binaryPath, $this->binaryVersion, $this->output);
return new TailwindBinary($this->tailwindVarDir, $this->projectRootDir, $this->binaryPath, $this->binaryVersion, $this->cache, $this->output);
}
}
7 changes: 5 additions & 2 deletions tests/TailwindBinaryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Response\MockResponse;
use Symfony\Contracts\Cache\CacheInterface;
use Symfonycasts\TailwindBundle\TailwindBinary;

class TailwindBinaryTest extends TestCase
Expand All @@ -29,8 +30,9 @@ public function testBinaryIsDownloadedAndProcessCreated()
$client = new MockHttpClient([
new MockResponse('fake binary contents'),
]);
$cache = $this->createMock(CacheInterface::class);

$binary = new TailwindBinary($binaryDownloadDir, __DIR__, null, 'fake-version', null, $client);
$binary = new TailwindBinary($binaryDownloadDir, __DIR__, null, 'fake-version', $cache, null, $client);
$process = $binary->createProcess(['-i', 'fake.css']);
$this->assertFileExists($binaryDownloadDir.'/fake-version/'.TailwindBinary::getBinaryName());

Expand All @@ -46,8 +48,9 @@ public function testBinaryIsDownloadedAndProcessCreated()
public function testCustomBinaryUsed()
{
$client = new MockHttpClient();
$cache = $this->createMock(CacheInterface::class);

$binary = new TailwindBinary('', __DIR__, 'custom-binary', null, null, null, $client);
$binary = new TailwindBinary('', __DIR__, 'custom-binary', null, $cache, null, $client);
$process = $binary->createProcess(['-i', 'fake.css']);
// on windows, arguments are not wrapped in quotes
$expected = '\\' === \DIRECTORY_SEPARATOR ? 'custom-binary -i fake.css' : "'custom-binary' '-i' 'fake.css'";
Expand Down
3 changes: 3 additions & 0 deletions tests/TailwindBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
namespace Symfonycasts\TailwindBundle\Tests;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use Symfonycasts\TailwindBundle\TailwindBuilder;
Expand Down Expand Up @@ -40,6 +41,7 @@ public function testIntegrationWithDefaultOptions(): void
__DIR__.'/fixtures',
__DIR__.'/fixtures/assets/styles/app.css',
__DIR__.'/fixtures/var/tailwind',
new ArrayAdapter(),
null,
null,
__DIR__.'/fixtures/tailwind.config.js'
Expand All @@ -60,6 +62,7 @@ public function testIntegrationWithMinify(): void
__DIR__.'/fixtures',
__DIR__.'/fixtures/assets/styles/app.css',
__DIR__.'/fixtures/var/tailwind',
new ArrayAdapter(),
null,
null,
__DIR__.'/fixtures/tailwind.config.js'
Expand Down

0 comments on commit 1c075f2

Please sign in to comment.