Skip to content
Open
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
10 changes: 5 additions & 5 deletions .azure-pipelines/publish-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ extends:
echo '{ "data-root": "/mnt/docker" }' | sudo tee /etc/docker/daemon.json
sudo service docker start

# Used by scripts/download_driver.sh on the host. The repository root is the
# Docker build context, so .dockerignore keeps this file out of the images.
# Used by scripts/download_driver.sh on the host. The Docker build context is
# utils/docker (see build.sh), so this file never reaches the images.
- task: Bash@3
displayName: "setup .npmrc"
inputs:
Expand Down Expand Up @@ -115,9 +115,9 @@ extends:
displayName: "Build & publish Docker images"
inputs:
targetType: "inline"
# The authenticated settings.xml is passed to `docker build` as a secret so
# that Maven inside the image also resolves from DevDiv_PublicPackages.
script: MAVEN_SETTINGS_SECRET="$HOME/.m2/settings.xml" ./utils/docker/publish_docker.sh ${{ parameters.releaseChannel }}
# build.sh builds the client on the host, where ~/.m2/settings.xml mirrors Maven
# Central to DevDiv_PublicPackages.
script: ./utils/docker/publish_docker.sh ${{ parameters.releaseChannel }}
env:
ACR_CACHE_PREFIX: "playwright.azurecr.io/cached/"
UBUNTU_MIRROR_PREFIX: "azure."
8 changes: 0 additions & 8 deletions .dockerignore

This file was deleted.

11 changes: 11 additions & 0 deletions utils/docker/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This directory is the Docker build context (see build.sh). The image reads only the
# artifacts staged in dist/ and the Maven tarball in maven/; keep everything else, such
# as the oras download of publish_docker.sh, out of the build context.
*
!dist
!maven
# Should the build context ever grow, keep VCS metadata, registry credentials and local
# environment files out of it regardless.
**/.git
**/.npmrc
**/.env*
2 changes: 1 addition & 1 deletion utils/docker/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
oras/

dist/
29 changes: 10 additions & 19 deletions utils/docker/Dockerfile.jammy
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ RUN find /etc/apt -type f \( -name '*.list' -o -name '*.sources' \) \
# Java 25, so we install latest Maven from Apache instead. build.sh
# downloads it into utils/docker/maven.
ARG MAVEN_VERSION
RUN --mount=type=bind,source=utils/docker/maven,target=/tmp/maven \
RUN --mount=type=bind,source=maven,target=/tmp/maven \
tar zxf /tmp/maven/apache-maven-$MAVEN_VERSION-bin.tar.gz -C /opt/ && \
ln -s /opt/apache-maven-$MAVEN_VERSION/bin/mvn /usr/local/bin/

Expand All @@ -50,25 +50,16 @@ ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
# 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
# The playwright-java artifacts built by build.sh go into the local Maven repository so
# that Maven projects built in the image resolve them without downloading.
COPY dist/m2 /root/.m2/repository

COPY . /tmp/pw-java

# The optional Maven settings secret routes dependency resolution through a mirror
# (see .azure-pipelines/publish-docker.yml).
RUN --mount=type=secret,id=mavensettings,target=/root/.m2/settings.xml,required=false \
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 && \
# The CLI runs from the jars staged by build.sh; the mount leaves nothing in the image.
RUN --mount=type=bind,source=dist/cli,target=/tmp/pw-java \
mkdir /ms-playwright && \
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI install-driver && \
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI install --with-deps && \
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI mark-docker-image "${DOCKER_IMAGE_NAME_TEMPLATE}" && \
# Workaround for https://github.com/microsoft/playwright/issues/27313
# While the gstreamer plugin load process can be in-process, it ended up throwing
# an error that it can't have libsoup2 and libsoup3 in the same process because
Expand Down
29 changes: 10 additions & 19 deletions utils/docker/Dockerfile.noble
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ RUN find /etc/apt -type f \( -name '*.list' -o -name '*.sources' \) \
# Java 25, so we install latest Maven from Apache instead. build.sh
# downloads it into utils/docker/maven.
ARG MAVEN_VERSION
RUN --mount=type=bind,source=utils/docker/maven,target=/tmp/maven \
RUN --mount=type=bind,source=maven,target=/tmp/maven \
tar zxf /tmp/maven/apache-maven-$MAVEN_VERSION-bin.tar.gz -C /opt/ && \
ln -s /opt/apache-maven-$MAVEN_VERSION/bin/mvn /usr/local/bin/

Expand All @@ -50,24 +50,15 @@ ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
# 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
# The playwright-java artifacts built by build.sh go into the local Maven repository so
# that Maven projects built in the image resolve them without downloading.
COPY dist/m2 /root/.m2/repository

COPY . /tmp/pw-java

# The optional Maven settings secret routes dependency resolution through a mirror
# (see .azure-pipelines/publish-docker.yml).
RUN --mount=type=secret,id=mavensettings,target=/root/.m2/settings.xml,required=false \
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 && \
# The CLI runs from the jars staged by build.sh; the mount leaves nothing in the image.
RUN --mount=type=bind,source=dist/cli,target=/tmp/pw-java \
mkdir /ms-playwright && \
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI install-driver && \
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI install --with-deps && \
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI mark-docker-image "${DOCKER_IMAGE_NAME_TEMPLATE}" && \
chmod -R 777 $PLAYWRIGHT_BROWSERS_PATH && \
chmod -R 777 $PLAYWRIGHT_DRIVER_DIR
29 changes: 10 additions & 19 deletions utils/docker/Dockerfile.resolute
Original file line number Diff line number Diff line change
Expand Up @@ -44,24 +44,15 @@ ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
# 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

# The optional Maven settings secret routes dependency resolution through a mirror
# (see .azure-pipelines/publish-docker.yml).
RUN --mount=type=secret,id=mavensettings,target=/root/.m2/settings.xml,required=false \
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 && \
# The playwright-java artifacts built by build.sh go into the local Maven repository so
# that Maven projects built in the image resolve them without downloading.
COPY dist/m2 /root/.m2/repository

# The CLI runs from the jars staged by build.sh; the mount leaves nothing in the image.
RUN --mount=type=bind,source=dist/cli,target=/tmp/pw-java \
mkdir /ms-playwright && \
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI install-driver && \
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI install --with-deps && \
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI mark-docker-image "${DOCKER_IMAGE_NAME_TEMPLATE}" && \
chmod -R 777 $PLAYWRIGHT_BROWSERS_PATH && \
chmod -R 777 $PLAYWRIGHT_DRIVER_DIR
53 changes: 37 additions & 16 deletions utils/docker/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ if [[ ($1 == '--help') || ($1 == '-h') || ($1 == '') || ($2 == '') ]]; then
echo ""
echo " docker run --rm -it playwright:localbuild-noble /bin/bash"
echo ""
echo "NOTE: this requires on Playwright PIP dependencies to be installed"
echo "NOTE: this requires a JDK, Maven and npm on the host: the client is built here"
echo "and the image only installs the result."
echo ""
exit 0
fi

function cleanup() {
:
rm -rf dist
}

trap "cleanup; cd $(pwd -P)" EXIT
Expand All @@ -34,21 +35,42 @@ 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
# The host Maven settings (~/.m2/settings.xml) route dependency resolution through the
# mirror of the release pipeline, which cannot reach Maven Central directly.
MVN=(mvn --no-transfer-progress)

# The jammy and noble images install this Maven (see the Dockerfiles). Fetch it with the
# host's Maven so that it resolves through the configured mirror: the release pipeline
# cannot reach Maven Central directly (see .azure-pipelines/settings.xml).
MAVEN_VERSION=3.9.12
mvn dependency:copy -Dartifact="org.apache.maven:apache-maven:${MAVEN_VERSION}:tar.gz:bin" \
-DoutputDirectory=maven --no-transfer-progress -q
# Like the other language ports, build the client on the host, where npm, a JDK and
# Maven are available, and stage what the Dockerfile copies into the image under dist/.
# The build context is this directory, so nothing else reaches the image.
../../scripts/download_driver.sh
"${MVN[@]}" -B install -D skipTests -f ../../pom.xml

SECRET_ARGS=()
if [[ -n "${MAVEN_SETTINGS_SECRET:-}" ]]; then
SECRET_ARGS+=(--secret "id=mavensettings,src=${MAVEN_SETTINGS_SECRET}")
if ! PW_INFO=$("${MVN[@]}" -q -N -f ../../pom.xml exec:exec -D exec.executable=echo \
-D exec.args='${project.version} ${settings.localRepository}'); then
# With -q Maven prints its errors to stdout, which was captured above.
echo "ERROR: failed to read the project version and the local repository: ${PW_INFO}"
exit 1
fi
read -r PW_VERSION LOCAL_REPO <<< "$PW_INFO"
rm -rf dist

# dist/m2: the playwright-java artifacts of this build, for the local Maven repository of
# the image. Projects built in the image then resolve them without downloading.
for MODULE in parent-pom driver driver-bundle playwright; do
mkdir -p "dist/m2/com/microsoft/playwright/$MODULE"
cp -R "$LOCAL_REPO/com/microsoft/playwright/$MODULE/$PW_VERSION" "dist/m2/com/microsoft/playwright/$MODULE/"
done

# dist/cli: the client jar and its runtime dependencies, which the Dockerfile runs the
# CLI from to install the driver, the browsers and their dependencies.
"${MVN[@]}" -q -f ../../playwright/pom.xml dependency:copy-dependencies \
-D includeScope=runtime -D outputDirectory="$PWD/dist/cli"
cp "../../playwright/target/playwright-$PW_VERSION.jar" dist/cli/

# The jammy and noble images install this Maven (see the Dockerfiles).
MAVEN_VERSION=3.9.12
"${MVN[@]}" -q dependency:copy -D artifact="org.apache.maven:apache-maven:${MAVEN_VERSION}:tar.gz:bin" \
-D outputDirectory=maven

# Keep each arch image a plain single-platform manifest without the unknown/unknown platform entry.
export BUILDX_NO_DEFAULT_ATTESTATIONS=1
Expand All @@ -69,8 +91,7 @@ for ((attempt = 1; attempt <= MAX_ATTEMPTS; attempt++)); do
--build-arg "MAVEN_VERSION=${MAVEN_VERSION}" \
--build-arg ACR_CACHE_PREFIX="${ACR_CACHE_PREFIX}" \
--build-arg UBUNTU_MIRROR_PREFIX="${UBUNTU_MIRROR_PREFIX}" \
"${SECRET_ARGS[@]}" \
-t "$3" -f "Dockerfile.$2" ../../; then
-t "$3" -f "Dockerfile.$2" .; then
exit 0
fi
if (( attempt < MAX_ATTEMPTS )); then
Expand Down
Loading