Skip to content
Merged
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
65 changes: 65 additions & 0 deletions .github/workflows/Nightly.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: "Nightly"

on:
schedule:
- cron: "27 3 * * *"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false

jobs:
descriptors:
name: "Device descriptors"
runs-on: ubuntu-latest
steps:
- name: "Git: checkout"
uses: actions/checkout@v4

- name: "PHP: setup 8.4"
uses: shivammathur/setup-php@v2
with:
php-version: "8.4"
coverage: none

- name: "Node: setup"
uses: actions/setup-node@v4
with:
node-version: "20"

- name: "Playwright: resolve latest stable"
id: resolve
run: |
version=$(npm view playwright version)
case "$version" in
[0-9]*.[0-9]*.[0-9]*) ;;
*) echo "::error::could not resolve the latest Playwright version"; exit 1 ;;
esac
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "Latest stable Playwright is $version"

- name: "Devices: verify latest stable"
env:
PLAYWRIGHT_VERSION: ${{ steps.resolve.outputs.version }}
run: php bin/check-devices.php --playwright-version="$PLAYWRIGHT_VERSION" | tee device-descriptors-report.md

- name: "Summary"
if: always()
env:
VERSION: ${{ steps.resolve.outputs.version }}
STATUS: ${{ job.status }}
run: |
if [ -f device-descriptors-report.md ]; then
cat device-descriptors-report.md >> "$GITHUB_STEP_SUMMARY"
echo >> "$GITHUB_STEP_SUMMARY"
fi
{
echo "| | |"
echo "|---|---|"
echo "| Latest Playwright | \`${VERSION:-unresolved}\` |"
echo "| Result | $STATUS |"
} >> "$GITHUB_STEP_SUMMARY"
30 changes: 26 additions & 4 deletions .github/workflows/update.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
name: "Update devices"

on:
# schedule:
# - cron: '0 2 * * *' # Every night at 02:00 UTC
workflow_dispatch: {}
workflow_dispatch:

jobs:
update:
Expand All @@ -24,7 +22,31 @@ jobs:
run: composer update --no-interaction --prefer-dist

- name: Update device descriptors
run: php bin/update-devices.php
run: php bin/update-devices.php | tee device-descriptors-report.md

- name: Update markdown files
run: php bin/update-docs.php

- name: Format generated files
run: vendor/bin/php-cs-fixer fix

- name: Validate generated changes
run: git diff --check

- name: Write summary
if: always()
run: |
if [ -f device-descriptors-report.md ]; then
cat device-descriptors-report.md >> "$GITHUB_STEP_SUMMARY"
fi

- name: Create update patch
run: git diff --binary > device-descriptors.patch

- name: Upload update patch
uses: actions/upload-artifact@v4
with:
name: device-descriptors-update
path: device-descriptors.patch
if-no-files-found: error
retention-days: 7
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/.phpunit.cache/
/vendor/
/data/deviceDescriptorsSource.json
/.php-cs-fixer.cache
/composer.lock
/phpstan.neon
Expand Down
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ Use `DeviceRegistry::has()` to check a name and `DeviceRegistry::all()` to retri

The generated [device catalog](docs/DEVICES.md) lists every available descriptor and its browser, screen, viewport, scale, mobile, and touch values.

Each catalog is generated from an explicit stable Playwright release. The source version is recorded in [`data/playwright-version.txt`](data/playwright-version.txt); generation never follows Playwright's moving `main` branch.

This package follows SemVer independently of Playwright. A catalog update is released as a new minor version because it changes the public descriptor data; matching Playwright and package version numbers is not implied.

Device descriptors emulate browser-visible properties. They do not reproduce physical hardware, operating-system UI, network conditions, or device performance.

## Documentation
Expand All @@ -95,6 +99,24 @@ vendor/bin/phpstan analyse
vendor/bin/phpunit
```

To refresh the catalog for a stable Playwright release:

```bash
php bin/update-devices.php
php bin/update-docs.php
vendor/bin/php-cs-fixer fix
```

Verify the committed catalog without modifying it:

```bash
php bin/check-devices.php
```

Both commands resolve the latest stable Playwright version from npm. Pass `--playwright-version=1.63.0` only when reproducing a specific historical snapshot.

The nightly workflow runs the check automatically. It fails when the recorded source version is behind or when the committed catalog does not match its recorded release.

## License

Playwright PHP Devices is released under the [MIT License](LICENSE).
60 changes: 60 additions & 0 deletions bin/check-devices.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

/*
* This file is part of the community-maintained Playwright PHP project.
* It is not affiliated with or endorsed by Microsoft.
*
* (c) 2025-Present - Playwright PHP <https://github.com/playwright-php>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

require_once __DIR__.'/update-devices-functions.php';

use function Playwright\Device\Update\commandArguments;
use function Playwright\Device\Update\compareDeviceCatalogs;
use function Playwright\Device\Update\downloadDescriptors;
use function Playwright\Device\Update\formatDeviceCatalogDiff;
use function Playwright\Device\Update\latestPlaywrightVersion;
use function Playwright\Device\Update\loadDeviceCatalog;
use function Playwright\Device\Update\normalizeDevices;
use function Playwright\Device\Update\parsePlaywrightVersion;
use function Playwright\Device\Update\readRecordedPlaywrightVersion;
use function Playwright\Device\Update\sourceUrl;

$rootDir = dirname(__DIR__);
$devicesPath = $rootDir.'/data/devices.php';
$versionPath = $rootDir.'/data/playwright-version.txt';

try {
$arguments = commandArguments($_SERVER['argv'] ?? null);
$recordedVersion = readRecordedPlaywrightVersion($versionPath);
$expectedVersion = [] === $arguments ? latestPlaywrightVersion() : parsePlaywrightVersion($arguments);
$currentDevices = loadDeviceCatalog($devicesPath);

$json = downloadDescriptors(sourceUrl($expectedVersion));
$decoded = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
if (!is_array($decoded)) {
throw new UnexpectedValueException('Playwright descriptors must decode to an object.');
}

$expectedDevices = normalizeDevices($decoded);
$diff = compareDeviceCatalogs($currentDevices, $expectedDevices);
fwrite(STDOUT, formatDeviceCatalogDiff($diff, $recordedVersion, $expectedVersion));

if ($recordedVersion !== $expectedVersion || $currentDevices !== $expectedDevices) {
$updateCommand = [] === $arguments
? 'php bin/update-devices.php'
: sprintf('php bin/update-devices.php --playwright-version=%s', $expectedVersion);

throw new RuntimeException('Device descriptors are out of date. Run: '.$updateCommand);
}

fwrite(STDOUT, sprintf('Device descriptors are up to date with Playwright v%s.'.PHP_EOL, $expectedVersion));
} catch (Throwable $e) {
fwrite(STDERR, 'Error: '.$e->getMessage().PHP_EOL);
exit(1);
}
Loading
Loading