diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index fd7168c..0000000 --- a/.appveyor.yml +++ /dev/null @@ -1,53 +0,0 @@ -## Thanks to Cees-Jan Kiewiet: https://blog.wyrihaximus.net/2016/11/running-php-unit-tests-on-windows-using-appveyor-and-chocolatey/ - -## Versioning pattern -version: 6.0.0-{build} - -## Disable unneeded features -build: off -deploy: off - -## Test against various PHP versions -environment: - matrix: - - php_version: "7.1" - - php_version: "7.2" - - php_version: "7.3" - -## Cache composer, chocolatey and php. -cache: - # Composer - - '%LOCALAPPDATA%\Composer\files -> composer.lock' - - composer.phar - # Cache chocolatey packages - - C:\ProgramData\chocolatey\bin -> .appveyor.yml - - C:\ProgramData\chocolatey\lib -> .appveyor.yml - # Cache php install - - c:\tools\php -> .appveyor.yml - -## Set up environment variables -init: - - SET PATH=C:\Program Files\OpenSSL;c:\tools\php;%PATH% - - SET COMPOSER_NO_INTERACTION=1 - - SET PHP=1 # This var is connected to PHP install cache - - SET ANSICON=121x90 (121x90) - -## Install PHP and composer, and run the appropriate composer command -install: - - IF EXIST c:\tools\php (SET PHP=0) # Checks for the PHP install being cached - - ps: appveyor-retry cinst --params '""/InstallDir:C:\tools\php""' --ignore-checksums -y php --version ((choco search php --exact --all-versions -r | select-string -pattern $env:php_version | sort { [version]($_ -split '\|' | select -last 1) } -Descending | Select-Object -first 1) -replace '[php|]','') - - cd c:\tools\php - - IF %PHP%==1 copy php.ini-production php.ini /Y - - IF %PHP%==1 echo date.timezone="UTC" >> php.ini - - IF %PHP%==1 echo extension_dir=ext >> php.ini - - IF %PHP%==1 echo extension=php_openssl.dll >> php.ini - - IF %PHP%==1 echo extension=php_mbstring.dll >> php.ini - - IF %PHP%==1 echo extension=php_fileinfo.dll >> php.ini - - IF %PHP%==1 echo @php %%~dp0composer.phar %%* > composer.bat - - appveyor-retry appveyor DownloadFile https://getcomposer.org/composer.phar - - cd c:\projects\assets - - appveyor-retry composer update --no-progress - -## Run the actual test -test_script: - - vendor/bin/phpunit diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 0000000..c464e2d --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,36 @@ +name: Continuous Integration +on: + # Every push + push: + schedule: + # Every Monday and Thursday at 12PM UTC + - cron: '0 12 * * 1,4' + +jobs: + test: + strategy: + matrix: + os: [ ubuntu-latest, macos-latest, windows-latest ] + php-version: [ '7.1', '7.2', '7.3', '7.4' ] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + coverage: xdebug + extensions: mbstring + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + - name: Retain composer cache + uses: actions/cache@v1 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + - run: composer install + - run: vendor/bin/phpunit --coverage-clover=coverage.xml +# - uses: codecov/codecov-action@v1 +# with: +# token: ${{ secrets.CODECOV_UPLOAD_TOKEN }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index fa2ae23..0000000 --- a/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -sudo: false -dist: trusty -language: php - -php: - - 7.1 - - 7.2 - - 7.3 - -cache: - directories: - - $HOME/.composer/cache - -before_script: - - composer install - -script: - - vendor/bin/phpunit --coverage-clover=coverage.xml - -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/CHANGELOG.md b/CHANGELOG.md index b043af2..a2f17c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [Unknown] +- Added partial caching support to development server + ## [6.0.0] - 2019-06-22 - Dropping support for PHP 5.6 & 7.0 - Updated PHPUnit to 7.5 diff --git a/README.md b/README.md index 107d265..b2363d6 100644 --- a/README.md +++ b/README.md @@ -7,26 +7,24 @@ | Branch | Build | Coverage | Style | | ------ | ----- | -------- | ----- | -| [master][master] | [![Build Status][master-build-travis-badge]][travis] [![Windows Build][master-build-appveyor-badge]][appveyor] | [![codecov][master-codecov-badge]][codecov] | [![][master-styleci-badge]][styleci] | -| [develop][develop] | [![Build Status][develop-build-travis-badge]][travis] [![Windows Build][develop-build-appveyor-badge]][appveyor] | [![codecov][develop-codecov-badge]][codecov] | [![][develop-styleci-badge]][styleci] | +| [master][master] | [![Continuous Integration][master-gh-ci-badge]](master-gh-ci) | [![codecov][master-codecov-badge]][codecov] | [![][master-styleci-badge]][styleci] | +| [develop][develop] | [![Continuous Integration][develop-gh-ci-badge]](develop-gh-ci) | [![codecov][develop-codecov-badge]][codecov] | [![][develop-styleci-badge]][styleci] | [codecov]: https://codecov.io/gh/userfrosting/assets [releases]: https://github.com/userfrosting/assets/releases [styleci]: https://github.styleci.io/repos/55460230 -[travis]: https://travis-ci.org/userfrosting/assets -[appveyor]: https://ci.appveyor.com/project/userfrosting/assets [version-badge]: https://img.shields.io/github/release/userfrosting/assets.svg [master]: https://github.com/userfrosting/assets/tree/master +[master-gh-ci]: https://github.com/userfrosting/assets/actions?query=branch:master+workflow:"Continuous+Integration" +[master-gh-ci-badge]: https://github.com/userfrosting/assets/workflows/Continuous%20Integration/badge.svg?branch=master [master-styleci-badge]: https://github.styleci.io/repos/55460230/shield?branch=master&style=flat [master-codecov-badge]: https://codecov.io/gh/userfrosting/assets/branch/master/graph/badge.svg -[master-build-travis-badge]: https://travis-ci.org/userfrosting/assets.svg?branch=master -[master-build-appveyor-badge]: https://ci.appveyor.com/api/projects/status/github/userfrosting/assets?branch=master&svg=true [develop]: https://github.com/userfrosting/assets/tree/develop +[develop-gh-ci]: https://github.com/userfrosting/assets/actions?query=branch:develop+workflow:"Continuous+Integration" +[develop-gh-ci-badge]: https://github.com/userfrosting/assets/workflows/Continuous%20Integration/badge.svg?branch=develop [develop-styleci-badge]: https://github.styleci.io/repos/55460230/shield?branch=develop&style=flat [develop-codecov-badge]: https://codecov.io/gh/userfrosting/assets/branch/develop/graph/badge.svg -[develop-build-travis-badge]: https://travis-ci.org/userfrosting/assets.svg?branch=develop -[develop-build-appveyor-badge]: https://ci.appveyor.com/api/projects/status/github/userfrosting/assets?branch=develop&svg=true **Assets** is a library originally created for UserFrosting 4 to make it much easier to reference frontend assets in both production and development contexts. diff --git a/src/AssetLoader.php b/src/AssetLoader.php index 5e4121f..2d06ab3 100644 --- a/src/AssetLoader.php +++ b/src/AssetLoader.php @@ -91,4 +91,14 @@ public function getType() { return MimeType::detectByFilename($this->fullPath); } + + /** + * Get the last modified date and time. + * + * @return \DateTime + */ + public function getLastModified(): \DateTime + { + return new \DateTime('@'.filemtime($this->fullPath)); + } } diff --git a/src/Assets.php b/src/Assets.php index 6f0a176..3c7051c 100644 --- a/src/Assets.php +++ b/src/Assets.php @@ -29,7 +29,7 @@ class Assets /** @var ResourceLocatorInterface Resource locator used to find assets. */ protected $locator; - /** @var string Scheme used when finding assets via $locator. */ + /** @var string Scheme used when finding assets via the provided locator. */ protected $locatorScheme; /** @var string Sites base URL and optionally assets directory. */ diff --git a/src/ServeAsset/SlimServeAsset.php b/src/ServeAsset/SlimServeAsset.php index 518e4b9..45dd94f 100644 --- a/src/ServeAsset/SlimServeAsset.php +++ b/src/ServeAsset/SlimServeAsset.php @@ -58,9 +58,24 @@ public function serveAsset(RequestInterface $request, ResponseInterface $respons return $response->withStatus(404); } - return $response - ->withHeader('Content-Type', $assetLoader->getType()) + // Generate file last modified + $lastModified = $assetLoader->getLastModified()->format('D, d M Y H:i:s \G\M\T'); + + // Return 304 if asset not modified + try { + $clientLastModified = $request->getHeader('If-Modified-Since')[0] ?? false; + if ($lastModified === $clientLastModified) { + return $response->withStatus(304); + } + } catch (\Exception $e) { + // Fallback to regular response + } + + $response->getBody()->write($assetLoader->getContent()); + + return $response->withHeader('Content-Type', $assetLoader->getType()) ->withHeader('Content-Length', $assetLoader->getLength()) - ->write($assetLoader->getContent()); + ->withHeader('Cache-Control', 'no-cache') + ->withHeader('Last-Modified', $lastModified); } } diff --git a/tests/ServeAsset/SlimServeAssetTest.php b/tests/ServeAsset/SlimServeAssetTest.php index 8d00b4a..f7fecf4 100644 --- a/tests/ServeAsset/SlimServeAssetTest.php +++ b/tests/ServeAsset/SlimServeAssetTest.php @@ -110,9 +110,7 @@ public function testAssetMatchesExpectations(SlimServeAsset $controller) $response = new Response(); // Invoke controller method. - $response = $controller->serveAsset($request, $response, [ - 'url' => 'allowed.txt', - ]); + $response = $controller->serveAsset($request, $response, ['url' => 'allowed.txt']); // Assert 200 response $this->assertSame($response->getStatusCode(), 200); @@ -122,10 +120,22 @@ public function testAssetMatchesExpectations(SlimServeAsset $controller) // Assert correct MIME $this->assertSame($response->getHeader('Content-Type'), ['text/plain']); + + // Asset last-modified set + $this->assertStringEndsWith('GMT', $response->getHeader('Last-Modified')[0] ?? false); + + // Last modified support + $request = Request::createFromEnvironment($environment) + ->withHeader('If-Modified-Since', $response->getHeader('Last-Modified')[0]); + $response = new Response(); + $response = $controller->serveAsset($request, $response, ['url' => 'allowed.txt']); + + // Assert 304 response + $this->assertSame($response->getStatusCode(), 304); } /** - * Test with existent asset. + * Test with existent asset of unknown type. * * @param SlimServeAsset $controller *