diff --git a/.github/workflows/build-push.yml b/.github/workflows/build-push.yml new file mode 100644 index 0000000..ab64f00 --- /dev/null +++ b/.github/workflows/build-push.yml @@ -0,0 +1,74 @@ +name: build-push +on: + push: + branches: + schedule: + - cron: '15 12 * * *' + +jobs: + lint: + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + id-token: write + steps: + - uses: 'actions/checkout@v4' + + - uses: hadolint/hadolint-action@v3.1.0 + with: + dockerfile: Dockerfile + verbose: true + build-push: + needs: [lint] + runs-on: ubuntu-latest + strategy: + matrix: + php-version: ["8.1", "8.2", "8.3"] + drupal-version: ["10.2.x", "10.3.x", "10.4.x-dev", "11.0.x"] + exclude: + - drupal-version: "11.0.x" + php-versions: "8.1" + - drupal-version: "11.0.x" + php-versions: "8.2" + steps: + - uses: 'actions/checkout@v4' + + - name: Extract branch or tag name as docker tag + shell: bash + run: |- + if [[ "${GITHUB_REF}" == refs/tags/* ]]; then + TAG=$(echo "${GITHUB_REF#refs/tags/}" | sed 's/[^a-zA-Z0-9._-]//g' | awk '{print substr($0, length($0)-120)}') + else + TAG=$(echo "${GITHUB_REF#refs/heads/}" | sed 's/[^a-zA-Z0-9._-]//g' | awk '{print substr($0, length($0)-120)}') + if [ "$TAG" = "main" ]; then + TAG="" + fi + fi + echo "tag=$TAG" >> $GITHUB_OUTPUT + DRUPAL_MAJOR_MINOR=$(echo "${{ matrix.drupal-version }}" | cut -d. -f1 -f2) + echo "drupal_version=$DRUPAL_MAJOR_MINOR" >> $GITHUB_OUTPUT + id: extract_tag + + - name: Docker Hub Login + uses: docker/login-action@v3 + with: + registry: 'docker.io' + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and push dockerhub + uses: docker/build-push-action@v5 + with: + platforms: | + linux/amd64 + linux/arm64 + linux/arm/v7 + darwin/amd64 + darwin/arm64 + build-args: | + PHP_VERSION=${{ matrix.php-version }} + DRUPAL_VERSION=${{ matrix.drupal-version }} + push: true + tags: | + lehighlts/drupal-ci:${{ steps.extract_tag.outputs.drupal_version }}-php${{ matrix.php-version }}${{steps.extract_tag.outputs.tag}} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f372ead --- /dev/null +++ b/Dockerfile @@ -0,0 +1,38 @@ +ARG PHP_VERSION=8.3 +FROM php:${PHP_VERSION}-fpm-alpine3.20 + +ARG DRUPAL_VERSION=11.0.x +ENV DRUPAL_VERSION=$DRUPAL_VERSION +ENV COMPOSER_MEMORY_LIMIT=-1 +ENV DRUPAL_DIR=/var/www/drupal +ENV SIMPLETEST_DB=sqlite://localhost/default +ENV LINT=1 +ENV DRUPAL_PRACTICE=1 + +WORKDIR $DRUPAL_DIR + +ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/ + +RUN chmod +x /usr/local/bin/install-php-extensions && \ + install-php-extensions @composer \ + gd \ + zip + +RUN apk update \ + && apk add --no-cache \ + bash==5.2.26-r0 \ + curl==8.10.1-r0 \ + git==2.45.2-r0 \ + jq==1.7.1-r0 \ + yq==4.44.1-r2 \ + zip==3.0-r12 + +RUN composer create-project drupal/recommended-project:$DRUPAL_VERSION . && \ + composer require "drupal/core-dev:$DRUPAL_VERSION" drush/drush && \ + ln -s /var/www/drupal/vendor/bin/drush /usr/local/bin/drush && \ + composer require drupal/coder && \ + drush si --db-url=${SIMPLETEST_DB} --yes + +COPY scripts . + +ENTRYPOINT ["/var/www/drupal/docker-entrypoint.sh"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..1332a38 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# drupal-ci + +Drupal docker images to easily run linters and phpunit tests. + +e.g. to test the module in Drupal 11.0 in php 8.3 you can run + +``` +MODULE=foo +docker run --rm \ + --volume $(pwd):/var/www/drupal/web/modules/contrib/$MODULE \ + --env ENABLE_MODULES=$MODULE \ + lehighlts/drupal-ci:11.0-php8.3 +``` + +## Settings + +You can pass some environment variables to the docker image + +| Env Var Name | Explanation | +|------------------- |------------------------------------------------------------------------------------------------- | +| `ENABLE_MODULES` | The name of the module to enable (e.g. ENABLE_MODULES=turnstile_protect) | +| `LINT` | 1/0 - whether to run code sniffer with `Drupal` standard on the `ENABLE_MODULES` codebase | +| `DRUPAL_PRACTICE` | 1/0 - whether to run code sniffer with `DrupalPractice` standard on the `ENABLE_MODULES` codebase | diff --git a/scripts/docker-entrypoint.sh b/scripts/docker-entrypoint.sh new file mode 100755 index 0000000..53b3b73 --- /dev/null +++ b/scripts/docker-entrypoint.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash + +set -eou pipefail + +if [ "$LINT" -eq 1 ]; then + cp web/core/phpcs.xml.dist . + if [ -v ENABLE_MODULES ]; then + for MODULE in $ENABLE_MODULES; do + INFO_FILE=$(find web -type f -name "$MODULE.info.yml") + if [ "$INFO_FILE" = "" ]; then + continue + fi + DIR=$(dirname "$INFO_FILE") + + php vendor/bin/phpcs \ + --standard=Drupal \ + --extensions=php,module,inc,install,test,profile,theme \ + "$DIR" + if [ "$DRUPAL_PRACTICE" -eq 1 ]; then + php vendor/bin/phpcs \ + --standard=DrupalPractice \ + --extensions=php,module,inc,install,test,profile,theme \ + "$DIR" + fi + done + fi +fi + +# test +PHPUNIT_FILE=web/core/phpunit.xml.dist +if [ -v ENABLE_MODULES ]; then + composer config --no-interaction allow-plugins true + for MODULE in $ENABLE_MODULES; do + INFO_FILE=$(find web -type f -name "$MODULE.info.yml") + if [ "$INFO_FILE" = "" ]; then + composer require "drupal/$MODULE" --no-interaction --yes + continue + fi + + DIR=$(dirname "$INFO_FILE") + if [ -f "$DIR/phpunit.xml" ]; then + PHPUNIT_FILE="$DIR/phpunit.xml" + fi + COMPOSER_JSON="$DIR/composer.json" + + if [ -f "$COMPOSER_JSON" ]; then + dependencies=$(jq -r '.require | to_entries[] | "\(.key):\(.value)"' "$COMPOSER_JSON") + if [ -n "$dependencies" ]; then + echo "Dependencies for $MODULE: $dependencies" + for dependency in $dependencies; do + echo "Running composer require $dependency" + composer require "$dependency" + done + else + echo "No dependencies found for $MODULE" + fi + else + composer require "drupal/$MODULE" --no-interaction --yes + fi + done + + echo "Enabling $ENABLE_MODULES" + drush -y en "$ENABLE_MODULES" +fi + +echo "Starting test server" +drush rs --quiet 127.0.0.1:8282 & +until curl -s http://127.0.0.1:8282/; do true; done > /dev/null + +echo "Running phpunit" +cd "$DRUPAL_DIR/web/core" +"$DRUPAL_DIR"/vendor/bin/phpunit --debug