diff --git a/.github/scripts/verify-release-metadata.sh b/.github/scripts/verify-release-metadata.sh new file mode 100644 index 00000000..5b730ea4 --- /dev/null +++ b/.github/scripts/verify-release-metadata.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +set -euo pipefail + +fail() { + echo "$1" >&2 + exit 1 +} + +EXPECTED_VERSION="${1:-}" + +PLUGIN_VERSION="$(sed -n 's/^ \* Version: \(.*\)$/\1/p' load.php | head -n 1 | tr -d '\r')" +STABLE_TAG="$(sed -n 's/^Stable tag:[[:space:]]*//p' readme.txt | head -n 1 | tr -d '\r')" +CONSTANT_VERSION="$(php -r "require 'version.php'; echo SQLITE_DRIVER_VERSION;")" + +[ -n "$PLUGIN_VERSION" ] || fail 'Could not extract the plugin version from load.php.' +[ -n "$STABLE_TAG" ] || fail 'Could not extract the Stable tag from readme.txt.' +[ -n "$CONSTANT_VERSION" ] || fail 'Could not extract SQLITE_DRIVER_VERSION from version.php.' + +[ "$PLUGIN_VERSION" = "$CONSTANT_VERSION" ] || fail "Version mismatch: load.php=$PLUGIN_VERSION, version.php=$CONSTANT_VERSION." +[ "$PLUGIN_VERSION" = "$STABLE_TAG" ] || fail "Version mismatch: load.php=$PLUGIN_VERSION, readme.txt Stable tag=$STABLE_TAG." + +if [ -n "$EXPECTED_VERSION" ] && [ "$PLUGIN_VERSION" != "$EXPECTED_VERSION" ]; then + fail "Version mismatch: expected $EXPECTED_VERSION, found $PLUGIN_VERSION in plugin metadata." +fi + +grep -Fxq '== Changelog ==' readme.txt || fail 'readme.txt is missing a == Changelog == section.' + +if ! awk -v version="$PLUGIN_VERSION" ' +BEGIN { + in_changelog = 0 + in_entry = 0 + has_content = 0 +} +$0 == "== Changelog ==" { + in_changelog = 1 + next +} +in_changelog && $0 == "= " version " =" { + in_entry = 1 + next +} +in_entry && $0 ~ /^= / { + exit has_content ? 0 : 1 +} +in_entry && $0 !~ /^[[:space:]]*$/ { + has_content = 1 +} +END { + if ( ! in_changelog || ! in_entry || ! has_content ) { + exit 1 + } +} +' readme.txt; then + fail "readme.txt must contain a changelog entry with content for version $PLUGIN_VERSION." +fi + +echo "Verified release metadata for version $PLUGIN_VERSION." diff --git a/.github/workflows/release-wordpress-org.yml b/.github/workflows/release-wordpress-org.yml new file mode 100644 index 00000000..b73eef72 --- /dev/null +++ b/.github/workflows/release-wordpress-org.yml @@ -0,0 +1,143 @@ +name: Release to WordPress.org + +on: + push: + tags: + - 'v*.*.*' + workflow_dispatch: + inputs: + tag: + description: Existing Git tag to deploy, for example v2.2.16 + required: true + type: string + +concurrency: + group: release-${{ github.event.inputs.tag || github.ref_name }} + cancel-in-progress: false + +jobs: + release: + if: github.repository == 'WordPress/sqlite-database-integration' + name: Deploy ${{ steps.release_meta.outputs.tag }} to WordPress.org + runs-on: ubuntu-latest + environment: WordPress.org + permissions: + contents: read + env: + SVN_URL: https://plugins.svn.wordpress.org/sqlite-database-integration + RELEASE_TAG: ${{ github.event.inputs.tag || github.ref_name }} + steps: + - name: Checkout release source + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.tag || github.ref }} + fetch-depth: 0 + clean: true + persist-credentials: false + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + coverage: none + + - name: Determine release metadata + id: release_meta + run: | + TAG="${RELEASE_TAG}" + if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Release tags must look like v2.2.19, got: $TAG" + exit 1 + fi + + VERSION="${TAG#v}" + echo "tag=$TAG" >> "$GITHUB_OUTPUT" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + + - name: Ensure the release commit is on main + run: | + git fetch origin main --depth=1 + RELEASE_SHA="$(git rev-parse HEAD)" + if ! git merge-base --is-ancestor "$RELEASE_SHA" origin/main; then + echo "Release commit must be reachable from origin/main." + exit 1 + fi + + - name: Verify release metadata + run: bash ./.github/scripts/verify-release-metadata.sh "${{ steps.release_meta.outputs.version }}" + + - name: Install Subversion + run: sudo apt-get update && sudo apt-get install -y subversion rsync + + - name: Build the plugin package + run: | + mkdir build + git archive --format=tar HEAD | tar -xf - -C build + test -f build/load.php + test -f build/readme.txt + test -f build/version.php + + - name: Checkout the WordPress.org SVN repository + run: svn checkout "$SVN_URL" svn-clone + + - name: Sync trunk and create the release tag + run: | + VERSION="${{ steps.release_meta.outputs.version }}" + + if [ -e "svn-clone/tags/$VERSION" ]; then + echo "The WordPress.org tag $VERSION already exists." + exit 1 + fi + + rsync -a --delete --exclude='.svn/' build/ svn-clone/trunk/ + mkdir -p "svn-clone/tags/$VERSION" + rsync -a --delete --exclude='.svn/' build/ "svn-clone/tags/$VERSION/" + + - name: Stage SVN changes + run: | + cd svn-clone + + while IFS= read -r line; do + status="${line:0:1}" + path="${line:8}" + + if [ -z "$path" ]; then + continue + fi + + case "$status" in + '?') + svn add --parents "$path" + ;; + '!') + svn delete "$path" + ;; + esac + done < <(svn status) + + echo "Pending SVN changes:" + svn status + + - name: Commit the WordPress.org release + env: + SVN_USERNAME: ${{ secrets.WPORG_SVN_USERNAME }} + SVN_PASSWORD: ${{ secrets.WPORG_SVN_PASSWORD }} + run: | + if [ -z "$SVN_USERNAME" ] || [ -z "$SVN_PASSWORD" ]; then + echo "Missing WordPress.org SVN credentials." + exit 1 + fi + + cd svn-clone + + if ! svn status | grep -q '.'; then + echo "No SVN changes to commit." + exit 1 + fi + + svn commit \ + -m "Release ${{ steps.release_meta.outputs.version }}" \ + --username "$SVN_USERNAME" \ + --password "$SVN_PASSWORD" \ + --non-interactive \ + --trust-server-cert-failures=unknown-ca,cn-mismatch,expired,not-yet-valid,other diff --git a/.github/workflows/verify-version.yml b/.github/workflows/verify-version.yml index 9bc9a617..155ff9af 100644 --- a/.github/workflows/verify-version.yml +++ b/.github/workflows/verify-version.yml @@ -1,4 +1,4 @@ -name: Verify plugin version +name: Verify plugin release metadata on: push: @@ -8,28 +8,16 @@ on: jobs: verify-version: - name: Assert the WordPress plugin header declares the same version as the SQLITE_DRIVER_VERSION constant + name: Assert the release metadata is internally consistent runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Extract version from "load.php" - id: load_version - run: | - VERSION=$(grep "Version:" load.php | sed "s/.*Version: \([^ ]*\).*/\1/") - echo "load_version=$VERSION" >> $GITHUB_OUTPUT + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + coverage: none - - name: Extract version from "version.php" - id: const_version - run: | - VERSION=$(php -r "require 'version.php'; echo SQLITE_DRIVER_VERSION;") - echo "const_version=$VERSION" >> $GITHUB_OUTPUT - - - name: Compare versions - run: | - if [ "${{ steps.load_version.outputs.load_version }}" != "${{ steps.const_version.outputs.const_version }}" ]; then - echo "Version mismatch detected!" - echo " load.php version: ${{ steps.load_version.outputs.load_version }}" - echo " version.php constant: ${{ steps.const_version.outputs.const_version }}" - exit 1 - fi + - name: Verify release metadata + run: bash ./.github/scripts/verify-release-metadata.sh diff --git a/readme.txt b/readme.txt index a1694b8b..d04f1185 100644 --- a/readme.txt +++ b/readme.txt @@ -37,11 +37,19 @@ Feedback is encouraged and much appreciated, especially since this plugin is a f Contributions are always welcome! Learn more about how to get involved in the [Core Performance Team Handbook](https://make.wordpress.org/performance/handbook/get-involved/). -= Does this plugin change how WordPress queries are executed? = - -The plugin replaces the default MySQL-based database layer with an -SQLite-backed implementation. Core WordPress code continues to use -the wpdb API, while queries are internally adapted to be compatible -with SQLite syntax and behavior. += Does this plugin change how WordPress queries are executed? = + +The plugin replaces the default MySQL-based database layer with an +SQLite-backed implementation. Core WordPress code continues to use +the wpdb API, while queries are internally adapted to be compatible +with SQLite syntax and behavior. + +== Changelog == + += 2.2.18 = + +* Improved PDO statement compatibility by implementing the fetchColumn() and fetchObject() methods. +* Hardened identifier and string escaping in the legacy SQLite driver. +* Refined project tooling and release automation for future plugin updates.