Skip to content
Merged
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
14 changes: 14 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
extends: [ 'plugin:@wordpress/eslint-plugin/recommended' ],
rules: {
// @wordpress/* packages are WordPress runtime globals — not npm packages.
// They are resolved by webpack externals during build, not by Node.
'import/no-unresolved': [ 'error', { ignore: [ '^@wordpress/' ] } ],
},
overrides: [
{
files: [ '**/*.test.js' ],
env: { jest: true },
},
],
};
92 changes: 92 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
name: CI

on:
pull_request:
branches: [ main ]

jobs:

test-php:
name: PHP ${{ matrix.php }} / WP Latest
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
php: [ '8.2', '8.3' ]

services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=5s
--health-retries=3

steps:
- uses: actions/checkout@v6.0.2

- name: Set up PHP ${{ matrix.php }}
uses: shivammathur/setup-php@2.37.0
with:
php-version: ${{ matrix.php }}
extensions: mysqli
coverage: none

- name: Install Subversion
run: sudo apt-get update -q && sudo apt-get install -y subversion

- name: Install Composer dependencies
uses: ramsey/composer-install@4.0.0

- name: Install WordPress test library
run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 latest

- name: Run PHPUnit
run: vendor/bin/phpunit

test-js:
name: JS Tests
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v6.0.2

- name: Set up Node
uses: actions/setup-node@v6.3.0
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Run Jest
run: npm run test:unit

lint:
name: Lint
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v6.0.2

- name: Set up Node
uses: actions/setup-node@v6.3.0
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Lint JS
run: npm run lint:js

- name: Lint CSS
run: npm run lint:css
3 changes: 3 additions & 0 deletions .stylelintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dist/
gpse/build/
node_modules/
6 changes: 6 additions & 0 deletions .wp-env.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"core": null,
"plugins": [ "." ],
"themes": [],
"phpVersion": "8.2"
}
58 changes: 57 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ RED = \033[0;31m
NC = \033[0m # No Color

# Phony targets (not actual files)
.PHONY: all clean build version help
.PHONY: all clean build version help lint test test-js test-php

# Default target
all: build
Expand All @@ -31,6 +31,10 @@ help:
@echo " $(YELLOW)make$(NC) or $(YELLOW)make build$(NC) - Build and package the plugin"
@echo " $(YELLOW)make clean$(NC) - Remove dist/ directory"
@echo " $(YELLOW)make version$(NC) - Update version numbers interactively"
@echo " $(YELLOW)make lint$(NC) - Run JS and CSS linters (mirrors CI lint job)"
@echo " $(YELLOW)make test-js$(NC) - Run Jest unit tests (mirrors CI test-js job)"
@echo " $(YELLOW)make test-php$(NC) - Run PHPUnit via wp-env (mirrors CI test-php job)"
@echo " $(YELLOW)make test$(NC) - Run all tests (test-js + test-php)"
@echo " $(YELLOW)make help$(NC) - Show this help message"
@echo ""
@echo "$(GREEN)Current Configuration:$(NC)"
Expand Down Expand Up @@ -115,6 +119,58 @@ build: clean
@echo " 1. Upload $(ZIP_FILE) to WordPress"
@echo " 2. Or extract to wp-content/plugins/"

# Lint target - Run JS and CSS linters (mirrors CI lint job)
lint:
@echo "$(BLUE)Running linters$(NC)"
@echo ""
@if [ ! -d "node_modules" ]; then \
echo "$(YELLOW)Installing npm dependencies...$(NC)"; \
npm install; \
echo ""; \
fi
@echo "$(YELLOW)Linting JS...$(NC)"
@npm run lint:js
@echo "$(GREEN)✓ JS lint passed$(NC)"
@echo ""
@echo "$(YELLOW)Linting CSS...$(NC)"
@npm run lint:css
@echo "$(GREEN)✓ CSS lint passed$(NC)"
@echo ""
@echo "$(GREEN)✓ All linters passed$(NC)"

# test-js target - Run Jest unit tests (mirrors CI test-js job)
test-js:
@echo "$(BLUE)Running JS tests$(NC)"
@echo ""
@if [ ! -d "node_modules" ]; then \
echo "$(YELLOW)Installing npm dependencies...$(NC)"; \
npm install; \
echo ""; \
fi
@npm run test:unit
@echo "$(GREEN)✓ JS tests passed$(NC)"

# test-php target - Run PHPUnit in Docker (mirrors CI test-php job)
# Builds a PHP 8.2 container with all test dependencies pre-installed.
# WP test library is cached in a named Docker volume between runs.
test-php:
@echo "$(BLUE)Running PHP tests$(NC)"
@echo ""
@if ! command -v docker >/dev/null 2>&1; then \
echo "$(RED)✗ Error: Docker is required for PHP tests$(NC)"; \
exit 1; \
fi
@echo "$(YELLOW)Building test container (first run may take a minute)...$(NC)"
@docker compose -f docker-compose.test.yml build phpunit
@echo ""
@echo "$(YELLOW)Running PHPUnit...$(NC)"
@docker compose -f docker-compose.test.yml run --rm phpunit
@docker compose -f docker-compose.test.yml down
@echo "$(GREEN)✓ PHP tests passed$(NC)"

# test target - Run all tests
test: test-js test-php

# Version target - Update version numbers across files
version:
@echo "$(BLUE)Update GPSE Plugin Version$(NC)"
Expand Down
117 changes: 117 additions & 0 deletions bin/install-wp-tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/usr/bin/env bash
# Install WordPress and the WordPress test library.
# Usage: install-wp-tests.sh <db-name> <db-user> <db-pass> [db-host] [wp-version]

DB_NAME=${1:-wordpress_test}
DB_USER=${2:-root}
DB_PASS=${3:-}
DB_HOST=${4:-localhost}
WP_VERSION=${5:-latest}

TMPDIR=${TMPDIR-/tmp}
TMPDIR=$(echo "$TMPDIR" | sed -e 's/\/$//')
WP_TESTS_DIR=${WP_TESTS_DIR-$TMPDIR/wordpress-tests-lib}
WP_CORE_DIR=${WP_CORE_DIR-$TMPDIR/wordpress}

download() {
if command -v curl &>/dev/null; then
curl -s "$1" >"$2"
elif command -v wget &>/dev/null; then
wget -nv -O "$2" "$1"
fi
}

resolve_wp_tests_tag() {
if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+\-(beta|RC)[0-9]+$ ]]; then
WP_TESTS_TAG="branches/${WP_VERSION%-*}"
elif [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then
WP_TESTS_TAG="branches/$WP_VERSION"
elif [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+\.0$ ]]; then
WP_TESTS_TAG="branches/${WP_VERSION%.*}"
else
WP_TESTS_TAG="tags/$WP_VERSION"
fi
elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
WP_TESTS_TAG="trunk"
else
download https://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | head -1 | sed 's/"version":"//')
if [[ -z "$LATEST_VERSION" ]]; then
echo "Could not determine latest WordPress version."
exit 1
fi
WP_TESTS_TAG="tags/$LATEST_VERSION"
fi
}

install_wp() {
if [ -d "$WP_CORE_DIR" ]; then return; fi
mkdir -p "$WP_CORE_DIR"

if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
mkdir -p "$TMPDIR/wordpress-trunk"
svn export --quiet https://core.svn.wordpress.org/trunk "$TMPDIR/wordpress-trunk/wordpress"
mv "$TMPDIR/wordpress-trunk/wordpress" "$WP_CORE_DIR"
else
local ARCHIVE=${WP_VERSION/latest/latest}
[[ $WP_VERSION != 'latest' ]] && ARCHIVE="wordpress-${WP_VERSION}"
download "https://wordpress.org/${ARCHIVE}.tar.gz" "$TMPDIR/wordpress.tar.gz"
tar --strip-components=1 -zxmf "$TMPDIR/wordpress.tar.gz" -C "$WP_CORE_DIR"
fi
}

install_test_suite() {
if [[ $(uname -s) == 'Darwin' ]]; then
local ioption='-i .bak'
else
local ioption='-i'
fi

if [ ! -d "$WP_TESTS_DIR/includes" ]; then
mkdir -p "$WP_TESTS_DIR"
svn co --quiet "https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/" "$WP_TESTS_DIR/includes"
svn co --quiet "https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/" "$WP_TESTS_DIR/data"
fi

if [ ! -f "$WP_TESTS_DIR/wp-tests-config.php" ]; then
download "https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php" "$WP_TESTS_DIR/wp-tests-config.php"
WP_CORE_DIR_TRIMMED=$(echo "$WP_CORE_DIR" | sed 's:/*$::')
sed $ioption "s:dirname( __FILE__ ) . '/src/':'${WP_CORE_DIR_TRIMMED}/':" "$WP_TESTS_DIR/wp-tests-config.php"
sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR/wp-tests-config.php"
sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR/wp-tests-config.php"
sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR/wp-tests-config.php"
sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR/wp-tests-config.php"
fi
}

install_db() {
local PARTS
IFS=':' read -ra PARTS <<< "$DB_HOST"
local DB_HOSTNAME=${PARTS[0]}
local DB_PORT=${PARTS[1]}
local EXTRA=""

# MariaDB client tries to verify the server SSL cert by default and fails
# on self-signed certs; --skip-ssl disables SSL for MariaDB.
# MySQL 8.0+ client uses ssl-mode=PREFERRED by default (SSL without cert
# verification), which is required for caching_sha2_password auth to work.
local SSL_OPT=""
if mysqladmin --version 2>/dev/null | grep -qi "MariaDB"; then
SSL_OPT="--skip-ssl"
fi

if [ -n "$DB_PORT" ]; then
EXTRA=" --host=$DB_HOSTNAME --port=$DB_PORT --protocol=tcp $SSL_OPT"
elif [ -n "$DB_HOSTNAME" ]; then
EXTRA=" --host=$DB_HOSTNAME --protocol=tcp $SSL_OPT"
fi

mysqladmin create "$DB_NAME" --user="$DB_USER" --password="$DB_PASS" $EXTRA || true
}

set -ex
resolve_wp_tests_tag
install_wp
install_test_suite
install_db
18 changes: 18 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "aclabs/wp-gpse",
"description": "GPSE Search WordPress Plugin",
"license": "AGPL-3.0-or-later",
"require": {
"php": ">=8.2"
},
"require-dev": {
"phpunit/phpunit": "^9.6",
"yoast/phpunit-polyfills": "^3.0"
},
"config": {
"platform": {
"php": "8.2"
},
"allow-plugins": {}
}
}
Loading