From 1cedd805ed08600e87bf8a1a37f8d11ac38c9630 Mon Sep 17 00:00:00 2001 From: Andrey Lushnikov Date: Tue, 23 Aug 2022 10:39:59 -0700 Subject: [PATCH] chore: a nicer message to urge updating docker image with Playwright (#16758) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will result in the following message: ``` root@docker-desktop:/playwright# node a.mjs node:internal/process/esm_loader:94 internalBinding('errors').triggerUncaughtException( ^ browserType.launch: Executable doesn't exist at /ms-playwright/chromium-1021/chrome-linux/chrome ╔══════════════════════════════════════════════════════════════════════╗ ║ Looks like Playwright Test or Playwright was just updated to 1.26.0. ║ ║ Please update docker image as well. ║ ║ - current: mcr.microsoft.com/playwright:v1.23.0-focal ║ ║ - required: mcr.microsoft.com/playwright:v1.26.0-focal ║ ║ ║ ║ <3 Playwright Team ║ ╚══════════════════════════════════════════════════════════════════════╝ at file:///playwright/a.mjs:3:43 { name: 'Error' } ``` Fixes #15483 --- .../src/server/registry/dependencies.ts | 28 +++++++++++++------ .../src/server/registry/index.ts | 14 ++++++++-- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/packages/playwright-core/src/server/registry/dependencies.ts b/packages/playwright-core/src/server/registry/dependencies.ts index f27539872b..7b96303661 100644 --- a/packages/playwright-core/src/server/registry/dependencies.ts +++ b/packages/playwright-core/src/server/registry/dependencies.ts @@ -31,18 +31,28 @@ 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'); + await fs.promises.writeFile(dockerVersionFilePath, JSON.stringify(dockerVersion(dockerImageNameTemplate), null, 2), 'utf8'); // Make sure version file is globally accessible. await fs.promises.chmod(dockerVersionFilePath, 0o777); } -async function readDockerVersion(): Promise { - return await fs.promises.readFile(dockerVersionFilePath, 'utf8') - .then(text => JSON.parse(text)) - .catch(e => null); +export function dockerVersion(dockerImageNameTemplate: string): { driverVersion: string, dockerImageName: string } { + return { + driverVersion: packageJSON.version, + dockerImageName: dockerImageNameTemplate.replace('%version%', packageJSON.version), + }; +} + +export function readDockerVersionSync(): null | { driverVersion: string, dockerImageName: string, dockerImageNameTemplate: string } { + try { + const data = JSON.parse(fs.readFileSync(dockerVersionFilePath, 'utf8')); + return { + ...data, + dockerImageNameTemplate: data.dockerImageName.replace(data.driverVersion, '%version%'), + }; + } catch (e) { + return null; + } } const checkExecutable = (filePath: string) => fs.promises.access(filePath, fs.constants.X_OK).then(() => true).catch(e => false); @@ -206,7 +216,7 @@ export async function validateDependenciesLinux(sdkLanguage: string, linuxLddDir } const maybeSudo = (process.getuid() !== 0) && os.platform() !== 'win32' ? 'sudo ' : ''; - const dockerInfo = await readDockerVersion(); + const dockerInfo = readDockerVersionSync(); const errorLines = [ `Host system is missing dependencies to run browsers.`, ]; diff --git a/packages/playwright-core/src/server/registry/index.ts b/packages/playwright-core/src/server/registry/index.ts index cdc6de680d..599df59ff6 100644 --- a/packages/playwright-core/src/server/registry/index.ts +++ b/packages/playwright-core/src/server/registry/index.ts @@ -28,7 +28,7 @@ import { removeFolders, existsAsync, canAccessFile } from '../../utils/fileUtils import { hostPlatform } from '../../utils/hostPlatform'; import { spawnAsync } from '../../utils/spawnAsync'; import type { DependencyGroup } from './dependencies'; -import { transformCommandsForRoot } from './dependencies'; +import { transformCommandsForRoot, dockerVersion, readDockerVersionSync } from './dependencies'; import { installDependenciesLinux, installDependenciesWindows, validateDependenciesLinux, validateDependenciesWindows } from './dependencies'; import { downloadBrowserWithProgressBar, logPolitely } from './browserFetcher'; export { writeDockerVersion } from './dependencies'; @@ -341,7 +341,17 @@ export class Registry { throw new Error(`${name} is not supported on ${hostPlatform}`); const installCommand = buildPlaywrightCLICommand(sdkLanguage, `install${installByDefault ? '' : ' ' + name}`); if (!canAccessFile(e)) { - const prettyMessage = [ + const currentDockerVersion = readDockerVersionSync(); + const preferredDockerVersion = currentDockerVersion ? dockerVersion(currentDockerVersion.dockerImageNameTemplate) : null; + const isOutdatedDockerImage = currentDockerVersion && preferredDockerVersion && currentDockerVersion.dockerImageName !== preferredDockerVersion.dockerImageName; + const prettyMessage = isOutdatedDockerImage ? [ + `Looks like ${sdkLanguage === 'javascript' ? 'Playwright Test or ' : ''}Playwright was just updated to ${preferredDockerVersion.driverVersion}.`, + `Please update docker image as well.`, + `- current: ${currentDockerVersion.dockerImageName}`, + `- required: ${preferredDockerVersion.dockerImageName}`, + ``, + `<3 Playwright Team`, + ].join('\n') : [ `Looks like ${sdkLanguage === 'javascript' ? 'Playwright Test or ' : ''}Playwright was just installed or updated.`, `Please run the following command to download new browser${installByDefault ? 's' : ''}:`, ``,