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
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
/docs export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/.travis.yml export-ignore
/.github export-ignore
/.tx export-ignore
/.scrutinizer.yml export-ignore
214 changes: 214 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
name: CI

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

jobs:
test:
name: SS${{ matrix.silverstripe }} / PHP ${{ matrix.php }}
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
include:
# One job per supported Silverstripe major, at the oldest and newest PHP that major is used
# with here. The module's composer.json is the source of truth for the supported range; this
# matrix must follow it.
- silverstripe: '5'
php: '8.1'
recipe: '^5'
testing: '^3'
- silverstripe: '5'
php: '8.3'
recipe: '^5'
testing: '^3'
- silverstripe: '6'
php: '8.3'
recipe: '^6'
testing: '^4'
- silverstripe: '6'
php: '8.4'
recipe: '^6'
testing: '^4'

services:
database:
# MariaDB rather than MySQL: it matches both the local dev machine and the Forge servers, so a
# version-specific failure here means something real.
image: mariadb:11.4
env:
MARIADB_ROOT_PASSWORD: root
MARIADB_DATABASE: ss_ci
ports:
- 3306:3306
options: >-
--health-cmd="healthcheck.sh --connect --innodb_initialized"
--health-interval=10s --health-timeout=5s --health-retries=10

steps:
- name: Check out the module
uses: actions/checkout@v4
with:
path: module

- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: mbstring, intl, pdo_mysql, mysqli, gd, zip, dom, xml, tokenizer, simplexml, ctype, hash, session
tools: composer:v2
coverage: none

- name: Build a host project
# The module cannot be tested on its own: it needs a booted Silverstripe app.
# The module is required through a PATH repository pointing at the checkout, and symlinked
# rather than mirrored ON PURPOSE - `/tests` is `export-ignore` in .gitattributes, so a dist or
# mirrored install contains no tests at all.
run: |
mkdir -p app-host
cd app-host
cat > composer.json <<JSON
{
"name": "restruct/ci-host",
"require": {
"silverstripe/recipe-cms": "${{ matrix.recipe }}",
"silverstripe/recipe-testing": "${{ matrix.testing }}",
"restruct/silverstripe-shortcodable": "*"
},
"repositories": [
{ "type": "path", "url": "../module", "options": { "symlink": true } }
],
"autoload-dev": {
"psr-4": {
"Shortcodable\\\\Tests\\\\": "vendor/restruct/silverstripe-shortcodable/tests/"
}
},
"minimum-stability": "dev",
"prefer-stable": true,
"config": { "allow-plugins": true }
}
JSON
# Silverstripe 5 is in security-fixes-only until its April 2027 EOL, and every release of it
# is covered by advisory PKSA-pjvm-vnw2-n3m2 (range <6.2.1), which will not be patched there.
# Composer therefore refuses to install it under the default policy.
# Blocking is disabled HERE ONLY, in a throwaway CI host project.
composer config policy.advisories.block false
if [ "${{ matrix.silverstripe }}" = "6" ]; then
# TinyMCE is a separate module on Silverstripe 6 and recipe-cms does not include it.
composer require --no-update silverstripe/htmleditor-tinymce:^1
# restruct/silverstripe-simpler 1.0.0 is released (2026-09-25), so ^1 now resolves from
# Packagist and CI proves the published constraint. The alias used until then is kept
# below, disabled:
# composer require --no-update "restruct/silverstripe-simpler:dev-main as 1.0.0"
fi
composer update --no-interaction --no-progress

- name: Configure the test suite
run: |
cd app-host
cat > phpunit.xml <<'XML'
<?xml version="1.0" encoding="UTF-8"?>
<!-- Warning-to-error escalation is the RUNNER's behaviour and differs by PHPUnit
major: 9 (SS5) converts warnings by default, 11 (SS6) has no such attribute.
failOnWarning is pinned so a warning behaves identically on every leg. -->
<phpunit bootstrap="vendor/silverstripe/framework/tests/bootstrap.php" colors="true"
failOnWarning="true">
<testsuites>
<testsuite name="shortcodable">
<directory>vendor/restruct/silverstripe-shortcodable/tests</directory>
</testsuite>
<testsuite name="consumer">
<directory>app/tests</directory>
</testsuite>
</testsuites>
</phpunit>
XML

- name: Add a consumer-shape database test
# An unbuildable fixture in this module's tests/ dir fatals the temp-database build in every
# CONSUMING project, and the module's own suite structurally cannot catch it (its fixtures are
# loaded by PHPUnit, not registered in the class manifest, so no tables are built for them).
run: |
mkdir -p app-host/app/tests
cat > app-host/app/tests/ConsumerDbTest.php <<'PHP'
<?php

use SilverStripe\Dev\SapphireTest;
use SilverStripe\Security\Member;

class ConsumerDbTest extends SapphireTest
{
protected $usesDatabase = true;

public function testTempDatabaseBuilds()
{
$m = Member::create(['FirstName' => 'x']);
$m->write();
$this->assertGreaterThan(0, $m->ID);
}
}
PHP

- name: Run tests
working-directory: app-host
env:
SS_DATABASE_CLASS: MySQLDatabase
SS_DATABASE_SERVER: 127.0.0.1
SS_DATABASE_PORT: 3306
SS_DATABASE_USERNAME: root
SS_DATABASE_PASSWORD: root
SS_DATABASE_NAME: ss_ci
SS_ENVIRONMENT_TYPE: dev
# The manifest is flushed differently per major:
# - Silverstripe 5 (framework 5 / PHPUnit 9): framework 5 does not read SS_PHPUNIT_FLUSH, only a
# `flush` argument, and that argument only works after a test PATH (next to --testsuite PHPUnit
# 9 takes `flush=1` for a file: 'Cannot open file "flush=1"'), so these legs run path-first.
# - Silverstripe 6 (PHPUnit 11): a `flush=1` argument is ignored; framework 6 reads
# SS_PHPUNIT_FLUSH instead, so it is set for those legs only.
run: |
if [ "${{ matrix.silverstripe }}" = "6" ]; then
SS_PHPUNIT_FLUSH=1 vendor/bin/phpunit --testsuite shortcodable
SS_PHPUNIT_FLUSH=1 vendor/bin/phpunit --testsuite consumer
else
vendor/bin/phpunit vendor/restruct/silverstripe-shortcodable/tests flush=1
vendor/bin/phpunit app/tests flush=1
fi

- name: Boot the app and build the database
# The suite proves the classes behave; this proves the module does not break a real boot.
working-directory: app-host
env:
SS_DATABASE_CLASS: MySQLDatabase
SS_DATABASE_SERVER: 127.0.0.1
SS_DATABASE_PORT: 3306
SS_DATABASE_USERNAME: root
SS_DATABASE_PASSWORD: root
SS_DATABASE_NAME: ss_ci
SS_ENVIRONMENT_TYPE: dev
run: |
if [ "${{ matrix.silverstripe }}" = "6" ]; then
vendor/bin/sake db:build --flush
else
vendor/bin/sake dev/build flush=1
fi

lint:
name: Lint PHP ${{ matrix.php }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# The floor and the ceiling of the module's declared php constraint.
php: ['8.1', '8.4']
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: none
- name: Syntax check every PHP file
run: find src tests -name '*.php' -print0 | xargs -0 -n1 php -l && php -l _config.php
36 changes: 0 additions & 36 deletions .travis.yml

This file was deleted.

53 changes: 53 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Changelog

## 5.1.0 (2026-09-25)

**One line for Silverstripe 5 and 6.** `main` now declares `silverstripe/framework ^5 || ^6` on PHP
`^8.1`. Silverstripe 4 is no longer supported or tested; the `4.x` tags stay available for projects
still on it. Upgrade notes: [UPGRADING.md](UPGRADING.md).

The placeholder image fix below was also released for the 4.x line as 4.0.17 (branch `v4`, formerly `ss4-5`).

### Fixed

- **The 5.0.x releases could not be installed from Packagist.** They required
`restruct/silverstripe-simpler ~1.0`, and simpler has no 1.x release, so Composer refused every
5.0.x tag. The constraint is now `~0.2 || ^1`: the simpler line matching each Silverstripe major.
- **Silverstripe 6 without `silverstripe/htmleditor-tinymce` fatal on every request** with
`Class "SilverStripe\TinyMCE\TinyMCEConfig" not found` from `_config.php`. `recipe-cms` 6 does not
include TinyMCE, so a default install hit this. The editor config is now fetched through
`HTMLEditorConfig::get()`, and the plugin and button are only added to a TinyMCE config
(`Shortcodable::is_tinymce_config()`); other editors are skipped.
- **The shortcode dialog's modal is loaded explicitly** through simpler's `AdminExtension` with
`simpler_include_modal: true`, as on the 4.x line. `simpler-silverstripe.js` on its own does not
provide `simpler.modal`, which the dialog uses.
- **The placeholder image endpoint (`admin/shortcodable/placehold.img`) validates and escapes its
parameters.** They were interpolated into the SVG unescaped. Sizes now accept a positive integer or
`100%`, colours 3 or 6 hex digits; anything else falls back to `default_placeholder`. Font and text
are escaped for XML. Upgrading is recommended.
- **Placeholder text with non-ASCII characters no longer breaks the SVG.** `htmlentities()` produced
HTML named entities such as `&eacute;`, which XML does not define.

### Changed

- `ShortcodableAdminController::shortcodePlaceholderImage()` returns its `HTTPResponse` instead of
calling `output()` itself.
- The editor stylesheet is registered on whichever `TinyMCEConfig` class the installed Silverstripe
provides (`SilverStripe\Forms\HTMLEditor\TinyMCEConfig` on 5, `SilverStripe\TinyMCE\TinyMCEConfig`
on 6).
- `composer.json`: `silverstripe/vendor-plugin ^2 || ^3`, explicit `php ^8.1`, a `suggest` for
`silverstripe/htmleditor-tinymce`, and a `funding` entry.
- `composer.json` requires `silverstripe/admin ^2 || ^3`. The module's config and controller build on
`LeftAndMain`, which is part of admin, not framework; it was previously only pulled in indirectly.

### Added

- A behavioural PHPUnit suite (registration, tag and label maps, the TinyMCE button, the block-level
wrapper rewrite, the admin endpoints and their permission check), run by GitHub Actions against
Silverstripe 5 and 6. The Silverstripe 3 era `.travis.yml` is removed.
- README: requirements, every configuration option with its default, and how to run the tests.

## 5.0.0 - 5.0.5

Silverstripe 6 only, with TinyMCE 6 selection handling and inline Elemental editor placeholder fixes.
Not installable from Packagist (see 5.1.0).
Loading
Loading