Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
2588cbc
Create action file, checkout repositories
strangerkir Feb 19, 2026
52ddd8b
Update job name
strangerkir Feb 20, 2026
66aa793
Move env vars to the job level
strangerkir Feb 20, 2026
8b54ab4
Install required tools before synchronizing repos
strangerkir Feb 20, 2026
2f1aa34
Remove extra env var
strangerkir Feb 20, 2026
8a4cf80
Move checking out git to the sync action
strangerkir Feb 20, 2026
b777183
Install required tools first
strangerkir Feb 20, 2026
9d0b0ec
Create directory in a safer way
strangerkir Feb 20, 2026
6c74c55
Use rsync to synchronize SVN with git (WIP)
strangerkir Feb 20, 2026
ccaba39
Use official stable version of checkout action
strangerkir Feb 20, 2026
9016f32
Remove extra echo - step name already has it
strangerkir Feb 20, 2026
f68aa6c
Keep both SVN username and password as secrets
strangerkir Feb 20, 2026
08424a8
Remove extra else
strangerkir Mar 2, 2026
8b76efa
Do not add readme.txt to excludes list
strangerkir Mar 2, 2026
0f86d3d
Temporarily define env vars in an extra step
strangerkir Mar 2, 2026
6e32ff3
Update SVN tracking: add new files and delete removed ones
strangerkir Mar 2, 2026
a015e3a
Add test mode input and prepare dry-run step
strangerkir Mar 2, 2026
4136154
Compress svn trunk and upload as an artifact
strangerkir Mar 3, 2026
0a414be
Remove 'custom SVN repository' feature
strangerkir Mar 3, 2026
69322e6
Update comment
strangerkir Mar 3, 2026
66499ec
Make shell fail early on errors
strangerkir Mar 3, 2026
7bdc46b
Update comment - more concise and better example
strangerkir Mar 4, 2026
0df79c1
Rename TEST_MODE to DRY_RUN
strangerkir Mar 4, 2026
b7ea83f
Add IDE's directories to exclusions
strangerkir Mar 4, 2026
26def67
Merge branch 'main' into feature/SPP-91-wordpress-org-release
strangerkir Mar 4, 2026
9dc8ad8
Exclude .distignore file itself
strangerkir Mar 4, 2026
1c86daa
Make sure we have right paths when updating trunk
strangerkir Mar 4, 2026
64ab47e
Remove debug code
strangerkir Mar 5, 2026
77c418e
Add TAG input for both Git and SVN
strangerkir Mar 5, 2026
41c9145
Create SVN tag
strangerkir Mar 5, 2026
41ee1d6
Use separate inputs for plugin version and git ref
strangerkir Mar 11, 2026
46c3a73
Only checkout top-level dirs and trunk contents
strangerkir Mar 12, 2026
bef91db
Add ssh-key to the checkout action
strangerkir Mar 12, 2026
592dd13
Update comments
strangerkir Mar 12, 2026
d748fb5
Update descriptions
strangerkir Mar 12, 2026
66a87ee
Use env var for trunk path
strangerkir Mar 12, 2026
e0e4deb
Quote variables
strangerkir Mar 12, 2026
734a42e
Check for deleted files before removing them
strangerkir Mar 12, 2026
484dc7c
Make sure we are only operate on trunk
strangerkir Mar 12, 2026
59830c1
Remove debugging code
strangerkir Mar 12, 2026
1dbefce
Make sure version doesn't exist yet in SVN
strangerkir Mar 12, 2026
1e64f49
Make sure variable is safely limited
strangerkir Mar 12, 2026
5601a6f
Add committing to WordPress.org
strangerkir Mar 12, 2026
cd13f1c
Use env: to set env variables at job level
strangerkir Mar 12, 2026
5a65ef0
Fix verifying SVN version doesn't exist
strangerkir Mar 12, 2026
f1799b5
Update comments
strangerkir Mar 12, 2026
92d05cd
Use github.workspace instead of runner.workspace
strangerkir Mar 12, 2026
193fdfe
Add missing secret input
strangerkir Mar 12, 2026
9dc4e25
Add comment to clarify intentions
strangerkir Mar 12, 2026
0596f59
Fix and improve comment
strangerkir Mar 12, 2026
a6cfc7a
Merge branch 'main' into feature/SPP-91-wordpress-org-release
strangerkir Apr 22, 2026
25fdc5f
Check that versions match in all sources
strangerkir Apr 28, 2026
7372049
Split workflow into two jobs
strangerkir Apr 28, 2026
3618ab4
Only explicitly exclude sensitive files and .svn
strangerkir Apr 28, 2026
da3e14c
Remove check for SVN conflicts
strangerkir Apr 28, 2026
7cf7599
Merge branch 'main' into feature/SPP-91-wordpress-org-release
strangerkir May 7, 2026
1cc8ec1
Revert "Split workflow into two jobs"
strangerkir May 11, 2026
cb95e4d
Merge remote-tracking branch 'origin/feature/SPP-91-wordpress-org-rel…
strangerkir May 11, 2026
5e930b7
Make creating a tag conditional
strangerkir May 11, 2026
02357c2
Remove extra new line
strangerkir May 11, 2026
d3a463b
Skip version check when updating trunk only
strangerkir May 11, 2026
513b778
Remove extra space
strangerkir May 11, 2026
a9414c5
Add documentation
strangerkir May 11, 2026
3c4f149
Merge branch 'main' into feature/SPP-91-wordpress-org-release
strangerkir May 12, 2026
3093a63
Update documentation
strangerkir May 12, 2026
94a0e03
Update documentation
strangerkir May 12, 2026
d3bb7a6
Merge remote-tracking branch 'origin/feature/SPP-91-wordpress-org-rel…
strangerkir May 12, 2026
42464c4
Update documentation
strangerkir May 12, 2026
736ff07
Add plugin slug validation
strangerkir May 12, 2026
8b570af
Update documentation
strangerkir May 12, 2026
7732f43
Merge branch 'main' into feature/SPP-91-wordpress-org-release
Biont Jun 9, 2026
6b113cc
Merge branch 'main' into feature/SPP-91-wordpress-org-release
Biont Jul 14, 2026
53d0c0c
Merge branch 'main' into feature/SPP-91-wordpress-org-release
strangerkir Jul 14, 2026
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
261 changes: 261 additions & 0 deletions .github/workflows/wordpress-org-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json

name: wordpress.org publishing

on:
workflow_call:
inputs:
SVN_PLUGIN_SLUG:
description: "WordPress.org plugin slug (e.g., 'woocommerce')"
type: string
required: true

PLUGIN_VERSION:
description: "Plugin version to publish (MAJOR.MINOR.PATCH)"
type: string
required: true
Comment thread
Biont marked this conversation as resolved.

GIT_REF:
description: "Git ref to publish (tag, branch, or commit)"
type: string
required: true

DRY_RUN:
description: "Create artifact from trunk instead of committing to SVN"
type: boolean
default: false
required: false

UPDATE_TRUNK_ONLY:
description: "Only update trunk at wordpress.org, but don't create a new tag (version)"
type: boolean
default: true
required: false

secrets:
SVN_USERNAME:
required: true

SVN_PASSWORD:
required: true

GITHUB_USER_SSH_KEY:
required: true

jobs:
update_svn_from_git:
env:
SVN_REPO_PATH: "${{ github.workspace }}/svn_repository"
SVN_REPO_ROOT: "${{ github.workspace }}/svn_repository/${{ inputs.SVN_PLUGIN_SLUG }}"
runs-on: ubuntu-latest
steps:
- name: Install required tools
run: |
sudo apt-get update -y
sudo apt-get install -y subversion rsync

- name: Validate plugin slug
env:
SVN_PLUGIN_SLUG: ${{ inputs.SVN_PLUGIN_SLUG }}
run: |
set -euo pipefail

if [[ ! "$SVN_PLUGIN_SLUG" =~ ^[a-z0-9-]+$ ]]; then
echo "❌ Invalid plugin slug: $SVN_PLUGIN_SLUG"
echo " WordPress.org slugs may only contain lowercase letters, numbers, and hyphens"
exit 1
fi

echo "✅ Valid plugin slug: $SVN_PLUGIN_SLUG"

- name: Validate versions
env:
PLUGIN_VERSION: ${{ inputs.PLUGIN_VERSION }}
GIT_REF: ${{ inputs.GIT_REF }}
run: |
set -euo pipefail

if [[ ! "$PLUGIN_VERSION" =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then
echo "❌ WordPress.org expects version formatted as MAJOR.MINOR.PATCH"
echo " Three groups of numbers separated by dots"
echo " Each group: either 0 or digits not starting with 0"
echo " Received: $PLUGIN_VERSION"
exit 1
fi
Comment thread
Biont marked this conversation as resolved.

echo "VALIDATED_PLUGIN_VERSION=$PLUGIN_VERSION" >> $GITHUB_ENV
echo "✅ Valid WordPress.org version: $PLUGIN_VERSION"

if ! git check-ref-format --allow-onelevel "$GIT_REF"; then
echo "❌ Invalid Git ref name: $GIT_REF"
exit 1
fi
# We do not create VALIDATED_GIT_REF env var here because actions/checkout action we are going to use it with cannot take ref from vars anyway.
# But since it is validated, it is safe to use it directly from user input.

- name: Checkout git repository
uses: actions/checkout@v4
with:
ref: ${{ inputs.GIT_REF }}
ssh-key: ${{ secrets.GITHUB_USER_SSH_KEY }}

- name: Verify version consistency
run: |
set -euo pipefail

PLUGIN_FILE=$(find . -maxdepth 1 -type f -name '*.php' -exec grep -l 'Plugin Name:' {} + | head -1)
if [ -z "$PLUGIN_FILE" ]; then
echo "❌ No plugin file with 'Plugin Name:' header found"
exit 1
fi

EXTRACTION_ERROR=0

PLUGIN_FILE_VERSION=$(grep -m1 'Version:' "$PLUGIN_FILE" | grep -oP '[\d]+\.[\d]+\.[\d]+')
if [ -z "$PLUGIN_FILE_VERSION" ]; then
echo "❌ Could not extract version from $PLUGIN_FILE"
EXTRACTION_ERROR=1
fi

if [ ! -f readme.txt ]; then
echo "❌ readme.txt not found"
EXTRACTION_ERROR=1
else
README_VERSION=$(grep -m1 'Stable tag:' readme.txt | grep -oP '[\d]+\.[\d]+\.[\d]+' || true)
if [ -z "$README_VERSION" ]; then
echo "❌ Could not extract 'Stable tag:' from readme.txt"
EXTRACTION_ERROR=1
fi
fi

[ "$EXTRACTION_ERROR" = "1" ] && exit 1

MISMATCH=0

if [ "$VALIDATED_PLUGIN_VERSION" != "$PLUGIN_FILE_VERSION" ]; then
echo "❌ Input version ($VALIDATED_PLUGIN_VERSION) does not match $PLUGIN_FILE ($PLUGIN_FILE_VERSION)"
MISMATCH=1
fi
if [ "$VALIDATED_PLUGIN_VERSION" != "$README_VERSION" ]; then
echo "❌ Input version ($VALIDATED_PLUGIN_VERSION) does not match readme.txt Stable tag ($README_VERSION)"
MISMATCH=1
fi

[ "$MISMATCH" = "1" ] && exit 1

echo "✅ Version $VALIDATED_PLUGIN_VERSION is consistent across inputs, plugin file, and readme.txt"

- name: Checkout SVN repository
run: |
set -euo pipefail
mkdir -p "$SVN_REPO_PATH" && cd "$SVN_REPO_PATH"

# We only do a full checkout of trunk here, leaving other directories empty.
# Tags directory can take gigabytes for older plugins, and we don't need them for publishing.

svn checkout "https://plugins.svn.wordpress.org/${{ inputs.SVN_PLUGIN_SLUG }}" --depth immediates
cd "$SVN_REPO_ROOT" && svn update trunk --set-depth infinity

- name: Verify version doesn't exist in SVN
if: inputs.UPDATE_TRUNK_ONLY != true
run: |
set -euo pipefail

cd "${SVN_REPO_ROOT}/tags"
svn update --set-depth immediates

if [ -d "$VALIDATED_PLUGIN_VERSION" ]; then
echo "❌ Version $VALIDATED_PLUGIN_VERSION already exists in WordPress.org!"
echo " Check: https://plugins.svn.wordpress.org/${{ inputs.SVN_PLUGIN_SLUG }}/tags/"
exit 1
fi

echo "✅ Version $VALIDATED_PLUGIN_VERSION is available"

- name: Synchronize SVN repository with Git
working-directory: ${{ github.workspace }} #Make sure we are in the right place before start sync
run: |
set -euo pipefail

touch .distignore # Ensure file exists so --exclude-from doesn't fail

rsync -rc \
--delete \
--delete-excluded \
--exclude='.git' \
--exclude='.svn' \
--exclude='auth.json' \
--exclude='.npmrc' \
--exclude='.env' \
--exclude='.env.*' \
--exclude='.distignore' \
--exclude-from='.distignore' \
Comment thread
strangerkir marked this conversation as resolved.
./ "$SVN_REPO_ROOT/trunk/"

- name: Update SVN tracking
run: |
set -euo pipefail

cd "${SVN_REPO_ROOT}/trunk"
svn add . --force

#Only run if there's anything to delete
if svn status | grep -q '^!'; then
svn status | grep '^!' | cut -c9- | while IFS= read -r file; do
svn delete "$file@" # @ suffix handles files with @ in name
done
fi

- name: Commit changes to SVN repository
if: inputs.DRY_RUN != true
env:
SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
run: |
set -euo pipefail

[ -d "$SVN_REPO_ROOT" ] || { echo "❌ SVN_REPO_ROOT not found"; exit 1; }
cd "$SVN_REPO_ROOT"

svn status trunk | grep -q '^[ADMR!~]' || { echo "❌ No changes in trunk"; exit 1; }

# WordPress.org SVN doesn't support SSH keys or tokens.
# Keeping credentials as step-level env vars with --no-auth-cache is the best available option.
echo '🚀 Committing...'

svn commit trunk \
--username "$SVN_USERNAME" \
--password "$SVN_PASSWORD" \
--no-auth-cache \
--non-interactive \
-m "Update trunk to version ${VALIDATED_PLUGIN_VERSION}"

- name: Create a new tag
if: inputs.UPDATE_TRUNK_ONLY == false && inputs.DRY_RUN != true
env:
SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
run: |
set -euo pipefail

echo "🚀 Publishing version ${VALIDATED_PLUGIN_VERSION}"

svn copy \
"https://plugins.svn.wordpress.org/${{ inputs.SVN_PLUGIN_SLUG }}/trunk" \
"https://plugins.svn.wordpress.org/${{ inputs.SVN_PLUGIN_SLUG }}/tags/${VALIDATED_PLUGIN_VERSION}" \
--username "$SVN_USERNAME" \
--password "$SVN_PASSWORD" \
--no-auth-cache \
--non-interactive \
-m "Tagging version ${VALIDATED_PLUGIN_VERSION}"

echo "✅ Version ${VALIDATED_PLUGIN_VERSION} was published to WordPress.org"

- name: Compress and upload trunk contents as an artifact
if: inputs.DRY_RUN == true
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.SVN_PLUGIN_SLUG }}
path: ${{ env.SVN_REPO_ROOT }}/trunk
include-hidden-files: true
compression-level: 1 #Minimal compression - we don't want to waste resources for this
Loading
Loading