1
0
mirror of synced 2026-07-18 06:15:06 +00:00

Compare commits

..

10 Commits

Author SHA1 Message Date
dependabot[bot] 32cf6cd18e chore(deps): bump the actions group with 2 updates (#1945) 2026-07-08 16:59:35 -07:00
Simon Knott e5135db82c chore: Upgrade EsrpRelease task version to 11 (#1943) 2026-06-30 12:04:36 +02:00
Yury Semikhatsky 6234e06280 feat(docker): pre-extract the driver in images to avoid /tmp unpacking (#1938) 2026-06-29 11:31:15 -07:00
Yury Semikhatsky 20e4edd73c chore: roll driver to 1.61.1 (#1941) 2026-06-29 11:06:07 -07:00
Yury Semikhatsky d2d29d446d feat(driver): bundle playwright-core in driver, keep only Node.js in driver-bundle (#1936) 2026-06-19 09:54:36 -07:00
Yury Semikhatsky 43d2601be8 fix(fetch): serialize LocalDate in post data (#1934) 2026-06-18 10:20:37 -07:00
Yury Semikhatsky ace7a1241f fix(driver-bundle): exclude driver binaries from sources JAR (#1933) 2026-06-16 09:06:07 -07:00
Yury Semikhatsky fddd7c3708 feat(docker): add Ubuntu 26.04 (Resolute Raccoon) image (#1932) 2026-06-15 14:50:36 -07:00
Yury Semikhatsky 423cbf4cc7 chore: roll driver to 1.61.0-beta-1781285686000 (#1929) 2026-06-14 10:53:00 -07:00
Yury Semikhatsky e3f2f6fa5b fix(docker): assemble driver on the host for docker builds (#1930) 2026-06-12 14:09:31 -07:00
24 changed files with 311 additions and 87 deletions
+1 -1
View File
@@ -75,7 +75,7 @@ extends:
targetPath: $(Build.ArtifactStagingDirectory)/esrp-build
steps:
- checkout: none
- task: EsrpRelease@9
- task: EsrpRelease@11
inputs:
connectedservicename: 'Playwright-ESRP-PME'
usemanagedidentity: true
+2 -2
View File
@@ -13,7 +13,7 @@ jobs:
environment: Docker
if: github.repository == 'microsoft/playwright-java'
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Azure login
uses: azure/login@v3
with:
@@ -26,5 +26,5 @@ jobs:
uses: docker/setup-qemu-action@v4
with:
platforms: arm64
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- run: ./utils/docker/publish_docker.sh stable
+3 -3
View File
@@ -28,7 +28,7 @@ jobs:
browser: webkit
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Set up JDK 1.8
uses: actions/setup-java@v5
with:
@@ -73,7 +73,7 @@ jobs:
browser-channel: msedge
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Install Media Pack
if: matrix.os == 'windows-latest'
shell: powershell
@@ -108,7 +108,7 @@ jobs:
browser: [chromium, firefox, webkit]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Set up JDK 21
uses: actions/setup-java@v5
with:
+2 -2
View File
@@ -13,9 +13,9 @@ jobs:
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Cache Maven packages
uses: actions/cache@v5
uses: actions/cache@v6
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
+2 -2
View File
@@ -26,7 +26,7 @@ jobs:
strategy:
fail-fast: false
matrix:
flavor: [jammy, noble]
flavor: [jammy, noble, resolute]
runs-on: [ubuntu-24.04, ubuntu-24.04-arm]
include:
- runs-on: ubuntu-24.04
@@ -34,7 +34,7 @@ jobs:
- runs-on: ubuntu-24.04-arm
arch: arm64
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Build Docker image
run: |
bash utils/docker/build.sh --${{ matrix.arch }} ${{ matrix.flavor }} playwright-java:localbuild-${{ matrix.flavor }}
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Download drivers
run: scripts/download_driver.sh
- name: Regenerate APIs
+1 -1
View File
@@ -20,7 +20,7 @@ git clone https://github.com/microsoft/playwright-java
cd playwright-java
```
2. Run the following script to download and assemble the Playwright driver for all platforms into `driver-bundle/src/main/resources/driver/` directory (browser binaries for Chromium, Firefox and WebKit will be automatically downloaded later on first Playwright run).
2. Run the following script to download and assemble the Playwright driver. The platform-independent `playwright-core` package is assembled once into `driver/src/main/resources/driver/package/`, and the Node.js binary for each platform into `driver-bundle/src/main/resources/driver/<platform>/` (browser binaries for Chromium, Firefox and WebKit will be automatically downloaded later on first Playwright run).
```bash
scripts/download_driver.sh
+16 -15
View File
@@ -10,22 +10,23 @@
</parent>
<artifactId>driver-bundle</artifactId>
<name>Playwright - Drivers For All Platforms</name>
<name>Playwright - Node.js For All Platforms</name>
<description>
This module includes Playwright driver and related utilities for all supported platforms.
It is intended to be used on the systems where Playwright driver is not preinstalled.
Node.js binaries for the Playwright driver on every supported platform. Can be excluded when
Node.js is preinstalled on the host (see PLAYWRIGHT_NODEJS_PATH).
</description>
<dependencies>
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>driver</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- The Node.js binaries for all platforms live in src/main/resources and must not
be packaged into the sources JAR (see issue #1913). -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<configuration>
<excludeResources>true</excludeResources>
</configuration>
</plugin>
</plugins>
</build>
</project>
+16 -1
View File
@@ -12,7 +12,8 @@
<artifactId>driver</artifactId>
<name>Playwright - Driver</name>
<description>
This module provides API for discovery and launching of Playwright driver.
API for launching the Playwright driver. Bundles the platform-independent playwright-core
package; the Node.js binary comes from the driver-bundle module or a preinstalled Node.js.
</description>
<dependencies>
@@ -21,4 +22,18 @@
<artifactId>junit-jupiter-engine</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- The playwright-core package lives in src/main/resources and must not be packaged
into the sources JAR (see issue #1913). -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<configuration>
<excludeResources>true</excludeResources>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -25,12 +25,14 @@ import static com.microsoft.playwright.impl.driver.DriverLogging.logWithTimestam
/**
* This class provides access to playwright-cli. It can be either preinstalled
* in the host system and its path is passed as a system property or it can be
* loaded from the driver-bundle module if that module is in the classpath.
* in the host system and its path is passed as a system property, or it can be
* loaded from the classpath: the platform-independent driver code ships in the
* driver module and the Node.js binary in the optional driver-bundle module.
*/
public abstract class Driver {
protected final Map<String, String> env = new LinkedHashMap<>(System.getenv());
public static final String PLAYWRIGHT_NODEJS_PATH = "PLAYWRIGHT_NODEJS_PATH";
public static final String PLAYWRIGHT_DRIVER_DIR = "PLAYWRIGHT_DRIVER_DIR";
private static Driver instance;
@@ -107,9 +109,12 @@ public abstract class Driver {
}
private static Driver newInstance() throws Exception {
String pathFromProperty = System.getProperty("playwright.cli.dir");
if (pathFromProperty != null) {
return new PreinstalledDriver(Paths.get(pathFromProperty));
String driverDir = System.getProperty("playwright.cli.dir");
if (driverDir == null) {
driverDir = System.getenv(PLAYWRIGHT_DRIVER_DIR);
}
if (driverDir != null) {
return new PreinstalledDriver(Paths.get(driverDir));
}
String driverImpl =
@@ -30,17 +30,11 @@ public class DriverJar extends Driver {
private static final String PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD = "PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD";
private static final String SELENIUM_REMOTE_URL = "SELENIUM_REMOTE_URL";
private final Path driverTempDir;
private final boolean deleteOnExit;
private Path preinstalledNodePath;
public DriverJar() throws IOException {
// Allow specifying custom path for the driver installation
// See https://github.com/microsoft/playwright-java/issues/728
String alternativeTmpdir = System.getProperty("playwright.driver.tmpdir");
String prefix = "playwright-java-";
driverTempDir = alternativeTmpdir == null
? Files.createTempDirectory(prefix)
: Files.createTempDirectory(Paths.get(alternativeTmpdir), prefix);
driverTempDir.toFile().deleteOnExit();
this(createTempDriverDir(), true);
String nodePath = System.getProperty("playwright.nodejs.path");
if (nodePath != null) {
preinstalledNodePath = Paths.get(nodePath);
@@ -51,6 +45,32 @@ public class DriverJar extends Driver {
logMessage("created DriverJar: " + driverTempDir);
}
private DriverJar(Path driverDir, boolean deleteOnExit) {
this.driverTempDir = driverDir;
this.deleteOnExit = deleteOnExit;
if (deleteOnExit) {
driverTempDir.toFile().deleteOnExit();
}
}
private static Path createTempDriverDir() throws IOException {
// Allow specifying custom path for the driver installation
// See https://github.com/microsoft/playwright-java/issues/728
String alternativeTmpdir = System.getProperty("playwright.driver.tmpdir");
String prefix = "playwright-java-";
return alternativeTmpdir == null
? Files.createTempDirectory(prefix)
: Files.createTempDirectory(Paths.get(alternativeTmpdir), prefix);
}
// Extracts the driver (playwright-core package and the Node.js binary for the current platform)
// into the given directory, persistently. Point playwright.cli.dir / PLAYWRIGHT_DRIVER_DIR at it
// to run without extracting to a temp directory on every launch. See issue #1268.
public static void installDriverTo(Path driverDir) throws IOException, URISyntaxException {
Files.createDirectories(driverDir);
new DriverJar(driverDir, false).extractDriverToTempDir();
}
@Override
protected void initialize(Boolean installBrowsers) throws Exception {
if (preinstalledNodePath == null && env.containsKey(PLAYWRIGHT_NODEJS_PATH)) {
@@ -119,7 +139,21 @@ public class DriverJar extends Driver {
}
void extractDriverToTempDir() throws URISyntaxException, IOException {
URI originalUri = getDriverResourceURI();
extractResourceToDir("driver/package", driverTempDir.resolve("package"));
if (preinstalledNodePath == null) {
String platformResource = "driver/" + platformDir();
if (DriverJar.class.getClassLoader().getResource(platformResource) == null) {
throw new RuntimeException("Failed to find the bundled Node.js for platform '" + platformDir()
+ "'. Add the com.microsoft.playwright:driver-bundle dependency, or set the "
+ PLAYWRIGHT_NODEJS_PATH + " environment variable (or the playwright.nodejs.path system "
+ "property) to point at a preinstalled Node.js.");
}
extractResourceToDir(platformResource, driverTempDir);
}
}
private void extractResourceToDir(String resourcePath, Path destDir) throws URISyntaxException, IOException {
URI originalUri = DriverJar.class.getClassLoader().getResource(resourcePath).toURI();
URI uri = maybeExtractNestedJar(originalUri);
// Create zip filesystem if loading from jar.
@@ -131,14 +165,8 @@ public class DriverJar extends Driver {
// See https://github.com/microsoft/playwright-java/issues/306
Path srcRootDefaultFs = Paths.get(srcRoot.toString());
Files.walk(srcRoot).forEach(fromPath -> {
if (preinstalledNodePath != null) {
String fileName = fromPath.getFileName().toString();
if ("node.exe".equals(fileName) || "node".equals(fileName)) {
return;
}
}
Path relative = srcRootDefaultFs.relativize(Paths.get(fromPath.toString()));
Path toPath = driverTempDir.resolve(relative.toString());
Path toPath = destDir.resolve(relative.toString());
try {
if (Files.isDirectory(fromPath)) {
Files.createDirectories(toPath);
@@ -148,7 +176,9 @@ public class DriverJar extends Driver {
toPath.toFile().setExecutable(true, true);
}
}
toPath.toFile().deleteOnExit();
if (deleteOnExit) {
toPath.toFile().deleteOnExit();
}
} catch (IOException e) {
throw new RuntimeException("Failed to extract driver from " + uri + ", full uri: " + originalUri, e);
}
@@ -171,7 +201,9 @@ public class DriverJar extends Driver {
Path fromPath = Paths.get(jarUri);
Path toPath = driverTempDir.resolve(fromPath.getFileName().toString());
Files.copy(fromPath, toPath);
toPath.toFile().deleteOnExit();
if (deleteOnExit) {
toPath.toFile().deleteOnExit();
}
return new URI("jar:" + toPath.toUri() + JAR_URL_SEPARATOR + parts[2]);
} catch (IOException e) {
throw new RuntimeException("Failed to extract driver's nested .jar from " + jarUri + "; full uri: " + uri, e);
+2
View File
@@ -0,0 +1,2 @@
driver/
local-driver/
@@ -17,9 +17,12 @@
package com.microsoft.playwright;
import com.microsoft.playwright.impl.driver.Driver;
import com.microsoft.playwright.impl.driver.jar.DriverJar;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import static java.util.Arrays.asList;
@@ -28,7 +31,13 @@ import static java.util.Arrays.asList;
* Use this class to launch playwright cli.
*/
public class CLI {
public static void main(String[] args) throws IOException, InterruptedException {
public static void main(String[] args) throws IOException, InterruptedException, URISyntaxException {
// Extract the driver into a fixed directory instead of running the playwright CLI. This is
// handled in Java because it must not require an already-extracted driver. See issue #1268.
if (args.length > 0 && "install-driver".equals(args[0])) {
installDriver(args);
return;
}
Driver driver = Driver.ensureDriverInstalled(Collections.emptyMap(), false);
ProcessBuilder pb = driver.createProcessBuilder();
pb.command().addAll(asList(args));
@@ -40,4 +49,17 @@ public class CLI {
Process process = pb.start();
System.exit(process.waitFor());
}
private static void installDriver(String[] args) throws IOException, URISyntaxException {
String dir = args.length > 1 ? args[1] : System.getenv(Driver.PLAYWRIGHT_DRIVER_DIR);
if (dir == null) {
System.err.println("Usage: install-driver <dir> (or set the " + Driver.PLAYWRIGHT_DRIVER_DIR
+ " environment variable)");
System.exit(1);
return;
}
Path driverDir = Paths.get(dir);
DriverJar.installDriverTo(driverDir);
System.out.println("Installed Playwright driver into " + driverDir.toAbsolutePath());
}
}
@@ -77,6 +77,7 @@ class Serialization {
static final Gson jsonDataSerializer = new GsonBuilder().disableHtmlEscaping()
.registerTypeAdapter(Date.class, new DateSerializer())
.registerTypeAdapter(LocalDate.class, new LocalDateSerializer())
.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer())
.registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeSerializer())
.serializeNulls().create();
@@ -571,6 +572,15 @@ class Serialization {
}
}
private static class LocalDateSerializer implements JsonSerializer<LocalDate> {
@Override
public JsonElement serialize(LocalDate src, Type typeOfSrc, JsonSerializationContext context) {
// LocalDate has no time or zone, so emit the ISO-8601 date (yyyy-MM-dd) as-is to
// avoid shifting the calendar date when converting through a time zone.
return new JsonPrimitive(src.toString());
}
}
private static class LocalDateTimeSerializer implements JsonSerializer<LocalDateTime> {
@Override
public JsonElement serialize(LocalDateTime src, Type typeOfSrc, JsonSerializationContext context) {
@@ -28,6 +28,7 @@ import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
@@ -533,6 +534,23 @@ public class TestBrowserContextFetch extends TestBase {
assertEquals("{\"date\":\"2024-07-10T18:15:30.000Z\"}", new String(body));
}
public static class LocalDateData {
public String name;
public LocalDate date;
}
@Test
void shouldSupportLocalDateInData() throws ExecutionException, InterruptedException {
APIRequestContext request = playwright.request().newContext();
LocalDateData testData = new LocalDateData();
testData.name = "foo";
testData.date = LocalDate.of(2022, 12, 23);
Future<Server.Request> serverRequest = server.futureRequest("/empty.html");
request.post(server.EMPTY_PAGE, RequestOptions.create().setData(testData));
byte[] body = serverRequest.get().postBody;
assertEquals("{\"name\":\"foo\",\"date\":\"2022-12-23\"}", new String(body));
}
@Test
void shouldSupportApplicationXWwwFormUrlencoded() throws ExecutionException, InterruptedException {
Future<Server.Request> req = server.futureRequest("/empty.html");
@@ -132,6 +132,30 @@ public class TestInstall {
}
@Test
void canInstallDriverToDirectoryAndReuseIt(@TempDir Path tmpDir) throws Exception {
Path driverDir = tmpDir.resolve("driver");
DriverJar.installDriverTo(driverDir);
// The directory is self-contained: the playwright-core package and the Node.js binary.
assertTrue(Files.exists(driverDir.resolve("package").resolve("cli.js")));
assertTrue(Files.exists(driverDir.resolve(isWindows() ? "node.exe" : "node")));
// Pointing playwright.cli.dir at it must reuse it as-is, without extracting to a temp directory.
System.setProperty("playwright.cli.dir", driverDir.toString());
Driver driver = Driver.createAndInstall(Collections.emptyMap(), false);
assertEquals(driverDir, driver.driverDir());
ProcessBuilder pb = driver.createProcessBuilder();
pb.command().add("--version");
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
Path out = tmpDir.resolve("out.txt");
pb.redirectOutput(out.toFile());
Process p = pb.start();
assertTrue(p.waitFor(1, TimeUnit.MINUTES), "Timed out waiting for version to be printed");
String stdout = new String(Files.readAllBytes(out), StandardCharsets.UTF_8);
assertTrue(stdout.contains("Version "), stdout);
}
private static String extractNodeJsToTemp() throws URISyntaxException, IOException {
DriverJar auxDriver = new DriverJar();
auxDriver.extractDriverToTempDir();
+1 -1
View File
@@ -1 +1 @@
1.61.0-beta-1781285686000
1.61.1
+31 -26
View File
@@ -9,9 +9,11 @@ cd "$(dirname $0)"
if [[ ($1 == '-h') || ($1 == '--help') ]]; then
echo ""
echo "This script downloads and assembles the Playwright driver for all platforms."
echo "Each driver is assembled from the 'playwright-core' npm package and the matching"
echo "Node.js binary from https://nodejs.org, the same way the upstream Playwright build"
echo "does it. The result is put under 'driver-bundle/src/main/resources/driver'."
echo "The platform-independent 'playwright-core' npm package is assembled once into the driver"
echo "module ('driver/src/main/resources/driver/package'), and the matching Node.js binary from"
echo "https://nodejs.org for each platform goes into the driver-bundle module"
echo "('driver-bundle/src/main/resources/driver/<platform>'), the same way the upstream"
echo "Playwright build does it."
echo ""
echo "Usage: scripts/download_driver.sh [option]"
echo ""
@@ -56,20 +58,26 @@ echo "Driver version: $DRIVER_VERSION"
echo "Upstream commit: $GIT_HEAD"
echo "Node.js version: $NODE_VERSION"
cd ../driver-bundle/src/main/resources
# The platform-independent driver code (playwright-core) is assembled once into the driver module;
# the Node.js binary for each platform is assembled into the driver-bundle module. See issue #1196.
ROOT="$(cd .. && pwd)"
CORE_DEST="$ROOT/driver/src/main/resources/driver"
NODE_DEST="$ROOT/driver-bundle/src/main/resources/driver"
if [[ -d 'driver' ]]; then
echo "Deleting existing drivers from $(pwd)"
rm -rf driver
fi
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
mkdir -p driver
cd driver
# Download the platform-independent driver package (playwright-core) once.
CORE_TGZ="$(pwd)/playwright-core-$DRIVER_VERSION.tgz"
# 1. playwright-core package -> driver module (once, shared by every platform).
echo "Assembling playwright-core package to $CORE_DEST/package"
rm -rf "$CORE_DEST/package"
mkdir -p "$CORE_DEST"
CORE_TGZ="$TMP_DIR/playwright-core-$DRIVER_VERSION.tgz"
download "https://registry.npmjs.org/playwright-core/-/playwright-core-$DRIVER_VERSION.tgz" "$CORE_TGZ"
# The npm tarball has a top-level package/ directory, so this creates $CORE_DEST/package.
tar -xzf "$CORE_TGZ" -C "$CORE_DEST"
rm -f "$CORE_TGZ"
# 2. Node.js binary for each platform -> driver-bundle module.
# <java platform dir>:<nodejs platform suffix>:<archive extension>
for ENTRY in \
"mac:darwin-x64:tar.gz" \
@@ -79,28 +87,25 @@ for ENTRY in \
"win32_x64:win-x64:zip"
do
IFS=':' read -r PLATFORM NODE_SUFFIX ARCHIVE <<< "$ENTRY"
echo "Assembling driver for $PLATFORM to $(pwd)/$PLATFORM"
mkdir "$PLATFORM"
DEST="$NODE_DEST/$PLATFORM"
echo "Assembling Node.js for $PLATFORM to $DEST"
rm -rf "$DEST"
mkdir -p "$DEST"
# 1. playwright-core package contents -> $PLATFORM/package
tar -xzf "$CORE_TGZ" -C "$PLATFORM"
# 2. Node.js binary and its license from the official Node.js distribution.
# Node.js binary and its license from the official Node.js distribution.
NODE_DIR="node-v$NODE_VERSION-$NODE_SUFFIX"
NODE_ARCHIVE="$NODE_DIR.$ARCHIVE"
NODE_ARCHIVE="$TMP_DIR/$NODE_DIR.$ARCHIVE"
download "https://nodejs.org/dist/v$NODE_VERSION/$NODE_DIR.$ARCHIVE" "$NODE_ARCHIVE"
if [[ $ARCHIVE == "zip" ]]; then
unzip -joq "$NODE_ARCHIVE" "$NODE_DIR/node.exe" -d "$PLATFORM"
unzip -joq "$NODE_ARCHIVE" "$NODE_DIR/LICENSE" -d "$PLATFORM"
unzip -joq "$NODE_ARCHIVE" "$NODE_DIR/node.exe" -d "$DEST"
unzip -joq "$NODE_ARCHIVE" "$NODE_DIR/LICENSE" -d "$DEST"
else
tar -xzf "$NODE_ARCHIVE" -C "$PLATFORM" --strip-components=2 "$NODE_DIR/bin/node"
tar -xzf "$NODE_ARCHIVE" -C "$PLATFORM" --strip-components=1 "$NODE_DIR/LICENSE"
tar -xzf "$NODE_ARCHIVE" -C "$DEST" --strip-components=2 "$NODE_DIR/bin/node"
tar -xzf "$NODE_ARCHIVE" -C "$DEST" --strip-components=1 "$NODE_DIR/LICENSE"
fi
rm -f "$NODE_ARCHIVE"
done
rm -f "$CORE_TGZ"
echo ""
echo "All drivers have been successfully assembled."
echo ""
@@ -10,7 +10,6 @@ cd "$(dirname $0)"
PROJECT_DIR=$(mktemp -d)
echo "Creating project in $PROJECT_DIR"
cp -R . $PROJECT_DIR
cp -R ../../driver-bundle/src/test/ $PROJECT_DIR/src/
cp -R ../../playwright/src/test/ $PROJECT_DIR/src/
cd $PROJECT_DIR
+8 -2
View File
@@ -38,14 +38,19 @@ ENV JAVA_HOME=/usr/lib/jvm/java-25-openjdk-${PW_TARGET_ARCH}
ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
# Extract the Playwright driver into the image once so the library reuses it instead of unpacking
# it into /tmp on every launch. See https://github.com/microsoft/playwright-java/issues/1268.
ENV PLAYWRIGHT_DRIVER_DIR=/ms-playwright-driver
RUN mkdir /ms-playwright && \
mkdir /tmp/pw-java
COPY . /tmp/pw-java
RUN cd /tmp/pw-java && \
./scripts/download_driver.sh && \
mvn install -D skipTests --no-transfer-progress && \
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
-D exec.args="install-driver" -f playwright/pom.xml --no-transfer-progress && \
DEBIAN_FRONTEND=noninteractive mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
-D exec.args="install-deps" -f playwright/pom.xml --no-transfer-progress && \
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
@@ -62,4 +67,5 @@ RUN cd /tmp/pw-java && \
else \
rm /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstwebrtc.so; \
fi && \
chmod -R 777 $PLAYWRIGHT_BROWSERS_PATH
chmod -R 777 $PLAYWRIGHT_BROWSERS_PATH && \
chmod -R 777 $PLAYWRIGHT_DRIVER_DIR
+8 -2
View File
@@ -38,14 +38,19 @@ ENV JAVA_HOME=/usr/lib/jvm/java-25-openjdk-${PW_TARGET_ARCH}
ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
# Extract the Playwright driver into the image once so the library reuses it instead of unpacking
# it into /tmp on every launch. See https://github.com/microsoft/playwright-java/issues/1268.
ENV PLAYWRIGHT_DRIVER_DIR=/ms-playwright-driver
RUN mkdir /ms-playwright && \
mkdir /tmp/pw-java
COPY . /tmp/pw-java
RUN cd /tmp/pw-java && \
./scripts/download_driver.sh && \
mvn install -D skipTests --no-transfer-progress && \
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
-D exec.args="install-driver" -f playwright/pom.xml --no-transfer-progress && \
DEBIAN_FRONTEND=noninteractive mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
-D exec.args="install-deps" -f playwright/pom.xml --no-transfer-progress && \
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
@@ -53,4 +58,5 @@ RUN cd /tmp/pw-java && \
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
-D exec.args="mark-docker-image '${DOCKER_IMAGE_NAME_TEMPLATE}'" -f playwright/pom.xml --no-transfer-progress && \
rm -rf /tmp/pw-java && \
chmod -R 777 $PLAYWRIGHT_BROWSERS_PATH
chmod -R 777 $PLAYWRIGHT_BROWSERS_PATH && \
chmod -R 777 $PLAYWRIGHT_DRIVER_DIR
+62
View File
@@ -0,0 +1,62 @@
FROM ubuntu:resolute
ARG DEBIAN_FRONTEND=noninteractive
ARG TZ=America/Los_Angeles
ARG DOCKER_IMAGE_NAME_TEMPLATE="mcr.microsoft.com/playwright/java:v%version%-resolute"
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
# === INSTALL JDK and Maven ===
RUN apt-get update && \
apt-get install -y --no-install-recommends openjdk-25-jdk \
# Install utilities required for downloading browsers
wget \
# Install utilities required for downloading driver
unzip \
# For the MSEdge install script
gpg && \
rm -rf /var/lib/apt/lists/* && \
# Create the pwuser
useradd -m -s /bin/bash pwuser
# Ubuntu 22.04 and earlier come with Maven 3.6.3 which fails with
# Java 25, so we install latest Maven from Apache instead.
RUN VERSION=3.9.12 && \
wget -O - https://archive.apache.org/dist/maven/maven-3/$VERSION/binaries/apache-maven-$VERSION-bin.tar.gz | tar zxfv - -C /opt/ && \
ln -s /opt/apache-maven-$VERSION/bin/mvn /usr/local/bin/
ARG PW_TARGET_ARCH
ENV JAVA_HOME=/usr/lib/jvm/java-25-openjdk-${PW_TARGET_ARCH}
# === BAKE BROWSERS INTO IMAGE ===
# Browsers will remain downloaded in `/ms-playwright`.
# Note: make sure to set 777 to the registry so that any user can access
# registry.
ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
# Extract the Playwright driver into the image once so the library reuses it instead of unpacking
# it into /tmp on every launch. See https://github.com/microsoft/playwright-java/issues/1268.
ENV PLAYWRIGHT_DRIVER_DIR=/ms-playwright-driver
RUN mkdir /ms-playwright && \
mkdir /tmp/pw-java
COPY . /tmp/pw-java
RUN cd /tmp/pw-java && \
mvn install -D skipTests --no-transfer-progress && \
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
-D exec.args="install-driver" -f playwright/pom.xml --no-transfer-progress && \
DEBIAN_FRONTEND=noninteractive mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
-D exec.args="install-deps" -f playwright/pom.xml --no-transfer-progress && \
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
-D exec.args="install" -f playwright/pom.xml --no-transfer-progress && \
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
-D exec.args="mark-docker-image '${DOCKER_IMAGE_NAME_TEMPLATE}'" -f playwright/pom.xml --no-transfer-progress && \
rm -rf /tmp/pw-java && \
chmod -R 777 $PLAYWRIGHT_BROWSERS_PATH && \
chmod -R 777 $PLAYWRIGHT_DRIVER_DIR
+5 -1
View File
@@ -3,7 +3,7 @@ set -e
set +x
if [[ ($1 == '--help') || ($1 == '-h') || ($1 == '') || ($2 == '') ]]; then
echo "usage: $(basename $0) {--arm64,--amd64} {jammy,noble} playwright:localbuild-noble"
echo "usage: $(basename $0) {--arm64,--amd64} {jammy,noble,resolute} playwright:localbuild-noble"
echo
echo "Build Playwright docker image and tag it as 'playwright:localbuild-noble'."
echo "Once image is built, you can run it with"
@@ -34,4 +34,8 @@ fi
PW_TARGET_ARCH=$(echo $1 | cut -c3-)
# Assemble the driver on the host where npm is available; the Dockerfile picks
# it up via `COPY . /tmp/pw-java`.
../../scripts/download_driver.sh
docker build --platform "${PLATFORM}" --build-arg "PW_TARGET_ARCH=${PW_TARGET_ARCH}" -t "$3" -f "Dockerfile.$2" ../../
+15 -2
View File
@@ -38,6 +38,11 @@ NOBLE_TAGS=(
"v${PW_VERSION}-noble"
)
# Ubuntu 26.04
RESOLUTE_TAGS=(
"v${PW_VERSION}-resolute"
)
tag_and_push() {
local source="$1"
local target="$2"
@@ -74,8 +79,10 @@ publish_docker_images_with_arch_suffix() {
TAGS=("${JAMMY_TAGS[@]}")
elif [[ "$FLAVOR" == "noble" ]]; then
TAGS=("${NOBLE_TAGS[@]}")
elif [[ "$FLAVOR" == "resolute" ]]; then
TAGS=("${RESOLUTE_TAGS[@]}")
else
echo "ERROR: unknown flavor - $FLAVOR. Must be either 'jammy', or 'noble'"
echo "ERROR: unknown flavor - $FLAVOR. Must be either 'jammy', 'noble', or 'resolute'"
exit 1
fi
local ARCH="$2"
@@ -100,8 +107,10 @@ publish_docker_manifest () {
TAGS=("${JAMMY_TAGS[@]}")
elif [[ "$FLAVOR" == "noble" ]]; then
TAGS=("${NOBLE_TAGS[@]}")
elif [[ "$FLAVOR" == "resolute" ]]; then
TAGS=("${RESOLUTE_TAGS[@]}")
else
echo "ERROR: unknown flavor - $FLAVOR. Must be either 'jammy', 'noble'"
echo "ERROR: unknown flavor - $FLAVOR. Must be either 'jammy', 'noble', or 'resolute'"
exit 1
fi
@@ -127,3 +136,7 @@ publish_docker_manifest jammy amd64 arm64
publish_docker_images_with_arch_suffix noble amd64
publish_docker_images_with_arch_suffix noble arm64
publish_docker_manifest noble amd64 arm64
publish_docker_images_with_arch_suffix resolute amd64
publish_docker_images_with_arch_suffix resolute arm64
publish_docker_manifest resolute amd64 arm64