feat: install chrome-beta via cli (#6831)

This patch starts introduces `npx playwright install chrome-beta`
command and switches our Chrome Beta tests to it.
This commit is contained in:
Andrey Lushnikov 2021-06-01 18:26:12 -07:00 committed by GitHub
parent 3c3a7f9293
commit cb4adb1446
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 73 additions and 37 deletions

View File

@ -472,7 +472,6 @@ jobs:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- run: ./utils/install-chrome-beta/reinstall_linux.sh
- uses: actions/setup-node@v2
with:
node-version: 12
@ -481,7 +480,7 @@ jobs:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: node lib/cli/cli install-deps chromium
- run: node lib/cli/cli install ffmpeg
- run: node lib/cli/cli install chrome-beta
# XVFB-RUN merges both STDOUT and STDERR, whereas we need only STDERR
# Wrap `npm run` in a subshell to redirect STDERR to file.
- run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- bash -c "npm run ctest"
@ -500,8 +499,6 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Install Chrome Beta
run: pwsh -command ".\$GITHUB_WORKSPACE\utils\install-chrome-beta\reinstall_win.ps1"
- name: Install Media Pack
shell: powershell
run: Install-WindowsFeature Server-Media-Foundation
@ -512,7 +509,7 @@ jobs:
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: node lib/cli/cli install ffmpeg
- run: node lib/cli/cli install chrome-beta
- run: npm run ctest
shell: bash
env:
@ -531,7 +528,6 @@ jobs:
runs-on: macos-10.15
steps:
- uses: actions/checkout@v2
- run: ./utils/install-chrome-beta/reinstall_mac.sh
- uses: actions/setup-node@v2
with:
node-version: 12
@ -539,7 +535,7 @@ jobs:
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- run: npm run build
- run: node lib/cli/cli install ffmpeg
- run: node lib/cli/cli install chrome-beta
- run: npm run ctest
env:
PWTEST_CHANNEL: chrome-beta

View File

@ -28,7 +28,7 @@ const cpAsync = util.promisify(ncp);
const SCRIPT_NAME = path.basename(__filename);
const ROOT_PATH = path.join(__dirname, '..');
const PLAYWRIGHT_CORE_FILES = ['bin/PrintDeps.exe', 'lib', 'types', 'NOTICE', 'LICENSE', 'bin/android-driver.apk', 'bin/android-driver-target.apk'];
const PLAYWRIGHT_CORE_FILES = ['bin', 'lib', 'types', 'NOTICE', 'LICENSE', ];
const PACKAGES = {
'playwright': {

View File

@ -34,7 +34,13 @@ import { BrowserType } from '../client/browserType';
import { BrowserContextOptions, LaunchOptions } from '../client/types';
import { spawn } from 'child_process';
import { installDeps } from '../install/installDeps';
import { allBrowserNames } from '../utils/registry';
import { allBrowserNames, BrowserName } from '../utils/registry';
import * as utils from '../utils/utils';
const SCRIPTS_DIRECTORY = path.join(__dirname, '..', '..', 'bin');
type BrowserChannel = 'chrome-beta';
const allBrowserChannels: Set<BrowserChannel> = new Set(['chrome-beta']);
program
.version('Version ' + require('../../package.json').version)
@ -86,24 +92,56 @@ program
program
.command('install [browserType...]')
.description('ensure browsers necessary for this version of Playwright are installed')
.action(async function(browserTypes) {
.action(async function(args) {
try {
const allBrowsers = new Set(allBrowserNames);
for (const browserType of browserTypes) {
if (!allBrowsers.has(browserType)) {
console.log(`Invalid browser name: '${browserType}'. Expecting one of: ${allBrowserNames.map(name => `'${name}'`).join(', ')}`);
process.exit(1);
}
// Install default browsers when invoked without arguments.
if (!args.length) {
await installBrowsers();
return;
}
const browserNames: Set<BrowserName> = new Set(args.filter((browser: any) => allBrowserNames.has(browser)));
const browserChannels: Set<BrowserChannel> = new Set(args.filter((browser: any) => allBrowserChannels.has(browser)));
const faultyArguments: string[] = args.filter((browser: any) => !browserNames.has(browser) && !browserChannels.has(browser));
if (faultyArguments.length) {
console.log(`Invalid installation targets: ${faultyArguments.map(name => `'${name}'`).join(', ')}. Expecting one of: ${[...allBrowserNames, ...allBrowserChannels].map(name => `'${name}'`).join(', ')}`);
process.exit(1);
}
if (browserNames.has('chromium') || browserChannels.has('chrome-beta'))
browserNames.add('ffmpeg');
if (browserNames.size)
await installBrowsers([...browserNames]);
for (const browserChannel of browserChannels) {
if (browserChannel === 'chrome-beta')
await installChromeBeta();
else
throw new Error(`ERROR: no installation instructions for '${browserChannel}' channel.`);
}
if (browserTypes.length && browserTypes.includes('chromium'))
browserTypes = browserTypes.concat('ffmpeg');
await installBrowsers(browserTypes.length ? browserTypes : undefined);
} catch (e) {
console.log(`Failed to install browsers\n${e}`);
process.exit(1);
}
});
async function installChromeBeta() {
const platform: string = os.platform();
const shell: (string|undefined) = {
'linux': 'bash',
'darwin': 'bash',
'win32': 'powershell.exe',
}[platform];
const scriptName: (string|undefined) = {
'linux': 'reinstall_chrome_beta_linux.sh',
'darwin': 'reinstall_chrome_beta_mac.sh',
'win32': 'reinstall_chrome_beta_win.ps1',
}[platform];
if (!shell || !scriptName)
throw new Error(`Cannot install chrome-beta on ${platform}`);
const {code} = await utils.spawnAsync(shell, [path.join(SCRIPTS_DIRECTORY, scriptName)], { cwd: SCRIPTS_DIRECTORY, stdio: 'inherit' });
if (code !== 0)
throw new Error('Failed to install chrome-beta');
}
program
.command('install-deps [browserType...]')
.description('install dependencies necessary to run browsers (will ask for sudo permissions)')

View File

@ -17,7 +17,6 @@ import fs from 'fs';
import * as util from 'util';
import path from 'path';
import * as os from 'os';
import { spawn } from 'child_process';
import { getUbuntuVersion } from '../utils/ubuntuVersion';
import * as registry from '../utils/registry';
import * as utils from '../utils/utils';
@ -218,7 +217,7 @@ async function missingFileDependenciesWindows(filePath: string): Promise<Array<s
return [];
const dirname = path.dirname(filePath);
const {stdout, code} = await spawnAsync(executable, [filePath], {
const {stdout, code} = await utils.spawnAsync(executable, [filePath], {
cwd: dirname,
env: {
...process.env,
@ -236,7 +235,7 @@ async function missingFileDependencies(filePath: string, extraLDPaths: string[])
let LD_LIBRARY_PATH = extraLDPaths.join(':');
if (process.env.LD_LIBRARY_PATH)
LD_LIBRARY_PATH = `${process.env.LD_LIBRARY_PATH}:${LD_LIBRARY_PATH}`;
const {stdout, code} = await spawnAsync('ldd', [filePath], {
const {stdout, code} = await utils.spawnAsync('ldd', [filePath], {
cwd: dirname,
env: {
...process.env,
@ -256,26 +255,13 @@ async function missingDLOPENLibraries(browserName: registry.BrowserName): Promis
// NOTE: Using full-qualified path to `ldconfig` since `/sbin` is not part of the
// default PATH in CRON.
// @see https://github.com/microsoft/playwright/issues/3397
const {stdout, code, error} = await spawnAsync('/sbin/ldconfig', ['-p'], {});
const {stdout, code, error} = await utils.spawnAsync('/sbin/ldconfig', ['-p'], {});
if (code !== 0 || error)
return [];
const isLibraryAvailable = (library: string) => stdout.toLowerCase().includes(library.toLowerCase());
return libraries.filter(library => !isLibraryAvailable(library));
}
export function spawnAsync(cmd: string, args: string[], options: any): Promise<{stdout: string, stderr: string, code: number, error?: Error}> {
const process = spawn(cmd, args, options);
return new Promise(resolve => {
let stdout = '';
let stderr = '';
process.stdout.on('data', data => stdout += data);
process.stderr.on('data', data => stderr += data);
process.on('close', code => resolve({stdout, stderr, code}));
process.on('error', error => resolve({stdout, stderr, code: 0, error}));
});
}
// This list is generted with the following program:
// ./utils/linux-browser-dependencies/run.sh ubuntu:18.04
const LIBRARY_TO_PACKAGE_NAME_UBUNTU_18_04: { [s: string]: string} = {

View File

@ -23,7 +23,7 @@ import { getUbuntuVersionSync } from './ubuntuVersion';
import { assert, getFromENV } from './utils';
export type BrowserName = 'chromium'|'webkit'|'firefox'|'firefox-stable'|'ffmpeg'|'webkit-technology-preview';
export const allBrowserNames: BrowserName[] = ['chromium', 'webkit', 'firefox', 'ffmpeg', 'webkit-technology-preview', 'firefox-stable'];
export const allBrowserNames: Set<BrowserName> = new Set(['chromium', 'webkit', 'firefox', 'ffmpeg', 'webkit-technology-preview', 'firefox-stable']);
const PACKAGE_PATH = path.join(__dirname, '..', '..');

View File

@ -19,9 +19,25 @@ import fs from 'fs';
import removeFolder from 'rimraf';
import * as util from 'util';
import * as crypto from 'crypto';
import { spawn } from 'child_process';
const mkdirAsync = util.promisify(fs.mkdir.bind(fs));
export function spawnAsync(cmd: string, args: string[], options: any): Promise<{stdout: string, stderr: string, code: number, error?: Error}> {
const process = spawn(cmd, args, options);
return new Promise(resolve => {
let stdout = '';
let stderr = '';
if (process.stdout)
process.stdout.on('data', data => stdout += data);
if (process.stderr)
process.stderr.on('data', data => stderr += data);
process.on('close', code => resolve({stdout, stderr, code}));
process.on('error', error => resolve({stdout, stderr, code: 0, error}));
});
}
// See https://joel.tools/microtasks/
export function makeWaitForNextTask() {
// As of Mar 2021, Electorn v12 doesn't create new task with `setImmediate` despite