Skip to content

Commit

Permalink
Fix support for Heroku-24 (#15)
Browse files Browse the repository at this point in the history
* try with Dockerfile

* add heroku 24

* separate packages for heroku-24

* remove packages from heroku-24

these no longer exist

* Test that Chrome is on PATH and can launch

To make testing fully representative of the Heroku platform, we have to run
the built app against the run image and not the build image. (Whilst Heroku CI
will use the build image, some apps will use the buildpack outside of CI, and so
against the run image which has fewer system libraries than the build image.)

* Add a `.dockerignore` to speed up local iteration

This prevents unnecessary Docker cache invalidation when editing files
that don't affect the image, meaning quicker iteration times when
developing on this buildpack locally.

* Fix packages on Heroku-24

Fixes this error:

```
chrome: error while loading shared libraries: libasound.so.2: cannot open shared object file: No such file or directory
```

And also cleans up the packages list, removing some packages that
either are no longer needed, or already exist in the base image. This
is safe to do now that `bin/test.sh` checks for missing shared libraries.

---------

Co-authored-by: Ed Morley <501702+edmorley@users.noreply.github.com>
  • Loading branch information
jason-salesforce and edmorley committed May 30, 2024
1 parent 7e489c1 commit 10cb812
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 18 deletions.
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.github/
bin/test.sh
Dockerfile
17 changes: 2 additions & 15 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,10 @@ jobs:
test:
strategy:
matrix:
stack: [heroku-20, heroku-22, heroku-24]
stack_version: [20, 22, 24]
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Run Buildpack Compile
run: |
./bin/compile . . .
env:
STACK: ${{ matrix.stack }}

- name: Check Installation
run: |
# Trick the profile script into using working dir as HOME
HOME="$(pwd)"
# Verify profile script puts Chrome & Chromedriver on the PATH
source .profile.d/chrome-for-testing.sh
chrome --version
chromedriver --version
run: ./bin/test.sh ${{ matrix.stack_version }}
35 changes: 35 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
ARG STACK_VERSION
FROM --platform=linux/amd64 heroku/heroku:${STACK_VERSION}-build as build

# This ARG duplication is required since the lines before and after the 'FROM' are in different scopes.
ARG STACK_VERSION
ENV STACK="heroku-${STACK_VERSION}"

# On Heroku-24 and later the default user is not root.
# Once support for Heroku-22 and older is removed, the `useradd` steps below can be removed.
USER root

# Emulate the platform where root access is not available
RUN useradd -m non-root-user
USER non-root-user
RUN mkdir -p /tmp/build /tmp/cache /tmp/env
COPY --chown=non-root-user . /buildpack

# Sanitize the environment seen by the buildpack, to prevent reliance on
# environment variables that won't be present when it's run by Heroku CI.
RUN env -i PATH=$PATH HOME=$HOME STACK=$STACK /buildpack/bin/detect /tmp/build
RUN env -i PATH=$PATH HOME=$HOME STACK=$STACK /buildpack/bin/compile /tmp/build /tmp/cache /tmp/env

# We must then test against the run image since that has fewer system libraries installed.
FROM --platform=linux/amd64 heroku/heroku:${STACK_VERSION}
USER root
# Emulate the platform where root access is not available
RUN useradd -m non-root-user
USER non-root-user
COPY --from=build --chown=non-root-user /tmp/build /app
# Emulate the platform which sources all .profile.d/ scripts on app boot.
RUN echo 'for f in /app/.profile.d/*; do source "${f}"; done' > /app/.profile
ENV HOME=/app
WORKDIR /app
# We have to use a login bash shell otherwise the .profile script won't be run.
CMD ["bash", "-l"]
21 changes: 18 additions & 3 deletions bin/install-chrome-dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
topic "Installing Chrome dependencies"

# Install correct dependencies according to $STACK
# The package list is validated by bin/test.sh - see its output to identify any missing libraries.
# Also look here for more packages/notes https://developers.google.com/web/tools/puppeteer/troubleshooting
case "${STACK}" in
"heroku-20" | "heroku-22" | "heroku-24")
# the package list is found by using ci:debug then running ldd $GOOGLE_CHROME_BIN | grep not
# also look here for more packages/notes https://developers.google.com/web/tools/puppeteer/troubleshooting
"heroku-20" | "heroku-22")
PACKAGES="
gconf-service
libappindicator1
Expand Down Expand Up @@ -46,6 +46,21 @@ case "${STACK}" in
fonts-liberation
"
;;
"heroku-24")
PACKAGES="
fonts-liberation
libasound2t64
libatk-bridge2.0-0
libatk1.0-0
libcups2
libgbm1
libxcomposite1
libxdamage1
libxfixes3
libxkbcommon0
libxrandr2
"
;;
*)
error "STACK must be 'heroku-20', 'heroku-22' or 'heroku-24', not '${STACK}'."
esac
Expand Down
23 changes: 23 additions & 0 deletions bin/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env bash

set -euo pipefail

STACK_VERSION="${1:?'Error: The stack version number must be specified as the first argument.'}"

set -x

docker build --progress=plain --build-arg="STACK_VERSION=${STACK_VERSION}" -t heroku-buildpack-chrome-for-testing .

# Note: All of the container commands must be run via a login bash shell otherwise the profile.d scripts won't be run.

# Check the profile.d scripts correctly added the binaries to PATH.
docker run heroku-buildpack-chrome-for-testing bash -l -c 'chrome --version'
docker run heroku-buildpack-chrome-for-testing bash -l -c 'chromedriver --version'

# Check that there are no missing dynamically linked libraries.
docker run heroku-buildpack-chrome-for-testing bash -l -c 'ldd $(which chrome)'
docker run heroku-buildpack-chrome-for-testing bash -l -c 'ldd $(which chromedriver)'

# Check Chrome can fully boot in both new and old headless modes.
docker run heroku-buildpack-chrome-for-testing bash -l -c 'chrome --no-sandbox --headless=new --screenshot https://google.com'
docker run heroku-buildpack-chrome-for-testing bash -l -c 'chrome --no-sandbox --headless=old --screenshot https://google.com'

0 comments on commit 10cb812

Please sign in to comment.