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
59 changes: 24 additions & 35 deletions .github/workflows/deploy-wordpress-org.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "22"
cache: npm
cache-dependency-path: mailmojo/package-lock.json

- name: Setup PHP
uses: shivammathur/setup-php@v2
uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # v2.37.2
with:
php-version: "8.2"
coverage: none
Expand Down Expand Up @@ -74,52 +74,41 @@ jobs:
echo "ZIP_NAME=${ZIP_NAME}" >> "$GITHUB_ENV"

rm -rf release
mkdir -p release/mailmojo

rsync -a \
--exclude '.*' \
--exclude 'node_modules/' \
--exclude 'src/' \
--exclude 'composer.lock' \
--exclude 'package.json' \
--exclude 'package-lock.json' \
--exclude 'phpcs.xml' \
--exclude 'test/' \
--exclude 'tests/' \
--exclude 'Test/' \
--exclude 'Tests/' \
--exclude 'docs/' \
--exclude '*.md' \
--exclude '*.sh' \
--exclude 'Dockerfile' \
--exclude '*.dist' \
mailmojo/ release/mailmojo/

test -f release/mailmojo/mailmojo.php
test -d release/mailmojo/build
test -d release/mailmojo/includes
test -d release/mailmojo/assets
test -d release/mailmojo/vendor
test -f release/mailmojo/readme.txt
bin/stage-release.sh release/mailmojo

# Zip and upload before verifying, so a failed release still leaves an
# artifact to download and inspect. The deploy step below only runs when
# every preceding step succeeded, so verification still gates the release.
- name: Create release zip
run: |
set -euo pipefail

ZIP_NAME="mailmojo-${GITHUB_REF_NAME#v}.zip"
(cd release && zip -qr "../${ZIP_NAME}" mailmojo)

unzip -l "${ZIP_NAME}" | grep -E 'mailmojo/(mailmojo\.php|readme\.txt|build/|includes/|assets/|vendor/)' >/dev/null

- name: Upload release zip
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: mailmojo-${{ github.ref_name }}
path: ${{ env.ZIP_NAME }}
if-no-files-found: error
if-no-files-found: warn

- name: Verify staged package
run: bin/verify-release.sh release/mailmojo

- name: Verify release zip
run: |
set -euo pipefail

rm -rf zip-check
mkdir -p zip-check
unzip -q "${ZIP_NAME}" -d zip-check
bin/verify-release.sh zip-check/mailmojo
rm -rf zip-check

- name: Deploy to WordPress.org
uses: 10up/action-wordpress-plugin-deploy@2.3.0
uses: 10up/action-wordpress-plugin-deploy@54bd289b8525fd23a5c365ec369185f2966529c2 # 2.3.0
env:
SLUG: mailmojo
BUILD_DIR: release/mailmojo
Expand Down
81 changes: 81 additions & 0 deletions .github/workflows/verify-package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Verify Release Package

# Dry run of the release packaging on every change, so a packaging regression is
# caught here instead of at tag time. Uses the same bin/stage-release.sh and
# bin/verify-release.sh as .github/workflows/deploy-wordpress-org.yml.

on:
pull_request:
push:
branches:
- main
workflow_dispatch:

permissions:
contents: read

concurrency:
group: verify-package-${{ github.ref }}
cancel-in-progress: true

jobs:
verify:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "22"
cache: npm
cache-dependency-path: mailmojo/package-lock.json

- name: Setup PHP
uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # v2.37.2
with:
php-version: "8.2"
coverage: none

- name: Install Node dependencies
run: npm ci --prefix mailmojo

- name: Build plugin assets
run: npm run build --prefix mailmojo

- name: Install Composer dependencies
run: composer install --working-dir=mailmojo --no-dev --prefer-dist --no-interaction --no-progress --optimize-autoloader

- name: Stage release package
run: bin/stage-release.sh release/mailmojo

# Zip before verifying, so a failing verification still leaves an artifact
# to download and inspect.
- name: Create release zip
run: |
set -euo pipefail

(cd release && zip -qr ../mailmojo-package-check.zip mailmojo)

- name: Upload package for inspection
if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: mailmojo-package-check
path: mailmojo-package-check.zip
if-no-files-found: warn
retention-days: 7

- name: Verify staged package
run: bin/verify-release.sh release/mailmojo

- name: Verify release zip
run: |
set -euo pipefail

rm -rf zip-check
mkdir -p zip-check
unzip -q mailmojo-package-check.zip -d zip-check
bin/verify-release.sh zip-check/mailmojo
28 changes: 8 additions & 20 deletions bin/package-plugin.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#!/usr/bin/env bash
set -euo pipefail

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "${REPO_ROOT}"

VERSION="$(sed -n 's/^[[:space:]]*\* Version:[[:space:]]*//p' mailmojo/mailmojo.php | head -n 1 | xargs)"
ZIP_NAME="dist/mailmojo-${VERSION}.zip"

Expand All @@ -12,26 +15,11 @@ npm run build --prefix mailmojo
mkdir -p dist
rm -f "${ZIP_NAME}"
rm -rf release
mkdir -p release/mailmojo

rsync -a \
--exclude '.*' \
--exclude 'node_modules/' \
--exclude '/src/' \
--exclude 'composer.lock' \
--exclude 'package.json' \
--exclude 'package-lock.json' \
--exclude 'phpcs.xml' \
--exclude 'test/' \
--exclude 'tests/' \
--exclude 'Test/' \
--exclude 'Tests/' \
--exclude 'docs/' \
--exclude '*.md' \
--exclude '*.sh' \
--exclude 'Dockerfile' \
--exclude '*.dist' \
mailmojo/ release/mailmojo/

# Staging and verification are shared with the WordPress.org deploy workflow so
# the zip built here matches what actually gets released.
bin/stage-release.sh release/mailmojo
bin/verify-release.sh release/mailmojo

(cd release && zip -qr "$(pwd)/../${ZIP_NAME}" mailmojo)

Expand Down
62 changes: 62 additions & 0 deletions bin/stage-release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env bash
#
# Stage the distributable plugin directory.
#
# This is the single source of truth for what ships to WordPress.org, shared by
# bin/package-plugin.sh (local zips) and .github/workflows/deploy-wordpress-org.yml
# (the actual release). Keep the exclude list here and nowhere else.
#
# Usage: bin/stage-release.sh [DEST_DIR]
#
set -euo pipefail

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SOURCE_DIR="${REPO_ROOT}/mailmojo"
DEST_DIR="${1:-${REPO_ROOT}/release/mailmojo}"

if [ ! -f "${SOURCE_DIR}/mailmojo.php" ]; then
echo "Error: ${SOURCE_DIR}/mailmojo.php not found." >&2
exit 1
fi

if [ ! -f "${SOURCE_DIR}/vendor/autoload.php" ]; then
echo "Error: ${SOURCE_DIR}/vendor is missing. Run:" >&2
echo " composer install --working-dir=mailmojo --no-dev --optimize-autoloader" >&2
exit 1
fi

if [ ! -d "${SOURCE_DIR}/build" ]; then
echo "Error: ${SOURCE_DIR}/build is missing. Run: npm run build --prefix mailmojo" >&2
exit 1
fi

echo "Staging ${SOURCE_DIR} -> ${DEST_DIR}"

rm -rf "${DEST_DIR}"
mkdir -p "${DEST_DIR}"

# rsync pattern anchoring matters here. A pattern with a leading slash is
# anchored to the transfer root (the plugin directory); a pattern without one
# matches at *every* depth. Writing 'src/' instead of '/src/' silently deletes
# vendor/*/src -- i.e. every Guzzle and PSR class -- and produces a plugin that
# fatals on load. Anything meant to match only the plugin root is anchored below.
rsync -a \
--exclude '.*' \
--exclude 'node_modules/' \
--exclude '/src/' \
--exclude '/composer.lock' \
--exclude '/package.json' \
--exclude '/package-lock.json' \
--exclude '/phpcs.xml' \
--exclude 'test/' \
--exclude 'tests/' \
--exclude 'Test/' \
--exclude 'Tests/' \
--exclude 'docs/' \
--exclude '*.md' \
--exclude '*.sh' \
--exclude 'Dockerfile' \
--exclude '*.dist' \
"${SOURCE_DIR}/" "${DEST_DIR}/"

echo "Staged $(find "${DEST_DIR}" -type f | wc -l | xargs) files."
Loading