Tests and delivery #3115
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Tests and delivery | |
on: | |
schedule: | |
- cron: '0 8 * * *' # Run at 8AM UTC. | |
push: | |
branches: | |
- '3.x' | |
- '3.x-**' | |
tags: | |
- '3.*' | |
pull_request: | |
branches: | |
- '3.x' | |
env: | |
DOCKER_IMG_PREFIX: farmos/farmos | |
jobs: | |
build: | |
name: Build Docker images | |
# Pin to Ubuntu 22.04 to work around upstream issue with QEMU and binfmt. | |
# @see https://github.com/tonistiigi/binfmt/issues/215 | |
runs-on: ubuntu-22.04 | |
strategy: | |
matrix: | |
platform: | |
- amd64 | |
- arm32v7 | |
- arm64v8 | |
include: | |
- platform: amd64 | |
DOCKER_PLATFORM_NAME: linux/amd64 | |
- platform: arm32v7 | |
DOCKER_PLATFORM_NAME: linux/arm/v7 | |
- platform: arm64v8 | |
DOCKER_PLATFORM_NAME: linux/arm64/v8 | |
steps: | |
# https://github.com/docker/setup-qemu-action | |
- name: Set up QEMU | |
uses: docker/setup-qemu-action@v3 | |
# https://github.com/docker/setup-buildx-action | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Checkout the repository | |
uses: actions/checkout@v4 | |
- name: Set default FARMOS_REPO and FARMOS_VERSION | |
run: | | |
echo "FARMOS_REPO=${GITHUB_REPOSITORY}" >> $GITHUB_ENV | |
echo "FARMOS_VERSION=3.x" >> $GITHUB_ENV | |
- name: Set FARMOS_VERSION for branch push event | |
if: github.event_name == 'push' && github.ref_type == 'branch' | |
run: echo "FARMOS_VERSION=${GITHUB_REF:11}" >> $GITHUB_ENV | |
- name: Set FARMOS_VERSION for tag push event | |
if: github.event_name == 'push' && github.ref_type == 'tag' | |
run: echo "FARMOS_VERSION=${GITHUB_REF:10}" >> $GITHUB_ENV | |
- name: Set FARMOS_VERSION and FARMOS_REPO for pull request event | |
if: github.event_name == 'pull_request' | |
run: | | |
echo "FARMOS_VERSION=${GITHUB_HEAD_REF}" >> $GITHUB_ENV | |
echo "FARMOS_REPO=${{ github.event.pull_request.head.repo.full_name }}" >> $GITHUB_ENV | |
# This builds the production/dev Docker images using the specified FARMOS_VERSION, | |
# but notably it does NOT override the default PROJECT_VERSION, so the | |
# farmOS Composer project 3.x branch is always used. | |
- name: Build and save the farmOS Docker image | |
run: | | |
COMMON_BUILD_ARGS="--load --build-arg FARMOS_REPO=https://github.com/${FARMOS_REPO} --build-arg FARMOS_VERSION=${FARMOS_VERSION} --platform ${{ matrix.DOCKER_PLATFORM_NAME }}" | |
PROD_IMG_NAME=$DOCKER_IMG_PREFIX:3.x-${{ matrix.platform }} | |
DEV_IMG_NAME=$DOCKER_IMG_PREFIX:3.x-dev-${{ matrix.platform }} | |
docker buildx build $COMMON_BUILD_ARGS -t $PROD_IMG_NAME docker | |
docker buildx build $COMMON_BUILD_ARGS -t $DEV_IMG_NAME --target dev docker | |
docker save $PROD_IMG_NAME > /tmp/farmos-${{ matrix.platform }}.tar | |
docker save $DEV_IMG_NAME > /tmp/farmos-dev-${{ matrix.platform }}.tar | |
- name: Cache the farmOS Docker image | |
uses: actions/cache@v4 | |
with: | |
path: /tmp/farmos-${{ matrix.platform }}.tar | |
key: farmos-${{ matrix.platform }}-${{ github.run_id }} | |
- name: Cache the farmOS dev Docker image | |
uses: actions/cache@v4 | |
with: | |
path: /tmp/farmos-dev-${{ matrix.platform }}.tar | |
key: farmos-dev-${{ matrix.platform }}-${{ github.run_id }} | |
outputs: | |
farmos_version: ${{ env.FARMOS_VERSION }} | |
phpcs: | |
name: PHP Codesniffer | |
runs-on: ubuntu-latest | |
needs: build | |
steps: | |
- name: Restore the farmOS dev Docker image from cache | |
uses: actions/cache@v4 | |
with: | |
path: /tmp/farmos-dev-amd64.tar | |
key: farmos-dev-amd64-${{ github.run_id }} | |
- name: Load the Docker dev image | |
run: docker load < /tmp/farmos-dev-amd64.tar | |
- name: Run PHP CodeSniffer | |
run: docker run $DOCKER_IMG_PREFIX:3.x-dev-amd64 phpcs /opt/drupal/web/profiles/farm | |
- name: Check PHP compatibility of contrib modules and themes (ignore warnings) | |
run: | | |
docker run $DOCKER_IMG_PREFIX:3.x-dev-amd64 phpcs --standard=PHPCompatibility --runtime-set testVersion 8.3- --warning-severity=0 /opt/drupal/web/modules | |
docker run $DOCKER_IMG_PREFIX:3.x-dev-amd64 phpcs --standard=PHPCompatibility --runtime-set testVersion 8.3- --warning-severity=0 /opt/drupal/web/themes | |
phpstan: | |
name: PHPStan | |
runs-on: ubuntu-latest | |
needs: build | |
steps: | |
- name: Restore the farmOS dev Docker image from cache | |
uses: actions/cache@v4 | |
with: | |
path: /tmp/farmos-dev-amd64.tar | |
key: farmos-dev-amd64-${{ github.run_id }} | |
- name: Load the Docker dev image | |
run: docker load < /tmp/farmos-dev-amd64.tar | |
- name: Run PHPStan | |
run: docker run $DOCKER_IMG_PREFIX:3.x-dev-amd64 phpstan analyze --memory-limit 1G /opt/drupal/web/profiles/farm | |
rector: | |
name: Rector | |
runs-on: ubuntu-latest | |
needs: build | |
steps: | |
- name: Restore the farmOS dev Docker image from cache | |
uses: actions/cache@v4 | |
with: | |
path: /tmp/farmos-dev-amd64.tar | |
key: farmos-dev-amd64-${{ github.run_id }} | |
- name: Load the Docker dev image | |
run: docker load < /tmp/farmos-dev-amd64.tar | |
- name: Run Rector | |
run: docker run $DOCKER_IMG_PREFIX:3.x-dev-amd64 rector process --dry-run /opt/drupal/web/profiles/farm | |
test: | |
name: Run PHPUnit tests | |
runs-on: ubuntu-latest | |
needs: build | |
strategy: | |
fail-fast: false | |
matrix: | |
dbms: | |
- pgsql | |
- mariadb | |
- sqlite | |
platform: | |
- amd64 | |
include: | |
- dbms: pgsql | |
DB_URL: pgsql://farm:farm@db/farm | |
test_cmd: paratest -vv | |
- dbms: mariadb | |
DB_URL: mysql://farm:farm@db/farm | |
test_cmd: paratest -vv | |
- dbms: sqlite | |
DB_URL: sqlite://localhost/sites/default/files/db.sqlite | |
test_cmd: phpunit --verbose --debug | |
steps: | |
- name: Print test matrix variables | |
run: echo "matrix.platform=${{ matrix.platform }}, matrix.dbms=${{ matrix.dbms }}, matrix.DB_URL=${{ matrix.DB_URL }}" | |
# https://github.com/docker/setup-qemu-action | |
- name: Set up QEMU | |
uses: docker/setup-qemu-action@v3 | |
- name: Checkout the repository | |
uses: actions/checkout@v4 | |
- name: Restore the farmOS dev Docker image from cache | |
uses: actions/cache@v4 | |
with: | |
path: /tmp/farmos-dev-${{ matrix.platform }}.tar | |
key: farmos-dev-${{ matrix.platform }}-${{ github.run_id }} | |
- name: Load the Docker dev image | |
run: docker load < /tmp/farmos-dev-${{ matrix.platform }}.tar | |
# Build a new docker-compose.yml file from docker-compose.testing.common + docker-compose.testing.{dbms}.yml. | |
# Copy to the current directory so that farmOS volume mounts don't change to the docker/www folder. | |
- name: Create docker-compose.yml | |
env: | |
DB_URL: ${{ matrix.DB_URL }} | |
run: | | |
cp docker/docker-compose.testing.* . | |
docker compose -f docker-compose.testing.common.yml -f docker-compose.testing.${{ matrix.dbms }}.yml config > docker-compose.yml | |
# Replace the generic 'farmos/farmos:3.x-dev' image name/tag with the reference to our local platform-specific tagged image | |
sed -i 's%farmos/farmos:3.x-dev%'$DOCKER_IMG_PREFIX:3.x-dev-${{ matrix.platform }}'%g' docker-compose.yml | |
- name: Start containers | |
run: docker compose up -d | |
- name: Wait until www container is ready | |
# The www-container-fs-ready file is only created once we expect the containers to be online | |
# so waiting for that lets us know it is safe to start the tests | |
run: until [ -f ./www/www-container-fs-ready ]; do sleep 0.1; done | |
- name: Install pg_trgm PostgreSQL extension | |
# This avoids race conditions when trying to automatically install it in concurrently run tests. | |
if: matrix.dbms == 'pgsql' | |
run: docker compose exec -T db psql -U farm -c 'CREATE EXTENSION IF NOT EXISTS pg_trgm;' | |
- name: Run PHPUnit tests | |
run: docker compose exec -u www-data -T www ${{ matrix.test_cmd }} /opt/drupal/web/profiles/farm | |
- name: Test Drush site install with all modules | |
run: docker compose exec -u www-data -T www drush site-install --db-url=${{ matrix.DB_URL }} farm farm.modules='all' | |
release: | |
name: Create release | |
# We only create a release if this is a tag push event to the official | |
# repository. | |
if: github.repository == 'farmOS/farmOS' && github.event_name == 'push' && github.ref_type == 'tag' | |
runs-on: ubuntu-latest | |
needs: | |
- build | |
- phpcs | |
- phpstan | |
- rector | |
- test | |
strategy: | |
matrix: | |
platform: | |
# The .tar.gz with the farmOS PHP code is the same for all platforms so we just publish the copy | |
# from the amd64 Docker image since that one will start up fastest | |
- amd64 | |
steps: | |
- name: Set FARMOS_VERSION from previous output | |
run: echo "FARMOS_VERSION=${{ needs.build.outputs.farmos_version }}" >> $GITHUB_ENV | |
- name: Restore the farmOS Docker image from cache | |
uses: actions/cache@v4 | |
with: | |
path: /tmp/farmos-${{ matrix.platform }}.tar | |
key: farmos-${{ matrix.platform }}-${{ github.run_id }} | |
- name: Load the Docker image | |
run: docker load < /tmp/farmos-${{ matrix.platform }}.tar | |
- name: Run the farmOS Docker container | |
run: docker run --rm -v /tmp/farmOS:/opt/drupal $DOCKER_IMG_PREFIX:3.x-${{ matrix.platform }} true | |
- name: Create artifact | |
run: cd /tmp && tar -czf farmOS-${FARMOS_VERSION}.tar.gz farmOS | |
- name: Create GitHub release | |
uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 #2.0.8 | |
with: | |
body: | | |
For full release notes, see [CHANGELOG.md](https://github.com/farmOS/farmOS/blob/${{ env.FARMOS_VERSION }}/CHANGELOG.md). | |
files: /tmp/farmOS-${{ env.FARMOS_VERSION }}.tar.gz | |
draft: false | |
prerelease: false | |
publish-multi-arch-images: | |
name: Publish to Docker Hub | |
# We only publish to Docker Hub if this is a tag or 3.x branch push event | |
# to the official repository. | |
if: github.repository == 'farmOS/farmOS' && github.event_name == 'push' && (github.ref_type == 'tag' || (github.ref_type == 'branch' && needs.build.outputs.farmos_version == '3.x')) | |
runs-on: ubuntu-latest | |
needs: | |
- build | |
- phpcs | |
- phpstan | |
- rector | |
- test | |
strategy: | |
matrix: | |
platform: | |
- amd64 | |
- arm32v7 | |
- arm64v8 | |
steps: | |
- name: Set FARMOS_VERSION from previous output | |
run: echo "FARMOS_VERSION=${{ needs.build.outputs.farmos_version }}" >> $GITHUB_ENV | |
- name: Restore the farmOS Docker image from cache | |
uses: actions/cache@v4 | |
with: | |
path: /tmp/farmos-${{ matrix.platform }}.tar | |
key: farmos-${{ matrix.platform }}-${{ github.run_id }} | |
- name: Load the farmOS Docker image | |
run: docker load < /tmp/farmos-${{ matrix.platform }}.tar | |
- name: Restore the farmOS dev Docker image from cache | |
uses: actions/cache@v4 | |
with: | |
path: /tmp/farmos-dev-${{ matrix.platform }}.tar | |
key: farmos-dev-${{ matrix.platform }}-${{ github.run_id }} | |
- name: Load the farmOS dev Docker image | |
run: docker load < /tmp/farmos-dev-${{ matrix.platform }}.tar | |
- name: Login to Docker Hub | |
uses: docker/login-action@v3 | |
with: | |
username: ${{ secrets.DOCKER_USERNAME }} | |
password: ${{ secrets.DOCKER_PASSWORD }} | |
# If the 3.x branch was pushed... | |
- name: Publish the farmOS image to Docker Hub | |
if: github.ref_type == 'branch' && env.FARMOS_VERSION == '3.x' | |
run: docker push $DOCKER_IMG_PREFIX:3.x-${{ matrix.platform }} | |
- name: Publish the farmOS dev Docker image to Docker Hub | |
if: github.ref_type == 'branch' && env.FARMOS_VERSION == '3.x' | |
run: docker push $DOCKER_IMG_PREFIX:3.x-dev-${{ matrix.platform }} | |
# If a tag was pushed, tag the Docker image and push to Docker Hub. | |
# If the tag is a valid semantic versioning string, also tag "latest". | |
# Semver regex from https://github.com/semver/semver/issues/199#issuecomment-43640395 | |
- name: Tag and publish {DOCKER_IMG_PREFIX}:{tag} image to Docker Hub | |
if: github.ref_type == 'tag' | |
run: | | |
docker tag $DOCKER_IMG_PREFIX:3.x-${{ matrix.platform }} $DOCKER_IMG_PREFIX:${{ env.FARMOS_VERSION }}-${{ matrix.platform }} | |
docker push $DOCKER_IMG_PREFIX:${{ env.FARMOS_VERSION }}-${{ matrix.platform }} | |
if echo ${{ env.FARMOS_VERSION }} | grep -Pq '^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'; then | |
docker tag $DOCKER_IMG_PREFIX:3.x-${{ matrix.platform }} $DOCKER_IMG_PREFIX:latest-${{ matrix.platform }} | |
docker push $DOCKER_IMG_PREFIX:latest-${{ matrix.platform }} | |
fi | |
publish-manifest: | |
name: Publish a multi-arch manifest to Docker Hub | |
# We only publish to Docker Hub if this is a tag or 3.x branch push event | |
# to the official repository. | |
if: github.repository == 'farmOS/farmOS' && github.event_name == 'push' && (github.ref_type == 'tag' || (github.ref_type == 'branch' && needs.build.outputs.farmos_version == '3.x')) | |
runs-on: ubuntu-latest | |
needs: | |
- build | |
- publish-multi-arch-images | |
steps: | |
- name: Set FARMOS_VERSION from previous output | |
run: echo "FARMOS_VERSION=${{ needs.build.outputs.farmos_version }}" >> $GITHUB_ENV | |
- name: Login to Docker Hub | |
uses: docker/login-action@v3 | |
with: | |
username: ${{ secrets.DOCKER_USERNAME }} | |
password: ${{ secrets.DOCKER_PASSWORD }} | |
# If the 3.x branch was pushed... | |
- name: Create and publish the {DOCKER_IMG_PREFIX}:3.x manifest to Docker Hub | |
if: github.ref_type == 'branch' && env.FARMOS_VERSION == '3.x' | |
run: | | |
docker manifest create $DOCKER_IMG_PREFIX:3.x --amend $DOCKER_IMG_PREFIX:3.x-amd64 --amend $DOCKER_IMG_PREFIX:3.x-arm32v7 --amend $DOCKER_IMG_PREFIX:3.x-arm64v8 | |
docker manifest push $DOCKER_IMG_PREFIX:3.x | |
- name: Create and publish the {DOCKER_IMG_PREFIX}:3.x-dev manifest to Docker Hub | |
if: github.ref_type == 'branch' && env.FARMOS_VERSION == '3.x' | |
run: | | |
docker manifest create $DOCKER_IMG_PREFIX:3.x-dev --amend $DOCKER_IMG_PREFIX:3.x-dev-amd64 --amend $DOCKER_IMG_PREFIX:3.x-dev-arm32v7 --amend $DOCKER_IMG_PREFIX:3.x-dev-arm64v8 | |
docker manifest push $DOCKER_IMG_PREFIX:3.x-dev | |
# Same conditional logic as in the publish-multi-arch-images step, except here we | |
# are creating the multi-arch manifest pointing at the previously pushed image tags. | |
# If "latest" is tagged, we will also announce the release in a followup job. | |
- name: Create and publish the {DOCKER_IMG_PREFIX}:{tag} manifest to Docker Hub | |
if: github.ref_type == 'tag' | |
run: | | |
docker manifest create $DOCKER_IMG_PREFIX:${{ env.FARMOS_VERSION }} --amend $DOCKER_IMG_PREFIX:${{ env.FARMOS_VERSION }}-amd64 --amend $DOCKER_IMG_PREFIX:${{ env.FARMOS_VERSION }}-arm32v7 --amend $DOCKER_IMG_PREFIX:${{ env.FARMOS_VERSION }}-arm64v8 | |
docker manifest push $DOCKER_IMG_PREFIX:${{ env.FARMOS_VERSION }} | |
if echo ${{ env.FARMOS_VERSION }} | grep -Pq '^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'; then | |
docker manifest create $DOCKER_IMG_PREFIX:latest --amend $DOCKER_IMG_PREFIX:${{ env.FARMOS_VERSION }}-amd64 --amend $DOCKER_IMG_PREFIX:${{ env.FARMOS_VERSION }}-arm32v7 --amend $DOCKER_IMG_PREFIX:${{ env.FARMOS_VERSION }}-arm64v8 | |
docker manifest push $DOCKER_IMG_PREFIX:latest | |
echo "ANNOUNCE_RELEASE=1" >> $GITHUB_ENV | |
else | |
echo "ANNOUNCE_RELEASE=0" >> $GITHUB_ENV | |
fi | |
outputs: | |
announce: ${{ env.ANNOUNCE_RELEASE }} | |
announce-microblog: | |
name: Announce new release on farmOS-microblog | |
if: needs.publish-manifest.outputs.announce | |
needs: | |
- build | |
- release | |
- publish-manifest | |
uses: farmOS/farmOS-microblog/.github/workflows/create-message.yml@main | |
with: | |
message: '#farmOS ${{ needs.build.outputs.farmos_version }} has been released! https://github.com/farmOS/farmOS/releases/${{ needs.build.outputs.farmos_version }}' | |
secrets: | |
MICROBLOG_DEPLOY_KEY: ${{ secrets.MICROBLOG_DEPLOY_KEY }} | |
announce-discourse: | |
name: Announce new release on farmOS.discourse.group | |
if: needs.publish-manifest.outputs.announce | |
runs-on: ubuntu-latest | |
needs: | |
- build | |
- release | |
- publish-manifest | |
steps: | |
- name: Discourse API request | |
env: | |
DISCOURSE_API_KEY: ${{ secrets.DISCOURSE_API_KEY }} | |
run: | | |
curl --fail-with-body -X POST "https://farmos.discourse.group/posts/" \ | |
-H "Content-Type: application/json" \ | |
-H "Api-Key: ${DISCOURSE_API_KEY}" \ | |
-H "Api-Username: mstenta" \ | |
-d '{ | |
"title": "farmOS ${{ needs.build.outputs.farmos_version }} has been released", | |
"raw": "farmOS [${{ needs.build.outputs.farmos_version }}](https://github.com/farmOS/farmOS/releases/${{ needs.build.outputs.farmos_version }}) has been released.\n\nFor the full release notes, see [CHANGELOG.md](https://github.com/farmOS/farmOS/blob/${{ needs.build.outputs.farmos_version }}/CHANGELOG.md).", | |
"category": 7 | |
}' |