mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
feat: detect docker version and Playwright version mismatch (#12806)
This patch prints a friendly instructions in case Docker image version
mismatches Playwright version and there are missing browser
dependencies.
With this patch, Playwright will yield the following error:
```
root@f0774d2b2097:~# node a.mjs
node:internal/process/promises:279
triggerUncaughtException(err, true /* fromPromise */);
^
browserType.launch:
╔════════════════════════════════════════════════════════════════════════════════════════════╗
║ Host system is missing dependencies to run browsers. ║
║ This is most likely due to docker image version not matching Playwright version: ║
║ - Playwright: 1.22.0 ║
║ - Docker: 1.21.0 ║
║ ║
║ Either: ║
║ - (recommended) use docker image "mcr.microsoft.com/playwright:v1.22.0-focal" ║
║ - (alternative 1) run the following command inside docker to install missing dependencies: ║
║ ║
║ npx playwright install-deps ║
║ ║
║ - (alternative 2) use Aptitude inside docker: ║
║ ║
║ apt-get install libgbm1 ║
║ ║
║ <3 Playwright Team ║
╚════════════════════════════════════════════════════════════════════════════════════════════╝
at file:///root/a.mjs:3:10 {
name: 'Error'
}```
Fixes #12796
Co-authored-by: Dmitry Gozman <dgozman@gmail.com>
This commit is contained in:
parent
6b81e76c2b
commit
4ab4c0bda1
@ -33,6 +33,7 @@ import { BrowserContextOptions, LaunchOptions } from '../client/types';
|
||||
import { spawn } from 'child_process';
|
||||
import { registry, Executable } from '../utils/registry';
|
||||
import { spawnAsync, getPlaywrightVersion } from '../utils/utils';
|
||||
import { writeDockerVersion } from '../utils/dependencies';
|
||||
import { launchGridAgent } from '../grid/gridAgent';
|
||||
import { GridServer, GridFactory } from '../grid/gridServer';
|
||||
|
||||
@ -42,6 +43,14 @@ program
|
||||
.version('Version ' + (process.env.PW_CLI_DISPLAY_VERSION || packageJSON.version))
|
||||
.name(buildBasePlaywrightCLICommand(process.env.PW_LANG_NAME));
|
||||
|
||||
program
|
||||
.command('mark-docker-image > [args...]', { hidden: true })
|
||||
.description('mark docker image')
|
||||
.allowUnknownOption(true)
|
||||
.action(function(dockerImageNameTemplate) {
|
||||
writeDockerVersion(dockerImageNameTemplate);
|
||||
});
|
||||
|
||||
commandWithOpenOptions('open [url]', 'open page in browser specified via -b, --browser', [])
|
||||
.action(function(url, options) {
|
||||
open(options, url, language()).catch(logErrorAndExit);
|
||||
|
||||
@ -24,6 +24,24 @@ import { deps } from './nativeDeps';
|
||||
import { getUbuntuVersion } from './ubuntuVersion';
|
||||
|
||||
const BIN_DIRECTORY = path.join(__dirname, '..', '..', 'bin');
|
||||
const packageJSON = require('../../package.json');
|
||||
|
||||
const dockerVersionFilePath = '/ms-playwright/.docker-info';
|
||||
export async function writeDockerVersion(dockerImageNameTemplate: string) {
|
||||
await fs.promises.mkdir(path.dirname(dockerVersionFilePath), { recursive: true });
|
||||
await fs.promises.writeFile(dockerVersionFilePath, JSON.stringify({
|
||||
driverVersion: packageJSON.version,
|
||||
dockerImageName: dockerImageNameTemplate.replace('%version%', packageJSON.version),
|
||||
}, null, 2), 'utf8');
|
||||
// Make sure version file is globally accessible.
|
||||
await fs.promises.chmod(dockerVersionFilePath, 0o777);
|
||||
}
|
||||
|
||||
async function readDockerVersion(): Promise<null | { driverVersion: string, dockerImageName: string }> {
|
||||
return await fs.promises.readFile(dockerVersionFilePath, 'utf8')
|
||||
.then(text => JSON.parse(text))
|
||||
.catch(e => null);
|
||||
}
|
||||
|
||||
const checkExecutable = (filePath: string) => fs.promises.access(filePath, fs.constants.X_OK).then(() => true).catch(e => false);
|
||||
|
||||
@ -183,11 +201,36 @@ export async function validateDependenciesLinux(sdkLanguage: string, linuxLddDir
|
||||
}
|
||||
|
||||
const maybeSudo = (process.getuid() !== 0) && os.platform() !== 'win32' ? 'sudo ' : '';
|
||||
const dockerInfo = await readDockerVersion();
|
||||
const errorLines = [
|
||||
`Host system is missing dependencies to run browsers.`,
|
||||
];
|
||||
if (missingPackages.size && !missingDeps.size) {
|
||||
// Happy path: known dependencies are missing for browsers.
|
||||
// Ignore patch versions when comparing docker container version and Playwright version:
|
||||
// we **NEVER** roll browsers in patch releases, so native dependencies do not change.
|
||||
if (dockerInfo && !dockerInfo.driverVersion.startsWith(utils.getPlaywrightVersion(true /* majorMinorOnly */) + '.')) {
|
||||
// We are running in a docker container with unmatching version.
|
||||
// In this case, we know how to install dependencies in it.
|
||||
const pwVersion = utils.getPlaywrightVersion();
|
||||
const requiredDockerImage = dockerInfo.dockerImageName.replace(dockerInfo.driverVersion, pwVersion);
|
||||
errorLines.push(...[
|
||||
`This is most likely due to docker image version not matching Playwright version:`,
|
||||
`- Playwright: ${pwVersion}`,
|
||||
`- Docker: ${dockerInfo.driverVersion}`,
|
||||
``,
|
||||
`Either:`,
|
||||
`- (recommended) use docker image "${requiredDockerImage}"`,
|
||||
`- (alternative 1) run the following command inside docker to install missing dependencies:`,
|
||||
``,
|
||||
` ${maybeSudo}${buildPlaywrightCLICommand(sdkLanguage, 'install-deps')}`,
|
||||
``,
|
||||
`- (alternative 2) use Aptitude inside docker:`,
|
||||
``,
|
||||
` ${maybeSudo}apt-get install ${[...missingPackages].join('\\\n ')}`,
|
||||
``,
|
||||
`<3 Playwright Team`,
|
||||
]);
|
||||
} else if (missingPackages.size && !missingDeps.size) {
|
||||
// Only known dependencies are missing for browsers.
|
||||
// Suggest installation with a Playwright CLI.
|
||||
errorLines.push(...[
|
||||
`Please install them with the following command:`,
|
||||
|
||||
@ -2,6 +2,7 @@ FROM ubuntu:bionic
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG TZ=America/Los_Angeles
|
||||
ARG DOCKER_IMAGE_NAME_TEMPLATE="mcr.microsoft.com/playwright:v%version%-bionic"
|
||||
|
||||
# === INSTALL Node.js ===
|
||||
|
||||
@ -34,7 +35,9 @@ RUN mkdir /ms-playwright && \
|
||||
mkdir /ms-playwright-agent && \
|
||||
cd /ms-playwright-agent && npm init -y && \
|
||||
npm i /tmp/playwright-core.tar.gz && \
|
||||
npx playwright mark-docker-image "${DOCKER_IMAGE_NAME_TEMPLATE}" && \
|
||||
npx playwright install --with-deps && rm -rf /var/lib/apt/lists/* && \
|
||||
rm /tmp/playwright-core.tar.gz && \
|
||||
rm -rf /ms-playwright-agent && \
|
||||
chmod -R 777 /ms-playwright
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ FROM ubuntu:focal
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG TZ=America/Los_Angeles
|
||||
ARG DOCKER_IMAGE_NAME_TEMPLATE="mcr.microsoft.com/playwright:v%version%-focal"
|
||||
|
||||
# === INSTALL Node.js ===
|
||||
|
||||
@ -34,6 +35,7 @@ RUN mkdir /ms-playwright && \
|
||||
mkdir /ms-playwright-agent && \
|
||||
cd /ms-playwright-agent && npm init -y && \
|
||||
npm i /tmp/playwright-core.tar.gz && \
|
||||
npx playwright mark-docker-image "${DOCKER_IMAGE_NAME_TEMPLATE}" && \
|
||||
npx playwright install --with-deps && rm -rf /var/lib/apt/lists/* && \
|
||||
rm /tmp/playwright-core.tar.gz && \
|
||||
rm -rf /ms-playwright-agent && \
|
||||
|
||||
@ -7,7 +7,7 @@ trap "cd $(pwd -P)" EXIT
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
MCR_IMAGE_NAME="playwright"
|
||||
PW_VERSION=$(node -e 'console.log(require("../../package.json").version)')
|
||||
PW_VERSION=$(node ../../utils/workspace.js --get-version)
|
||||
|
||||
RELEASE_CHANNEL="$1"
|
||||
if [[ "${RELEASE_CHANNEL}" == "stable" ]]; then
|
||||
|
||||
@ -56,6 +56,11 @@ class Workspace {
|
||||
return this._packages;
|
||||
}
|
||||
|
||||
async version() {
|
||||
const workspacePackageJSON = await readJSON(path.join(this._rootDir, 'package.json'));
|
||||
return workspacePackageJSON.version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} version
|
||||
*/
|
||||
@ -210,6 +215,9 @@ async function parseCLI() {
|
||||
console.log(pkg.path);
|
||||
}
|
||||
},
|
||||
'--get-version': async (version) => {
|
||||
console.log(await workspace.version());
|
||||
},
|
||||
'--set-version': async (version) => {
|
||||
if (!version)
|
||||
die('ERROR: Please specify version! e.g. --set-version 1.99.2');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user