Skip to content

Commit be0cf6d

Browse files
authored
fix(docker): build the client on the host and make utils/docker the build context (#2034)
1 parent bc1337e commit be0cf6d

9 files changed

Lines changed: 70 additions & 96 deletions

File tree

‎.azure-pipelines/publish-docker.yml‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ extends:
6969
echo '{ "data-root": "/mnt/docker" }' | sudo tee /etc/docker/daemon.json
7070
sudo service docker start
7171
72-
# Used by scripts/download_driver.sh on the host. The repository root is the
73-
# Docker build context, so .dockerignore keeps this file out of the images.
72+
# Used by scripts/download_driver.sh on the host. The Docker build context is
73+
# utils/docker (see build.sh), so this file never reaches the images.
7474
- task: Bash@3
7575
displayName: "setup .npmrc"
7676
inputs:
@@ -115,9 +115,7 @@ extends:
115115
displayName: "Build & publish Docker images"
116116
inputs:
117117
targetType: "inline"
118-
# The authenticated settings.xml is passed to `docker build` as a secret so
119-
# that Maven inside the image also resolves from DevDiv_PublicPackages.
120-
script: MAVEN_SETTINGS_SECRET="$HOME/.m2/settings.xml" ./utils/docker/publish_docker.sh ${{ parameters.releaseChannel }}
118+
script: ./utils/docker/publish_docker.sh ${{ parameters.releaseChannel }}
121119
env:
122120
ACR_CACHE_PREFIX: "playwright.azurecr.io/cached/"
123121
UBUNTU_MIRROR_PREFIX: "azure."

‎.dockerignore‎

Lines changed: 0 additions & 8 deletions
This file was deleted.

‎.github/workflows/test_docker.yml‎

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,11 @@ jobs:
5757
- name: Copy repository inside docker container
5858
run: |
5959
docker cp . "$CONTAINER_ID":/home/pwuser/playwright
60-
# /root/.m2 was populated as root during image build; move it to
61-
# pwuser so the locally-installed SNAPSHOT artifacts resolve.
62-
docker exec --user root "$CONTAINER_ID" bash -c '
63-
chown -R pwuser /home/pwuser/playwright
64-
mv /root/.m2 /home/pwuser/.m2
65-
chown -R pwuser /home/pwuser/.m2
66-
'
60+
# build.sh installed the SNAPSHOT artifacts into the local Maven repository
61+
# of the runner; give them to pwuser so the test projects resolve them.
62+
docker exec "$CONTAINER_ID" mkdir -p /home/pwuser/.m2/repository/com/microsoft
63+
docker cp ~/.m2/repository/com/microsoft/playwright "$CONTAINER_ID":/home/pwuser/.m2/repository/com/microsoft/playwright
64+
docker exec --user root "$CONTAINER_ID" chown -R pwuser /home/pwuser/playwright /home/pwuser/.m2
6765
6866
- name: Run smoke tests in container
6967
run: |

‎utils/docker/.dockerignore‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# This directory is the Docker build context (see build.sh). The image build reads only
2+
# the client jars staged in dist/ and the Maven tarball in maven/; keep everything else,
3+
# such as the oras download of publish_docker.sh, out of the build context.
4+
*
5+
!dist
6+
!maven
7+
# Should the build context ever grow, keep VCS metadata, registry credentials and local
8+
# environment files out of it regardless.
9+
**/.git
10+
**/.npmrc
11+
**/.env*

‎utils/docker/.gitignore‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
oras/
2-
2+
dist/

‎utils/docker/Dockerfile.jammy‎

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ RUN find /etc/apt -type f \( -name '*.list' -o -name '*.sources' \) \
3131
# Java 25, so we install latest Maven from Apache instead. build.sh
3232
# downloads it into utils/docker/maven.
3333
ARG MAVEN_VERSION
34-
RUN --mount=type=bind,source=utils/docker/maven,target=/tmp/maven \
34+
RUN --mount=type=bind,source=maven,target=/tmp/maven \
3535
tar zxf /tmp/maven/apache-maven-$MAVEN_VERSION-bin.tar.gz -C /opt/ && \
3636
ln -s /opt/apache-maven-$MAVEN_VERSION/bin/mvn /usr/local/bin/
3737

@@ -50,25 +50,13 @@ ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
5050
# it into /tmp on every launch. See https://github.com/microsoft/playwright-java/issues/1268.
5151
ENV PLAYWRIGHT_DRIVER_DIR=/ms-playwright-driver
5252

53-
RUN mkdir /ms-playwright && \
54-
mkdir /tmp/pw-java
55-
56-
COPY . /tmp/pw-java
57-
58-
# The optional Maven settings secret routes dependency resolution through a mirror
59-
# (see .azure-pipelines/publish-docker.yml).
60-
RUN --mount=type=secret,id=mavensettings,target=/root/.m2/settings.xml,required=false \
61-
cd /tmp/pw-java && \
62-
mvn install -D skipTests --no-transfer-progress && \
63-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
64-
-D exec.args="install-driver" -f playwright/pom.xml --no-transfer-progress && \
65-
DEBIAN_FRONTEND=noninteractive mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
66-
-D exec.args="install-deps" -f playwright/pom.xml --no-transfer-progress && \
67-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
68-
-D exec.args="install" -f playwright/pom.xml --no-transfer-progress && \
69-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
70-
-D exec.args="mark-docker-image '${DOCKER_IMAGE_NAME_TEMPLATE}'" -f playwright/pom.xml --no-transfer-progress && \
71-
rm -rf /tmp/pw-java && \
53+
# The client jar and its runtime dependencies, staged by build.sh, are only mounted to
54+
# run the CLI; they do not go into the image.
55+
RUN --mount=type=bind,source=dist,target=/tmp/pw-java \
56+
mkdir /ms-playwright && \
57+
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI install-driver && \
58+
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI install --with-deps && \
59+
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI mark-docker-image "${DOCKER_IMAGE_NAME_TEMPLATE}" && \
7260
# Workaround for https://github.com/microsoft/playwright/issues/27313
7361
# While the gstreamer plugin load process can be in-process, it ended up throwing
7462
# an error that it can't have libsoup2 and libsoup3 in the same process because

‎utils/docker/Dockerfile.noble‎

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ RUN find /etc/apt -type f \( -name '*.list' -o -name '*.sources' \) \
3131
# Java 25, so we install latest Maven from Apache instead. build.sh
3232
# downloads it into utils/docker/maven.
3333
ARG MAVEN_VERSION
34-
RUN --mount=type=bind,source=utils/docker/maven,target=/tmp/maven \
34+
RUN --mount=type=bind,source=maven,target=/tmp/maven \
3535
tar zxf /tmp/maven/apache-maven-$MAVEN_VERSION-bin.tar.gz -C /opt/ && \
3636
ln -s /opt/apache-maven-$MAVEN_VERSION/bin/mvn /usr/local/bin/
3737

@@ -50,24 +50,12 @@ ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
5050
# it into /tmp on every launch. See https://github.com/microsoft/playwright-java/issues/1268.
5151
ENV PLAYWRIGHT_DRIVER_DIR=/ms-playwright-driver
5252

53-
RUN mkdir /ms-playwright && \
54-
mkdir /tmp/pw-java
55-
56-
COPY . /tmp/pw-java
57-
58-
# The optional Maven settings secret routes dependency resolution through a mirror
59-
# (see .azure-pipelines/publish-docker.yml).
60-
RUN --mount=type=secret,id=mavensettings,target=/root/.m2/settings.xml,required=false \
61-
cd /tmp/pw-java && \
62-
mvn install -D skipTests --no-transfer-progress && \
63-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
64-
-D exec.args="install-driver" -f playwright/pom.xml --no-transfer-progress && \
65-
DEBIAN_FRONTEND=noninteractive mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
66-
-D exec.args="install-deps" -f playwright/pom.xml --no-transfer-progress && \
67-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
68-
-D exec.args="install" -f playwright/pom.xml --no-transfer-progress && \
69-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
70-
-D exec.args="mark-docker-image '${DOCKER_IMAGE_NAME_TEMPLATE}'" -f playwright/pom.xml --no-transfer-progress && \
71-
rm -rf /tmp/pw-java && \
53+
# The client jar and its runtime dependencies, staged by build.sh, are only mounted to
54+
# run the CLI; they do not go into the image.
55+
RUN --mount=type=bind,source=dist,target=/tmp/pw-java \
56+
mkdir /ms-playwright && \
57+
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI install-driver && \
58+
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI install --with-deps && \
59+
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI mark-docker-image "${DOCKER_IMAGE_NAME_TEMPLATE}" && \
7260
chmod -R 777 $PLAYWRIGHT_BROWSERS_PATH && \
7361
chmod -R 777 $PLAYWRIGHT_DRIVER_DIR

‎utils/docker/Dockerfile.resolute‎

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -44,24 +44,12 @@ ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
4444
# it into /tmp on every launch. See https://github.com/microsoft/playwright-java/issues/1268.
4545
ENV PLAYWRIGHT_DRIVER_DIR=/ms-playwright-driver
4646

47-
RUN mkdir /ms-playwright && \
48-
mkdir /tmp/pw-java
49-
50-
COPY . /tmp/pw-java
51-
52-
# The optional Maven settings secret routes dependency resolution through a mirror
53-
# (see .azure-pipelines/publish-docker.yml).
54-
RUN --mount=type=secret,id=mavensettings,target=/root/.m2/settings.xml,required=false \
55-
cd /tmp/pw-java && \
56-
mvn install -D skipTests --no-transfer-progress && \
57-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
58-
-D exec.args="install-driver" -f playwright/pom.xml --no-transfer-progress && \
59-
DEBIAN_FRONTEND=noninteractive mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
60-
-D exec.args="install-deps" -f playwright/pom.xml --no-transfer-progress && \
61-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
62-
-D exec.args="install" -f playwright/pom.xml --no-transfer-progress && \
63-
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
64-
-D exec.args="mark-docker-image '${DOCKER_IMAGE_NAME_TEMPLATE}'" -f playwright/pom.xml --no-transfer-progress && \
65-
rm -rf /tmp/pw-java && \
47+
# The client jar and its runtime dependencies, staged by build.sh, are only mounted to
48+
# run the CLI; they do not go into the image.
49+
RUN --mount=type=bind,source=dist,target=/tmp/pw-java \
50+
mkdir /ms-playwright && \
51+
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI install-driver && \
52+
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI install --with-deps && \
53+
java -cp '/tmp/pw-java/*' com.microsoft.playwright.CLI mark-docker-image "${DOCKER_IMAGE_NAME_TEMPLATE}" && \
6654
chmod -R 777 $PLAYWRIGHT_BROWSERS_PATH && \
6755
chmod -R 777 $PLAYWRIGHT_DRIVER_DIR

‎utils/docker/build.sh‎

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@ if [[ ($1 == '--help') || ($1 == '-h') || ($1 == '') || ($2 == '') ]]; then
1010
echo ""
1111
echo " docker run --rm -it playwright:localbuild-noble /bin/bash"
1212
echo ""
13-
echo "NOTE: this requires on Playwright PIP dependencies to be installed"
13+
echo "NOTE: this requires a JDK, Maven and npm on the host: the client is built here"
14+
echo "and the image only runs it to install the browsers."
1415
echo ""
1516
exit 0
1617
fi
1718

1819
function cleanup() {
19-
:
20+
rm -rf dist
2021
}
2122

2223
trap "cleanup; cd $(pwd -P)" EXIT
@@ -34,21 +35,32 @@ fi
3435

3536
PW_TARGET_ARCH=$(echo $1 | cut -c3-)
3637

37-
# Assemble the driver on the host where npm is available; the Dockerfile picks
38-
# it up via `COPY . /tmp/pw-java`.
39-
../../scripts/download_driver.sh
38+
# In the release pipeline ~/.m2/settings.xml routes all Maven downloads through the
39+
# DevDiv_PublicPackages feed instead of Maven Central, which the agent cannot reach.
40+
MVN=(mvn --no-transfer-progress)
4041

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

48-
SECRET_ARGS=()
49-
if [[ -n "${MAVEN_SETTINGS_SECRET:-}" ]]; then
50-
SECRET_ARGS+=(--secret "id=mavensettings,src=${MAVEN_SETTINGS_SECRET}")
49+
if ! PW_VERSION=$("${MVN[@]}" -q -N -f ../../pom.xml exec:exec -D exec.executable=echo \
50+
-D exec.args='${project.version}'); then
51+
# With -q Maven prints its errors to stdout, which was captured above.
52+
echo "ERROR: failed to read the project version: ${PW_VERSION}"
53+
exit 1
5154
fi
55+
rm -rf dist
56+
"${MVN[@]}" -q -f ../../playwright/pom.xml dependency:copy-dependencies \
57+
-D includeScope=runtime -D outputDirectory="$PWD/dist"
58+
cp "../../playwright/target/playwright-$PW_VERSION.jar" dist/
59+
60+
# The jammy and noble images install this Maven (see the Dockerfiles).
61+
MAVEN_VERSION=3.9.12
62+
"${MVN[@]}" -q dependency:copy -D artifact="org.apache.maven:apache-maven:${MAVEN_VERSION}:tar.gz:bin" \
63+
-D outputDirectory=maven
5264

5365
# Keep each arch image a plain single-platform manifest without the unknown/unknown platform entry.
5466
export BUILDX_NO_DEFAULT_ATTESTATIONS=1
@@ -69,8 +81,7 @@ for ((attempt = 1; attempt <= MAX_ATTEMPTS; attempt++)); do
6981
--build-arg "MAVEN_VERSION=${MAVEN_VERSION}" \
7082
--build-arg ACR_CACHE_PREFIX="${ACR_CACHE_PREFIX}" \
7183
--build-arg UBUNTU_MIRROR_PREFIX="${UBUNTU_MIRROR_PREFIX}" \
72-
"${SECRET_ARGS[@]}" \
73-
-t "$3" -f "Dockerfile.$2" ../../; then
84+
-t "$3" -f "Dockerfile.$2" .; then
7485
exit 0
7586
fi
7687
if (( attempt < MAX_ATTEMPTS )); then

0 commit comments

Comments
 (0)