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
33 changes: 32 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ jobs:
run: bash bin/build-plugins.sh

- name: Inspect Push MD plugin zip
run: bin/inspect-push-md-zip.sh dist/plugins/push-md.zip
run: bash bin/inspect-push-md-zip.sh dist/plugins/push-md.zip

- name: Upload Push MD release asset
env:
Expand All @@ -98,6 +98,37 @@ jobs:
gh --version
gh release upload "$RELEASE_TAG" dist/plugins/push-md.zip --clobber

- name: Deploy Push MD to WordPress.org SVN
env:
WPORG_PLUGIN_SLUG: push-md
WPORG_USERNAME: ${{ secrets.WPORG_USERNAME }}
WPORG_PASSWORD: ${{ secrets.WPORG_PASSWORD }}
shell: bash
run: |
set -euo pipefail

if [ "${{ github.event.release.prerelease }}" = "true" ]; then
echo "Skipping WordPress.org SVN deploy for prerelease $RELEASE_TAG."
exit 0
fi

if [[ "${{ steps.release.outputs.version }}" == *-* ]]; then
echo "Skipping WordPress.org SVN deploy for non-stable release version ${{ steps.release.outputs.version }}."
exit 0
fi

if [ -z "$WPORG_USERNAME" ] || [ -z "$WPORG_PASSWORD" ]; then
echo "Skipping WordPress.org SVN deploy because WPORG_USERNAME or WPORG_PASSWORD is not configured."
exit 0
fi

if ! command -v svn >/dev/null 2>&1; then
sudo apt-get update
sudo apt-get install -y subversion
fi

bin/deploy-push-md-wporg-svn.sh dist/plugins/push-md.zip

# Temporarily disabled legacy release flow. Restore these sections when the
# repository release process should publish Composer packages, PHARs, examples,
# and the older plugin zips again.
Expand Down
194 changes: 194 additions & 0 deletions bin/deploy-push-md-wporg-svn.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
#!/usr/bin/env bash

set -euo pipefail

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

ZIP_PATH="${1:-$PROJECT_DIR/dist/plugins/push-md.zip}"
PLUGIN_SLUG="${WPORG_PLUGIN_SLUG:-push-md}"
SVN_URL="${WPORG_SVN_URL:-https://plugins.svn.wordpress.org/$PLUGIN_SLUG/}"
COMMIT_MESSAGE="${WPORG_COMMIT_MESSAGE:-}"
DRY_RUN="${WPORG_DRY_RUN:-0}"
SVN_DIR="${WPORG_SVN_DIR:-}"
USERNAME="${WPORG_USERNAME:-}"
PASSWORD="${WPORG_PASSWORD:-}"

TEMP_SVN_DIR=""
TEMP_EXTRACT_DIR=""

usage() {
cat <<USAGE
Usage: bin/deploy-push-md-wporg-svn.sh [dist/plugins/push-md.zip]

Deploys the Push MD release zip to the WordPress.org plugin SVN repository.

Environment:
WPORG_PLUGIN_SLUG Plugin slug. Default: push-md
WPORG_SVN_URL SVN URL. Default: https://plugins.svn.wordpress.org/\$WPORG_PLUGIN_SLUG/
WPORG_SVN_DIR Optional existing SVN checkout path.
WPORG_USERNAME WordPress.org SVN username.
WPORG_PASSWORD WordPress.org SVN password.
WPORG_COMMIT_MESSAGE Optional SVN commit message.
WPORG_DRY_RUN=1 Prepare the working copy and print status without committing.
USAGE
}

cleanup() {
if [ -n "$TEMP_EXTRACT_DIR" ] && [ -d "$TEMP_EXTRACT_DIR" ]; then
rm -rf "$TEMP_EXTRACT_DIR"
fi
if [ "$DRY_RUN" != "1" ] && [ -n "$TEMP_SVN_DIR" ] && [ -d "$TEMP_SVN_DIR" ]; then
rm -rf "$TEMP_SVN_DIR"
fi
}
trap cleanup EXIT

fail() {
echo "$1" >&2
exit 1
}

require_command() {
if ! command -v "$1" >/dev/null 2>&1; then
fail "Missing required command: $1"
fi
}

trim_carriage_returns() {
tr -d '\r'
}

if [ "${1:-}" = "--help" ] || [ "${1:-}" = "-h" ]; then
usage
exit 0
fi

require_command svn
require_command unzip
require_command zipinfo
require_command rsync

if [ ! -f "$ZIP_PATH" ]; then
fail "Missing Push MD release zip: $ZIP_PATH"
fi

ZIP_CONTENTS="$( zipinfo -1 "$ZIP_PATH" )"

TOP_LEVEL_DIRS="$( printf '%s\n' "$ZIP_CONTENTS" | sed 's#/.*##' | sort -u )"
TOP_LEVEL_DIR_COUNT="$( printf '%s\n' "$TOP_LEVEL_DIRS" | grep -c . || true )"
if [ "$TOP_LEVEL_DIR_COUNT" -ne 1 ]; then
fail "Expected exactly one top-level directory in $ZIP_PATH."
fi

PACKAGE_ROOT="$TOP_LEVEL_DIRS"
if [ "$PACKAGE_ROOT" != "$PLUGIN_SLUG" ]; then
fail "Expected zip top-level directory '$PLUGIN_SLUG', found '$PACKAGE_ROOT'."
fi

README_PATH="$PACKAGE_ROOT/readme.txt"
PLUGIN_FILE_PATH="$PACKAGE_ROOT/$PLUGIN_SLUG.php"

if ! grep -Fxq "$README_PATH" <<< "$ZIP_CONTENTS"; then
fail "Missing $README_PATH in $ZIP_PATH"
fi
if ! grep -Fxq "$PLUGIN_FILE_PATH" <<< "$ZIP_CONTENTS"; then
fail "Missing $PLUGIN_FILE_PATH in $ZIP_PATH"
fi

STABLE_TAG="$(
unzip -p "$ZIP_PATH" "$README_PATH" |
sed -n 's/^Stable tag:[[:space:]]*//p' |
trim_carriage_returns |
head -n 1
)"
PLUGIN_VERSION="$(
unzip -p "$ZIP_PATH" "$PLUGIN_FILE_PATH" |
sed -n 's/^[[:space:]]*\*[[:space:]]*Version:[[:space:]]*//p' |
trim_carriage_returns |
head -n 1
)"

if [ -z "$STABLE_TAG" ]; then
fail "Unable to read Stable tag from $README_PATH"
fi
if [ -z "$PLUGIN_VERSION" ]; then
fail "Unable to read Version from $PLUGIN_FILE_PATH"
fi
if [ "$STABLE_TAG" != "$PLUGIN_VERSION" ]; then
fail "Version mismatch: readme Stable tag is $STABLE_TAG, plugin Version is $PLUGIN_VERSION"
fi
if [[ ! "$STABLE_TAG" =~ ^[0-9]+(\.[0-9]+)+$ ]]; then
fail "WordPress.org SVN release tags must use numbers and periods only. Refusing to deploy: $STABLE_TAG"
fi

VERSION="$STABLE_TAG"
if [ -z "$COMMIT_MESSAGE" ]; then
COMMIT_MESSAGE="Release Push MD $VERSION"
fi

SVN_AUTH_ARGS=()
if [ -n "$USERNAME" ]; then
SVN_AUTH_ARGS+=( --username "$USERNAME" )
fi
if [ -n "$PASSWORD" ]; then
if [ -z "$USERNAME" ]; then
fail "WPORG_PASSWORD was provided without WPORG_USERNAME."
fi
SVN_AUTH_ARGS+=( --password "$PASSWORD" --no-auth-cache )
fi
if [ "${CI:-}" = "true" ] || [ -n "$PASSWORD" ]; then
SVN_AUTH_ARGS+=( --non-interactive )
fi

if [ -z "$SVN_DIR" ]; then
TEMP_SVN_DIR="$(mktemp -d "${TMPDIR:-/tmp}/push-md-wporg-svn.XXXXXX")"
SVN_DIR="$TEMP_SVN_DIR"
fi
TEMP_EXTRACT_DIR="$(mktemp -d "${TMPDIR:-/tmp}/push-md-wporg-zip.XXXXXX")"

if [ -d "$SVN_DIR/.svn" ]; then
echo "Updating existing SVN checkout: $SVN_DIR"
svn update "${SVN_AUTH_ARGS[@]}" "$SVN_DIR"
else
echo "Checking out WordPress.org SVN repository: $SVN_URL"
rm -rf "$SVN_DIR"
svn checkout "${SVN_AUTH_ARGS[@]}" "$SVN_URL" "$SVN_DIR"
fi

mkdir -p "$SVN_DIR/trunk" "$SVN_DIR/tags" "$SVN_DIR/assets"

if [ -e "$SVN_DIR/tags/$VERSION" ]; then
fail "SVN tag already exists: tags/$VERSION"
fi

echo "Unpacking $ZIP_PATH for Push MD $VERSION"
unzip -q "$ZIP_PATH" -d "$TEMP_EXTRACT_DIR"

find "$SVN_DIR/trunk" -mindepth 1 -maxdepth 1 ! -name '.svn' -exec rm -rf {} +
rsync -a --delete "$TEMP_EXTRACT_DIR/$PACKAGE_ROOT/" "$SVN_DIR/trunk/"

cd "$SVN_DIR"

svn add --force trunk tags assets --quiet

svn status trunk | awk '$1 == "!" { print substr($0, 9) }' | while IFS= read -r missing_path; do
if [ -n "$missing_path" ]; then
svn delete --force "$missing_path" >/dev/null
fi
done

svn copy trunk "tags/$VERSION" >/dev/null

echo "Prepared WordPress.org SVN release:"
svn status

if [ "$DRY_RUN" = "1" ]; then
echo "WPORG_DRY_RUN=1; not committing."
if [ -n "$TEMP_SVN_DIR" ]; then
echo "SVN working copy left at: $SVN_DIR"
fi
exit 0
fi

svn commit "${SVN_AUTH_ARGS[@]}" -m "$COMMIT_MESSAGE"
30 changes: 28 additions & 2 deletions plugins/push-md/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,13 +237,15 @@ dist/plugins/push-md.zip
```

`bin/build-plugins.sh` copies `plugins/push-md/`, excludes development-only
paths, adds `dist/php-toolkit.phar`, and zips the result. It excludes:
paths, adds the scoped readable `php-toolkit/` runtime, and zips the result.
It excludes:

- `Tests/`
- `docker-demo/`
- `docs/`
- `blueprint-e2e.json`
- `push-md-dev-bootstrap.php`
- `push-md-phar-bootstrap.php`

Inspect the release zip before submission:

Expand All @@ -252,7 +254,31 @@ zipinfo -1 dist/plugins/push-md.zip
```

The zip should include `readme.txt`, `uninstall.php`, admin assets, plugin PHP
files, `push-md-phar-bootstrap.php`, and `php-toolkit.phar`.
files, `push-md-toolkit-bootstrap.php`, and `php-toolkit/`.

## Publish To WordPress.org SVN

Use the built release zip as the source of truth for WordPress.org:

```bash
WPORG_USERNAME='<wordpress.org-username>' \
WPORG_PASSWORD='<svn-password>' \
bin/deploy-push-md-wporg-svn.sh dist/plugins/push-md.zip
```

The script validates that `readme.txt` and `push-md.php` use the same release
version, checks out `https://plugins.svn.wordpress.org/push-md/`, unpacks the
contents of the zip's top-level `push-md/` directory into SVN `trunk/`, creates
`tags/<version>` from `trunk/`, and commits the release. Use
`WPORG_DRY_RUN=1` to prepare and inspect the SVN working copy without
committing.

The GitHub release workflow in `.github/workflows/publish.yml` can run the same
script after uploading `push-md.zip`. Configure repository secrets named
`WPORG_USERNAME` and `WPORG_PASSWORD` to enable it. The workflow skips
WordPress.org deployment for prereleases, release versions with suffixes such
as `1.2.3-beta`, and releases where those secrets are absent, so GitHub release
assets can still be published independently.

## Local Verification

Expand Down
22 changes: 10 additions & 12 deletions plugins/push-md/docs/landing/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,11 @@
<a href="#faq">FAQ</a>
<a href="https://github.com/Automattic/php-toolkit/tree/trunk/plugins/push-md/docs">Docs</a>
</nav>
<a class="button button-primary" href="https://github.com/Automattic/php-toolkit/releases/latest/download/push-md.zip">
<svg class="button-icon octicon octicon-download" viewBox="0 0 16 16" aria-hidden="true" focusable="false">
<path d="M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14Z"></path>
<path d="M7.25 7.689V2a.75.75 0 0 1 1.5 0v5.689l1.97-1.969a.749.749 0 1 1 1.06 1.06l-3.25 3.25a.749.749 0 0 1-1.06 0L4.22 6.78a.749.749 0 1 1 1.06-1.06l1.97 1.969Z"></path>
<a class="button button-primary" href="https://wordpress.org/plugins/push-md/">
<svg class="button-icon octicon octicon-plus-circle" viewBox="0 0 16 16" aria-hidden="true" focusable="false">
<path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm7.25-3.25a.75.75 0 0 0-1.5 0v2.5h-2.5a.75.75 0 0 0 0 1.5h2.5v2.5a.75.75 0 0 0 1.5 0v-2.5h2.5a.75.75 0 0 0 0-1.5h-2.5Z"></path>
</svg>
<span>Download plugin</span>
<span>Install plugin</span>
</a>
</header>

Expand All @@ -59,12 +58,11 @@ <h1 id="hero-title"><span class="md-token">#</span> Markdown in Git. WordPress i
revisions, rejects stale pushes, and lets WordPress render the site.
</p>
<div class="hero-actions" aria-label="Primary actions">
<a class="button button-primary" href="https://github.com/Automattic/php-toolkit/releases/latest/download/push-md.zip">
<svg class="button-icon octicon octicon-download" viewBox="0 0 16 16" aria-hidden="true" focusable="false">
<path d="M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14Z"></path>
<path d="M7.25 7.689V2a.75.75 0 0 1 1.5 0v5.689l1.97-1.969a.749.749 0 1 1 1.06 1.06l-3.25 3.25a.749.749 0 0 1-1.06 0L4.22 6.78a.749.749 0 1 1 1.06-1.06l1.97 1.969Z"></path>
<a class="button button-primary" href="https://wordpress.org/plugins/push-md/">
<svg class="button-icon octicon octicon-plus-circle" viewBox="0 0 16 16" aria-hidden="true" focusable="false">
<path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm7.25-3.25a.75.75 0 0 0-1.5 0v2.5h-2.5a.75.75 0 0 0 0 1.5h2.5v2.5a.75.75 0 0 0 1.5 0v-2.5h2.5a.75.75 0 0 0 0-1.5h-2.5Z"></path>
</svg>
<span>Download plugin</span>
<span>Install plugin</span>
</a>
<a class="button button-secondary" href="https://github.com/Automattic/php-toolkit/tree/trunk/plugins/push-md/docs">Read docs</a>
</div>
Expand Down Expand Up @@ -291,13 +289,13 @@ <h2 id="install-title"><span class="md-token">##</span> Clone WordPress like a G
<ol class="install-steps">
<li>Try the read-only public remote from this site.</li>
<li>Open the Markdown files with an editor or agent.</li>
<li>Install the plugin on your WordPress site when you are ready to accept pushes.</li>
<li><a href="https://wordpress.org/plugins/push-md/">Install Push MD from WordPress.org</a> on your site when you are ready to accept pushes.</li>
</ol>
<div class="code-block">
<code id="clone-command">git clone https://pushmd.blog/wp-json/git/v1/md.git my-site</code>
<button class="copy-button" type="button" data-copy-target="clone-command">Copy</button>
</div>
<p class="install-note">The public remote is pullable for a first look. Pushes need the plugin on your own authenticated WordPress site.</p>
<p class="install-note">The public remote is pullable for a first look. Pushes need <a href="https://wordpress.org/plugins/push-md/">Push MD installed from WordPress.org</a> on your own authenticated WordPress site.</p>
</div>
</section>
</main>
Expand Down
Loading
Loading