From 2588cbc24046683ecf5e7056481ac670e07c676c Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 19 Feb 2026 22:10:48 +0200 Subject: [PATCH 01/64] Create action file, checkout repositories --- .github/workflows/wordpress-org-release.yml | 50 +++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/wordpress-org-release.yml diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml new file mode 100644 index 000000000..e8b4ec4d7 --- /dev/null +++ b/.github/workflows/wordpress-org-release.yml @@ -0,0 +1,50 @@ +# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json + +name: wordpress.org publishing + +on: + workflow_call: + inputs: + SVN_REPOSITORY: + description: "SVN repository to push a new version to. Defaults to wordpress.org" + type: string + default: "https://plugins.svn.wordpress.org" + required: false + + SVN_PLUGIN_SLUG: + description: "Plugin slug in the SVN repository. E.g. if plugin URL is https://wordpress.org/plugins/payoneer-checkout, slug is payoneer-checkout." + type: string + required: true + + SVN_USERNAME: + description: "In case of wordpress.org, this is your username" + type: string + required: true + + SVN_PASSWORD: + description: "In case of wordpress.org, it should be a separate SVN password, not account password. See https://make.wordpress.org/meta/handbook/tutorials-guides/svn-access/ for more details." + type: string + required: true + +env: + SVN_REPO_PATH: $HOME/svn_repository + +jobs: + check_out_git_repository: + runs-on: ubuntu-latest + steps: + - name: Checkout git repository + uses: actions/checkout@v6 + + check_out_svn_repository: + runs-on: ubuntu-latest + steps: + - name: Checkout SVN repository + run: | + echo "Checking out SVN repository" + mkdir $SVN_REPO_PATH && cd $SVN_REPO_PATH + svn checkout "${{ inputs.SVN_REPOSITORY }}/${{ inputs.SVN_PLUGIN_SLUG }}" + + - name: Synchronize SVN repository with Git + run: | + # run rsync here From 52ddd8b5df604e3155b9025db903a573a892f5b5 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Fri, 20 Feb 2026 18:45:28 +0200 Subject: [PATCH 02/64] Update job name --- .github/workflows/wordpress-org-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index e8b4ec4d7..2a02d8a7b 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -36,7 +36,7 @@ jobs: - name: Checkout git repository uses: actions/checkout@v6 - check_out_svn_repository: + update_svn_from_git: runs-on: ubuntu-latest steps: - name: Checkout SVN repository From 66aa79333355183251f907588def505067784b63 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Fri, 20 Feb 2026 19:57:56 +0200 Subject: [PATCH 03/64] Move env vars to the job level --- .github/workflows/wordpress-org-release.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 2a02d8a7b..fdd73b29e 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -37,6 +37,9 @@ jobs: uses: actions/checkout@v6 update_svn_from_git: + env: + SVN_REPO_PATH: "$HOME/svn_repository" + SVN_TRUNK_PATH: "$SVN_REPO_PATH/trunk" runs-on: ubuntu-latest steps: - name: Checkout SVN repository From 8b54ab4aa36cfffa1545cf03e3ce06ec19964d5a Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Fri, 20 Feb 2026 19:58:33 +0200 Subject: [PATCH 04/64] Install required tools before synchronizing repos --- .github/workflows/wordpress-org-release.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index fdd73b29e..b1b719eff 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -48,6 +48,11 @@ jobs: mkdir $SVN_REPO_PATH && cd $SVN_REPO_PATH svn checkout "${{ inputs.SVN_REPOSITORY }}/${{ inputs.SVN_PLUGIN_SLUG }}" + - name: Install required tools + run: | + sudo apt-get update -y + sudo apt-get install -y subversion rsync + - name: Synchronize SVN repository with Git run: | # run rsync here From 2f1aa34719896934d637de9e036cc6143dbc3d1f Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Fri, 20 Feb 2026 20:31:05 +0200 Subject: [PATCH 05/64] Remove extra env var --- .github/workflows/wordpress-org-release.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index b1b719eff..a5ac9266e 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -26,9 +26,6 @@ on: type: string required: true -env: - SVN_REPO_PATH: $HOME/svn_repository - jobs: check_out_git_repository: runs-on: ubuntu-latest From 8a4cf80828a68d98babd29284033d563e77ceff6 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Fri, 20 Feb 2026 20:32:13 +0200 Subject: [PATCH 06/64] Move checking out git to the sync action --- .github/workflows/wordpress-org-release.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index a5ac9266e..cad3f7e4e 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -27,18 +27,15 @@ on: required: true jobs: - check_out_git_repository: - runs-on: ubuntu-latest - steps: - - name: Checkout git repository - uses: actions/checkout@v6 - update_svn_from_git: env: SVN_REPO_PATH: "$HOME/svn_repository" SVN_TRUNK_PATH: "$SVN_REPO_PATH/trunk" runs-on: ubuntu-latest steps: + - name: Checkout git repository + uses: actions/checkout@v6 + - name: Checkout SVN repository run: | echo "Checking out SVN repository" From b777183f5741f733e4785d4603d3bad339afcf56 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Fri, 20 Feb 2026 20:33:57 +0200 Subject: [PATCH 07/64] Install required tools first --- .github/workflows/wordpress-org-release.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index cad3f7e4e..0154e27b3 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -33,6 +33,11 @@ jobs: SVN_TRUNK_PATH: "$SVN_REPO_PATH/trunk" runs-on: ubuntu-latest steps: + - name: Install required tools + run: | + sudo apt-get update -y + sudo apt-get install -y subversion rsync + - name: Checkout git repository uses: actions/checkout@v6 @@ -42,11 +47,6 @@ jobs: mkdir $SVN_REPO_PATH && cd $SVN_REPO_PATH svn checkout "${{ inputs.SVN_REPOSITORY }}/${{ inputs.SVN_PLUGIN_SLUG }}" - - name: Install required tools - run: | - sudo apt-get update -y - sudo apt-get install -y subversion rsync - - name: Synchronize SVN repository with Git run: | # run rsync here From 9d0b0ec5ad1397a89b49a28fad1bd0003e9effdb Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Fri, 20 Feb 2026 20:37:15 +0200 Subject: [PATCH 08/64] Create directory in a safer way --- .github/workflows/wordpress-org-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 0154e27b3..c3ca918fc 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -44,7 +44,7 @@ jobs: - name: Checkout SVN repository run: | echo "Checking out SVN repository" - mkdir $SVN_REPO_PATH && cd $SVN_REPO_PATH + mkdir -p $SVN_REPO_PATH && cd $SVN_REPO_PATH svn checkout "${{ inputs.SVN_REPOSITORY }}/${{ inputs.SVN_PLUGIN_SLUG }}" - name: Synchronize SVN repository with Git From 6c74c55839dc3deccec3fb4d2eeb49a8d21e5ca9 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Fri, 20 Feb 2026 20:38:56 +0200 Subject: [PATCH 09/64] Use rsync to synchronize SVN with git (WIP) --- .github/workflows/wordpress-org-release.yml | 33 ++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index c3ca918fc..bf18634bb 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -43,10 +43,41 @@ jobs: - name: Checkout SVN repository run: | + set -euo pipefail echo "Checking out SVN repository" mkdir -p $SVN_REPO_PATH && cd $SVN_REPO_PATH svn checkout "${{ inputs.SVN_REPOSITORY }}/${{ inputs.SVN_PLUGIN_SLUG }}" - name: Synchronize SVN repository with Git run: | - # run rsync here + set -euo pipefail + + touch .distignore + + EXTRA_EXCLUDES="" + if [[ ! -f "$GITHUB_WORKSPACE/readme.txt" ]]; then + echo "No readme.txt in the Git repository - preserving exising one"; + EXTRA_EXCLUDES="--exclude=readme.txt" + else + echo "" + fi + + rsync -rc \ + --delete \ + --delete-excluded \ + --exclude='.git' \ + --exclude='.svn' \ + --exclude='auth.json' \ + --exclude='.env' \ + --exclude='.env.*' \ + --exclude='composer.json' \ + --exclude='composer.lock' \ + --exclude='package.json' \ + --exclude='package-lock.json' \ + --exclude='yarn.lock' \ + --exclude='node_modules' \ + --exclude='.github' \ + --exclude='.ddev' \ + --exclude-from='.distignore' \ + $EXTRA_EXCLUDES \ + "$GITHUB_WORKSPACE/" "$SVN_TRUNK_PATH/" From ccaba39076ea241159813c7167dd29cb00b5ab22 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Fri, 20 Feb 2026 21:08:59 +0200 Subject: [PATCH 10/64] Use official stable version of checkout action --- .github/workflows/wordpress-org-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index bf18634bb..eddb66465 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -39,7 +39,7 @@ jobs: sudo apt-get install -y subversion rsync - name: Checkout git repository - uses: actions/checkout@v6 + uses: actions/checkout@v4 - name: Checkout SVN repository run: | From 9016f3239a74ec1374b4abc50a14f0d764792354 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Fri, 20 Feb 2026 21:12:01 +0200 Subject: [PATCH 11/64] Remove extra echo - step name already has it --- .github/workflows/wordpress-org-release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index eddb66465..30a3636c7 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -44,7 +44,6 @@ jobs: - name: Checkout SVN repository run: | set -euo pipefail - echo "Checking out SVN repository" mkdir -p $SVN_REPO_PATH && cd $SVN_REPO_PATH svn checkout "${{ inputs.SVN_REPOSITORY }}/${{ inputs.SVN_PLUGIN_SLUG }}" From f68aa6c6a96bef47bd719508cae7f67c6064ede8 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Fri, 20 Feb 2026 21:18:26 +0200 Subject: [PATCH 12/64] Keep both SVN username and password as secrets --- .github/workflows/wordpress-org-release.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 30a3636c7..4ef0356b5 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -16,14 +16,11 @@ on: type: string required: true + secrets: SVN_USERNAME: - description: "In case of wordpress.org, this is your username" - type: string required: true SVN_PASSWORD: - description: "In case of wordpress.org, it should be a separate SVN password, not account password. See https://make.wordpress.org/meta/handbook/tutorials-guides/svn-access/ for more details." - type: string required: true jobs: From 08424a8dd617d18c4c38aa42daf5ef20d499242c Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Mon, 2 Mar 2026 15:23:39 +0200 Subject: [PATCH 13/64] Remove extra else --- .github/workflows/wordpress-org-release.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 4ef0356b5..7727a0b61 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -54,9 +54,6 @@ jobs: if [[ ! -f "$GITHUB_WORKSPACE/readme.txt" ]]; then echo "No readme.txt in the Git repository - preserving exising one"; EXTRA_EXCLUDES="--exclude=readme.txt" - else - echo "" - fi rsync -rc \ --delete \ From 8b76efa064b0cdfd9eaf823a8498b96c8db92ce7 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Mon, 2 Mar 2026 15:32:23 +0200 Subject: [PATCH 14/64] Do not add readme.txt to excludes list With the --delete-excluded flag, it would be removed from SVN if it doesn't exist in Git --- .github/workflows/wordpress-org-release.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 7727a0b61..fb0e64a58 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -49,11 +49,6 @@ jobs: set -euo pipefail touch .distignore - - EXTRA_EXCLUDES="" - if [[ ! -f "$GITHUB_WORKSPACE/readme.txt" ]]; then - echo "No readme.txt in the Git repository - preserving exising one"; - EXTRA_EXCLUDES="--exclude=readme.txt" rsync -rc \ --delete \ @@ -72,5 +67,4 @@ jobs: --exclude='.github' \ --exclude='.ddev' \ --exclude-from='.distignore' \ - $EXTRA_EXCLUDES \ "$GITHUB_WORKSPACE/" "$SVN_TRUNK_PATH/" From 0f86d3d985de8ce1315df94d1eda7e26f516d8e7 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Mon, 2 Mar 2026 17:52:36 +0200 Subject: [PATCH 15/64] Temporarily define env vars in an extra step --- .github/workflows/wordpress-org-release.yml | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index fb0e64a58..90e71884a 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -25,11 +25,20 @@ on: jobs: update_svn_from_git: - env: - SVN_REPO_PATH: "$HOME/svn_repository" - SVN_TRUNK_PATH: "$SVN_REPO_PATH/trunk" + # TODO: Set env vars here and remove an extra step. + # This works in real GH Actions but act doesn't support runner context at job level, so we had to create an extra step + # Desired format: + # env: + # SVN_REPO_PATH: "${{ runner.workspace }}/svn_repository" + # SVN_REPO_ROOT: "${{ runner.workspace }}/svn_repository/${{ inputs.SVN_PLUGIN_SLUG }}" runs-on: ubuntu-latest steps: + #TODO: remove this step (see the comment above for details) + - name: Configure paths + run: | + echo "SVN_REPO_PATH=${{ runner.workspace }}/svn_repository" >> $GITHUB_ENV + echo "SVN_REPO_ROOT=${{ runner.workspace }}/svn_repository/${{ inputs.SVN_PLUGIN_SLUG }}" >> $GITHUB_ENV + - name: Install required tools run: | sudo apt-get update -y @@ -42,7 +51,7 @@ jobs: run: | set -euo pipefail mkdir -p $SVN_REPO_PATH && cd $SVN_REPO_PATH - svn checkout "${{ inputs.SVN_REPOSITORY }}/${{ inputs.SVN_PLUGIN_SLUG }}" + svn checkout "${{ inputs.SVN_REPOSITORY }}/${{ inputs.SVN_PLUGIN_SLUG }}" - name: Synchronize SVN repository with Git run: | @@ -67,4 +76,4 @@ jobs: --exclude='.github' \ --exclude='.ddev' \ --exclude-from='.distignore' \ - "$GITHUB_WORKSPACE/" "$SVN_TRUNK_PATH/" + "$GITHUB_WORKSPACE/" "$SVN_REPO_ROOT/trunk/" From 6e32ff303c01a17eea0c90763e53dda574f3b99f Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Mon, 2 Mar 2026 20:17:39 +0200 Subject: [PATCH 16/64] Update SVN tracking: add new files and delete removed ones --- .github/workflows/wordpress-org-release.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 90e71884a..f85311a3d 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -77,3 +77,11 @@ jobs: --exclude='.ddev' \ --exclude-from='.distignore' \ "$GITHUB_WORKSPACE/" "$SVN_REPO_ROOT/trunk/" + + - name: Update SVN tracking + run: | + cd $SVN_REPO_ROOT + svn add . --force + svn status | grep '^!' | cut -c9- | while IFS= read -r file; do + svn delete "$file@" # @ suffix handles files with @ in name + done \ No newline at end of file From a015e3a7d5523e104dd6d33f58ad79da1dc9604a Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Mon, 2 Mar 2026 20:31:35 +0200 Subject: [PATCH 17/64] Add test mode input and prepare dry-run step --- .github/workflows/wordpress-org-release.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index f85311a3d..5c0e983ee 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -16,6 +16,12 @@ on: type: string required: true + TEST_MODE: + description: "In test mode no commit to SVN repository happens. Instead, local SVN repository is used, and then provided as an archive for manual checking." + type: boolean + default: false + required: false + secrets: SVN_USERNAME: required: true @@ -84,4 +90,8 @@ jobs: svn add . --force svn status | grep '^!' | cut -c9- | while IFS= read -r file; do svn delete "$file@" # @ suffix handles files with @ in name - done \ No newline at end of file + done + + - name: [TEST MODE] Pack files and provide as an artefact instead of commiting to the actual repository + if: ${{ inputs.TEST_MODE }} + run: | #TODO: create an artifact and upload it here From 4136154da67a800ba3474acaeaa3cf18aaa49021 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Tue, 3 Mar 2026 17:04:56 +0200 Subject: [PATCH 18/64] Compress svn trunk and upload as an artifact --- .github/workflows/wordpress-org-release.yml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 5c0e983ee..730112d36 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -92,6 +92,16 @@ jobs: svn delete "$file@" # @ suffix handles files with @ in name done - - name: [TEST MODE] Pack files and provide as an artefact instead of commiting to the actual repository - if: ${{ inputs.TEST_MODE }} - run: | #TODO: create an artifact and upload it here + - name: Commit changes to SVN repository + if: inputs.TEST_MODE != true + run: | #TODO: do SVN commit here + echo 'Committing...' + + - name: Compress and upload trunk contents as an artifact + if: inputs.TEST_MODE == true + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.SVN_PLUGIN_SLUG }} + path: ${{ runner.workspace }}/svn_repository/${{ inputs.SVN_PLUGIN_SLUG }}/trunk + include-hidden-files: true + compression-level: 1 From 0a414be063f33c4dc608bf45f484b93917e7a103 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Tue, 3 Mar 2026 19:25:22 +0200 Subject: [PATCH 19/64] Remove 'custom SVN repository' feature --- .github/workflows/wordpress-org-release.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 730112d36..7471a4cb1 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -5,12 +5,6 @@ name: wordpress.org publishing on: workflow_call: inputs: - SVN_REPOSITORY: - description: "SVN repository to push a new version to. Defaults to wordpress.org" - type: string - default: "https://plugins.svn.wordpress.org" - required: false - SVN_PLUGIN_SLUG: description: "Plugin slug in the SVN repository. E.g. if plugin URL is https://wordpress.org/plugins/payoneer-checkout, slug is payoneer-checkout." type: string @@ -57,7 +51,7 @@ jobs: run: | set -euo pipefail mkdir -p $SVN_REPO_PATH && cd $SVN_REPO_PATH - svn checkout "${{ inputs.SVN_REPOSITORY }}/${{ inputs.SVN_PLUGIN_SLUG }}" + svn checkout "https://plugins.svn.wordpress.org/${{ inputs.SVN_PLUGIN_SLUG }}" - name: Synchronize SVN repository with Git run: | From 69322e60fb499fd55aa1c611ee88e798d1fede7a Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Tue, 3 Mar 2026 19:26:19 +0200 Subject: [PATCH 20/64] Update comment --- .github/workflows/wordpress-org-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 7471a4cb1..9a3863b37 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -11,7 +11,7 @@ on: required: true TEST_MODE: - description: "In test mode no commit to SVN repository happens. Instead, local SVN repository is used, and then provided as an archive for manual checking." + description: "In test mode no commit to the SVN repository happens. Instead, files from trunk are provided as an artifact." type: boolean default: false required: false From 66499ecb81f7e5e705850e69e9a1d8f53e76f87c Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Tue, 3 Mar 2026 19:28:07 +0200 Subject: [PATCH 21/64] Make shell fail early on errors --- .github/workflows/wordpress-org-release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 9a3863b37..dec1f4698 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -80,6 +80,8 @@ jobs: - name: Update SVN tracking run: | + set -euo pipefail + cd $SVN_REPO_ROOT svn add . --force svn status | grep '^!' | cut -c9- | while IFS= read -r file; do From 7bdc46b8cb250dc6b3c85dac8ba67eeaffa31916 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Wed, 4 Mar 2026 16:11:47 +0200 Subject: [PATCH 22/64] Update comment - more concise and better example --- .github/workflows/wordpress-org-release.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index dec1f4698..01d31e7d3 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -6,7 +6,7 @@ on: workflow_call: inputs: SVN_PLUGIN_SLUG: - description: "Plugin slug in the SVN repository. E.g. if plugin URL is https://wordpress.org/plugins/payoneer-checkout, slug is payoneer-checkout." + description: "WordPress.org plugin slug (e.g., 'woocommerce' from https://wordpress.org/plugins/woocommerce)" type: string required: true @@ -59,6 +59,8 @@ jobs: touch .distignore + ls $GITHUB_WORKSPACE + rsync -rc \ --delete \ --delete-excluded \ @@ -77,6 +79,8 @@ jobs: --exclude='.ddev' \ --exclude-from='.distignore' \ "$GITHUB_WORKSPACE/" "$SVN_REPO_ROOT/trunk/" + + cd "$SVN_REPO_ROOT/trunk" && pwd && ls -lha - name: Update SVN tracking run: | From 0df79c1e8a766016ed0da3615683b214a72c80c6 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Wed, 4 Mar 2026 16:14:10 +0200 Subject: [PATCH 23/64] Rename TEST_MODE to DRY_RUN --- .github/workflows/wordpress-org-release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 01d31e7d3..dea5f2f0e 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -10,8 +10,8 @@ on: type: string required: true - TEST_MODE: - description: "In test mode no commit to the SVN repository happens. Instead, files from trunk are provided as an artifact." + DRY_RUN: + description: "In dry-run mode no commit to the SVN repository happens. Instead, files from trunk are provided as an artifact." type: boolean default: false required: false @@ -93,12 +93,12 @@ jobs: done - name: Commit changes to SVN repository - if: inputs.TEST_MODE != true + if: inputs.DRY_RUN != true run: | #TODO: do SVN commit here echo 'Committing...' - name: Compress and upload trunk contents as an artifact - if: inputs.TEST_MODE == true + if: inputs.DRY_RUN == true uses: actions/upload-artifact@v4 with: name: ${{ inputs.SVN_PLUGIN_SLUG }} From b7ea83f6d95aedeb9157e63f3c2a4ab4ea1ae458 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Wed, 4 Mar 2026 16:21:21 +0200 Subject: [PATCH 24/64] Add IDE's directories to exclusions --- .github/workflows/wordpress-org-release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index dea5f2f0e..a673cf2ac 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -77,6 +77,8 @@ jobs: --exclude='node_modules' \ --exclude='.github' \ --exclude='.ddev' \ + --exclude='.idea' \ + --exclude='.vscode' \ --exclude-from='.distignore' \ "$GITHUB_WORKSPACE/" "$SVN_REPO_ROOT/trunk/" From 9dc8ad8ea6c6d958af54445ebc389edc60b9e444 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Wed, 4 Mar 2026 17:59:43 +0200 Subject: [PATCH 25/64] Exclude .distignore file itself --- .github/workflows/wordpress-org-release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index a673cf2ac..a6731248f 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -79,6 +79,7 @@ jobs: --exclude='.ddev' \ --exclude='.idea' \ --exclude='.vscode' \ + --exclude='.distignore' \ --exclude-from='.distignore' \ "$GITHUB_WORKSPACE/" "$SVN_REPO_ROOT/trunk/" From 1c86daa63959c682afa19bab6ea42faf308c6e07 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Wed, 4 Mar 2026 18:03:56 +0200 Subject: [PATCH 26/64] Make sure we have right paths when updating trunk --- .github/workflows/wordpress-org-release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index a6731248f..f8408af52 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -54,6 +54,7 @@ jobs: svn checkout "https://plugins.svn.wordpress.org/${{ inputs.SVN_PLUGIN_SLUG }}" - 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 @@ -81,7 +82,7 @@ jobs: --exclude='.vscode' \ --exclude='.distignore' \ --exclude-from='.distignore' \ - "$GITHUB_WORKSPACE/" "$SVN_REPO_ROOT/trunk/" + ./ "$SVN_REPO_ROOT/trunk/" cd "$SVN_REPO_ROOT/trunk" && pwd && ls -lha From 64ab47e155ec5855f8d75c29479aef5a808324c1 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 5 Mar 2026 11:08:53 +0200 Subject: [PATCH 27/64] Remove debug code --- .github/workflows/wordpress-org-release.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index f8408af52..dcbf48bcb 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -83,8 +83,6 @@ jobs: --exclude='.distignore' \ --exclude-from='.distignore' \ ./ "$SVN_REPO_ROOT/trunk/" - - cd "$SVN_REPO_ROOT/trunk" && pwd && ls -lha - name: Update SVN tracking run: | From 77c418e2ef4a3fcefbc7588a2960f82aa4f5aa66 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 5 Mar 2026 11:58:33 +0200 Subject: [PATCH 28/64] Add TAG input for both Git and SVN --- .github/workflows/wordpress-org-release.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index dcbf48bcb..ad3b59150 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -10,6 +10,11 @@ on: type: string required: true + TAG: + description: "Git tag to publish to publish at WordPress.org (note: it must exist in git and not exist in SVN)" + type: string + required: true + DRY_RUN: description: "In dry-run mode no commit to the SVN repository happens. Instead, files from trunk are provided as an artifact." type: boolean @@ -33,7 +38,7 @@ jobs: # SVN_REPO_ROOT: "${{ runner.workspace }}/svn_repository/${{ inputs.SVN_PLUGIN_SLUG }}" runs-on: ubuntu-latest steps: - #TODO: remove this step (see the comment above for details) + #TODO: remove this step (see the comment above for details) - name: Configure paths run: | echo "SVN_REPO_PATH=${{ runner.workspace }}/svn_repository" >> $GITHUB_ENV @@ -46,6 +51,8 @@ jobs: - name: Checkout git repository uses: actions/checkout@v4 + with: + ref: ${{ inputs.TAG }} #TODO: Sanitize and validate tag name - name: Checkout SVN repository run: | From 41c914523c6ea979606a19a5cc304513d2a2615b Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 5 Mar 2026 12:08:41 +0200 Subject: [PATCH 29/64] Create SVN tag --- .github/workflows/wordpress-org-release.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index ad3b59150..9e5b29129 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -103,8 +103,10 @@ jobs: - name: Commit changes to SVN repository if: inputs.DRY_RUN != true - run: | #TODO: do SVN commit here - echo 'Committing...' + run: | + cd "$SVN_REPO_ROOT" + svn copy trunk "tags/$TAG" #TODO: put sanitized and validated tag into this env var or use step outputs instead + echo 'Committing...' #TODO: do SVN commit here - name: Compress and upload trunk contents as an artifact if: inputs.DRY_RUN == true From 41ee1d61dbeb46b194583ab0df9b7a696b2a2258 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Wed, 11 Mar 2026 18:13:00 +0200 Subject: [PATCH 30/64] Use separate inputs for plugin version and git ref --- .github/workflows/wordpress-org-release.yml | 38 ++++++++++++++++++--- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 9e5b29129..b6f644c9e 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -10,8 +10,13 @@ on: type: string required: true - TAG: - description: "Git tag to publish to publish at WordPress.org (note: it must exist in git and not exist in SVN)" + PLUGIN_VERSION: + description: "Plugin version to publish at WordPress.org (note: it must not exist in SVN)" + type: string + required: true + + GIT_REF: + description: "Git ref to publish at WordPress.org (tag, branch or commit)" type: string required: true @@ -49,10 +54,35 @@ jobs: sudo apt-get update -y sudo apt-get install -y subversion rsync + - 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 + + 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.TAG }} #TODO: Sanitize and validate tag name + ref: ${{ inputs.GIT_REF }} - name: Checkout SVN repository run: | @@ -105,7 +135,7 @@ jobs: if: inputs.DRY_RUN != true run: | cd "$SVN_REPO_ROOT" - svn copy trunk "tags/$TAG" #TODO: put sanitized and validated tag into this env var or use step outputs instead + svn copy trunk "tags/$VALIDATED_PLUGIN_VERSION" echo 'Committing...' #TODO: do SVN commit here - name: Compress and upload trunk contents as an artifact From 46c3a73898fb293f6dd7625c9c58b5b597aa2f70 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 11:33:50 +0200 Subject: [PATCH 31/64] Only checkout top-level dirs and trunk contents --- .github/workflows/wordpress-org-release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index b6f644c9e..357cebaf0 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -88,7 +88,8 @@ jobs: run: | set -euo pipefail mkdir -p $SVN_REPO_PATH && cd $SVN_REPO_PATH - svn checkout "https://plugins.svn.wordpress.org/${{ inputs.SVN_PLUGIN_SLUG }}" + svn checkout "https://plugins.svn.wordpress.org/${{ inputs.SVN_PLUGIN_SLUG }}" --depth immediates + cd $SVN_REPO_ROOT && svn update trunk --set-depth infinity - name: Synchronize SVN repository with Git working-directory: ${{ github.workspace }} #Make sure we are in the right place before start sync From bef91db40edba17fd6ca11440d96c9cbe09f5c35 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 11:34:20 +0200 Subject: [PATCH 32/64] Add ssh-key to the checkout action --- .github/workflows/wordpress-org-release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 357cebaf0..a03c35ea4 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -83,6 +83,7 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ inputs.GIT_REF }} + ssh-key: ${{ secrets.GITHUB_USER_SSH_KEY }} - name: Checkout SVN repository run: | From 592dd13c44a50bf120f535bc635e1264e2062e9b Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 11:34:33 +0200 Subject: [PATCH 33/64] Update comments --- .github/workflows/wordpress-org-release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index a03c35ea4..ad11dd65a 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -21,7 +21,7 @@ on: required: true DRY_RUN: - description: "In dry-run mode no commit to the SVN repository happens. Instead, files from trunk are provided as an artifact." + description: "Create artifact from trunk instead of committing to SVN" type: boolean default: false required: false @@ -147,4 +147,4 @@ jobs: name: ${{ inputs.SVN_PLUGIN_SLUG }} path: ${{ runner.workspace }}/svn_repository/${{ inputs.SVN_PLUGIN_SLUG }}/trunk include-hidden-files: true - compression-level: 1 + compression-level: 1 #Minimal compression - we don't want to waste resources for this From d748fb595515a17de3d7ccd51749cdfa65738d86 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 12:50:12 +0200 Subject: [PATCH 34/64] Update descriptions --- .github/workflows/wordpress-org-release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index ad11dd65a..b3aaff45a 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -6,17 +6,17 @@ on: workflow_call: inputs: SVN_PLUGIN_SLUG: - description: "WordPress.org plugin slug (e.g., 'woocommerce' from https://wordpress.org/plugins/woocommerce)" + description: "WordPress.org plugin slug (e.g., 'woocommerce')" type: string required: true PLUGIN_VERSION: - description: "Plugin version to publish at WordPress.org (note: it must not exist in SVN)" + description: "Plugin version to publish (MAJOR.MINOR.PATCH)" type: string required: true GIT_REF: - description: "Git ref to publish at WordPress.org (tag, branch or commit)" + description: "Git ref to publish (tag, branch, or commit)" type: string required: true From 66a87ee7ca2b530dd9cea359ff51279c689e4bac Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 12:56:19 +0200 Subject: [PATCH 35/64] Use env var for trunk path --- .github/workflows/wordpress-org-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index b3aaff45a..c614678f1 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -145,6 +145,6 @@ jobs: uses: actions/upload-artifact@v4 with: name: ${{ inputs.SVN_PLUGIN_SLUG }} - path: ${{ runner.workspace }}/svn_repository/${{ inputs.SVN_PLUGIN_SLUG }}/trunk + path: ${{ env.SVN_REPO_ROOT }}/trunk include-hidden-files: true compression-level: 1 #Minimal compression - we don't want to waste resources for this From e0e4deb1d5d8d682a7015757cb048bd79f1e3475 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 12:57:50 +0200 Subject: [PATCH 36/64] Quote variables --- .github/workflows/wordpress-org-release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index c614678f1..fb787cbc0 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -88,9 +88,9 @@ jobs: - name: Checkout SVN repository run: | set -euo pipefail - mkdir -p $SVN_REPO_PATH && cd $SVN_REPO_PATH + mkdir -p "$SVN_REPO_PATH" && cd "$SVN_REPO_PATH" svn checkout "https://plugins.svn.wordpress.org/${{ inputs.SVN_PLUGIN_SLUG }}" --depth immediates - cd $SVN_REPO_ROOT && svn update trunk --set-depth infinity + cd "$SVN_REPO_ROOT" && svn update trunk --set-depth infinity - name: Synchronize SVN repository with Git working-directory: ${{ github.workspace }} #Make sure we are in the right place before start sync From 734a42e46ded80127c64d7260729164a48221893 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 12:58:55 +0200 Subject: [PATCH 37/64] Check for deleted files before removing them --- .github/workflows/wordpress-org-release.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index fb787cbc0..395ae26d0 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -129,9 +129,12 @@ jobs: cd $SVN_REPO_ROOT svn add . --force - svn status | grep '^!' | cut -c9- | while IFS= read -r file; do - svn delete "$file@" # @ suffix handles files with @ in name - done + + if svn status | grep -q '^!'; then #Only run if there's anything to delete + 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 From 484dc7c6e1d09e03e67c2f8110a0d8bf010a4b3a Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 12:59:27 +0200 Subject: [PATCH 38/64] Make sure we are only operate on trunk --- .github/workflows/wordpress-org-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 395ae26d0..9169ee92c 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -127,7 +127,7 @@ jobs: run: | set -euo pipefail - cd $SVN_REPO_ROOT + cd "${SVN_REPO_ROOT}/trunk" svn add . --force if svn status | grep -q '^!'; then #Only run if there's anything to delete From 59830c1f2c59a2c12ee8ffd8e1216e04cbcce7d5 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 12:59:38 +0200 Subject: [PATCH 39/64] Remove debugging code --- .github/workflows/wordpress-org-release.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 9169ee92c..fc878bc6d 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -99,8 +99,6 @@ jobs: touch .distignore - ls $GITHUB_WORKSPACE - rsync -rc \ --delete \ --delete-excluded \ From 1dbefce750ae3403eceb7ed43c673f6faeda7676 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 13:04:16 +0200 Subject: [PATCH 40/64] Make sure version doesn't exist yet in SVN --- .github/workflows/wordpress-org-release.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index fc878bc6d..70c1adcbb 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -79,6 +79,21 @@ jobs: # 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: Verify version doesn't exist in SVN + 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: Checkout git repository uses: actions/checkout@v4 with: From 1e64f49bd75a179f14e0e4ed4be4c3eaff7579e3 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 13:09:36 +0200 Subject: [PATCH 41/64] Make sure variable is safely limited --- .github/workflows/wordpress-org-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 70c1adcbb..0d39e334c 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -153,7 +153,7 @@ jobs: if: inputs.DRY_RUN != true run: | cd "$SVN_REPO_ROOT" - svn copy trunk "tags/$VALIDATED_PLUGIN_VERSION" + svn copy trunk "tags/${VALIDATED_PLUGIN_VERSION}" echo 'Committing...' #TODO: do SVN commit here - name: Compress and upload trunk contents as an artifact From 5601a6f274e646af412dff9d654204b2b23b6e3d Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 16:00:30 +0200 Subject: [PATCH 42/64] Add committing to WordPress.org --- .github/workflows/wordpress-org-release.yml | 33 +++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 0d39e334c..a34c9b5d4 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -151,10 +151,39 @@ jobs: - 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 copy trunk "tags/${VALIDATED_PLUGIN_VERSION}" - echo 'Committing...' #TODO: do SVN commit here + + svn status trunk | grep -q '^C' && { echo "❌ SVN conflicts in trunk"; exit 1; } + 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}" + + 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 From cd13f1c1bebf69027d0c0b282b85cfcab5d33fb3 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 16:52:44 +0200 Subject: [PATCH 43/64] Use env: to set env variables at job level --- .github/workflows/wordpress-org-release.yml | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index a34c9b5d4..75fc2e2c8 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -35,20 +35,11 @@ on: jobs: update_svn_from_git: - # TODO: Set env vars here and remove an extra step. - # This works in real GH Actions but act doesn't support runner context at job level, so we had to create an extra step - # Desired format: - # env: - # SVN_REPO_PATH: "${{ runner.workspace }}/svn_repository" - # SVN_REPO_ROOT: "${{ runner.workspace }}/svn_repository/${{ inputs.SVN_PLUGIN_SLUG }}" + env: + SVN_REPO_PATH: "${{ runner.workspace }}/svn_repository" + SVN_REPO_ROOT: "${{ runner.workspace }}/svn_repository/${{ inputs.SVN_PLUGIN_SLUG }}" runs-on: ubuntu-latest steps: - #TODO: remove this step (see the comment above for details) - - name: Configure paths - run: | - echo "SVN_REPO_PATH=${{ runner.workspace }}/svn_repository" >> $GITHUB_ENV - echo "SVN_REPO_ROOT=${{ runner.workspace }}/svn_repository/${{ inputs.SVN_PLUGIN_SLUG }}" >> $GITHUB_ENV - - name: Install required tools run: | sudo apt-get update -y From 5a65ef084102b53695503d189b88e2ae3445134b Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 16:53:22 +0200 Subject: [PATCH 44/64] Fix verifying SVN version doesn't exist --- .github/workflows/wordpress-org-release.yml | 26 ++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 75fc2e2c8..b47b960d6 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -70,6 +70,19 @@ jobs: # 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: Checkout SVN repository + run: | + set -euo pipefail + mkdir -p "$SVN_REPO_PATH" && cd "$SVN_REPO_PATH" + 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 run: | set -euo pipefail @@ -85,19 +98,6 @@ jobs: echo "✅ Version $VALIDATED_PLUGIN_VERSION is available" - - name: Checkout git repository - uses: actions/checkout@v4 - with: - ref: ${{ inputs.GIT_REF }} - ssh-key: ${{ secrets.GITHUB_USER_SSH_KEY }} - - - name: Checkout SVN repository - run: | - set -euo pipefail - mkdir -p "$SVN_REPO_PATH" && cd "$SVN_REPO_PATH" - svn checkout "https://plugins.svn.wordpress.org/${{ inputs.SVN_PLUGIN_SLUG }}" --depth immediates - cd "$SVN_REPO_ROOT" && svn update trunk --set-depth infinity - - name: Synchronize SVN repository with Git working-directory: ${{ github.workspace }} #Make sure we are in the right place before start sync run: | From f1799b5f40d4ec2da76b1e6f7f548f6caa12d3e6 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 16:57:00 +0200 Subject: [PATCH 45/64] Update comments --- .github/workflows/wordpress-org-release.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index b47b960d6..9c5d8a650 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -103,7 +103,7 @@ jobs: run: | set -euo pipefail - touch .distignore + touch .distignore # Ensure file exists so --exclude-from doesn't fail rsync -rc \ --delete \ @@ -134,7 +134,8 @@ jobs: cd "${SVN_REPO_ROOT}/trunk" svn add . --force - if svn status | grep -q '^!'; then #Only run if there's anything to delete + #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 From 92d05cd74eb41882b4e37f0d71072a108414fb32 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 17:28:42 +0200 Subject: [PATCH 46/64] Use github.workspace instead of runner.workspace --- .github/workflows/wordpress-org-release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 9c5d8a650..03e168dce 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -36,8 +36,8 @@ on: jobs: update_svn_from_git: env: - SVN_REPO_PATH: "${{ runner.workspace }}/svn_repository" - SVN_REPO_ROOT: "${{ runner.workspace }}/svn_repository/${{ inputs.SVN_PLUGIN_SLUG }}" + 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 From 193fdfeda9ac5282ae2c5c3ab3e5822446f29008 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 17:34:09 +0200 Subject: [PATCH 47/64] Add missing secret input --- .github/workflows/wordpress-org-release.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 03e168dce..2f3e87cab 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -33,6 +33,9 @@ on: SVN_PASSWORD: required: true + GITHUB_USER_SSH_KEY: + required: true + jobs: update_svn_from_git: env: From 9dc4e25eaf6ddde4dcd8bc97e583200c06f3c29c Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 17:47:33 +0200 Subject: [PATCH 48/64] Add comment to clarify intentions --- .github/workflows/wordpress-org-release.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 2f3e87cab..3e6b90ee7 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -83,6 +83,10 @@ jobs: run: | set -euo pipefail mkdir -p "$SVN_REPO_PATH" && cd "$SVN_REPO_PATH" + + #We only getting full contents of trunk here, the rest of directories we left empty. + #For some older plugins, tags directory may take gigabytes, and we don't need them here. + svn checkout "https://plugins.svn.wordpress.org/${{ inputs.SVN_PLUGIN_SLUG }}" --depth immediates cd "$SVN_REPO_ROOT" && svn update trunk --set-depth infinity From 0596f5961f028be9a473d1e892232ace0520207b Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Thu, 12 Mar 2026 20:29:03 +0200 Subject: [PATCH 49/64] Fix and improve comment --- .github/workflows/wordpress-org-release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 3e6b90ee7..02b07bbf8 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -84,8 +84,8 @@ jobs: set -euo pipefail mkdir -p "$SVN_REPO_PATH" && cd "$SVN_REPO_PATH" - #We only getting full contents of trunk here, the rest of directories we left empty. - #For some older plugins, tags directory may take gigabytes, and we don't need them here. + # 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 From 25fdc5fe71e4d543dbc0abb7fd8baf1d7d38e87c Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Tue, 28 Apr 2026 13:24:02 +0300 Subject: [PATCH 50/64] Check that versions match in all sources --- .github/workflows/wordpress-org-release.yml | 46 +++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 02b07bbf8..7f0aea761 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -79,6 +79,52 @@ jobs: 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 From 73720493e48867088ac2effdf07f72b9641e1a83 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Tue, 28 Apr 2026 17:14:20 +0300 Subject: [PATCH 51/64] Split workflow into two jobs The first one does validation and pushes changes to the trunk. The second one creates a new tag from the trunk at wordpress.org This gives the ability to set up environment guard and test changes already pushed to trunk before creating a new tag. --- .github/workflows/wordpress-org-release.yml | 58 ++++++++++++++------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 7f0aea761..d6f9ba496 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -37,7 +37,7 @@ on: required: true jobs: - update_svn_from_git: + push_trunk: env: SVN_REPO_PATH: "${{ github.workspace }}/svn_repository" SVN_REPO_ROOT: "${{ github.workspace }}/svn_repository/${{ inputs.SVN_PLUGIN_SLUG }}" @@ -129,10 +129,10 @@ jobs: 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 @@ -157,7 +157,7 @@ jobs: set -euo pipefail touch .distignore # Ensure file exists so --exclude-from doesn't fail - + rsync -rc \ --delete \ --delete-excluded \ @@ -183,10 +183,10 @@ jobs: - 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 @@ -194,7 +194,7 @@ jobs: done fi - - name: Commit changes to SVN repository + - name: Commit trunk to SVN repository if: inputs.DRY_RUN != true env: SVN_USERNAME: ${{ secrets.SVN_USERNAME }} @@ -210,7 +210,7 @@ jobs: # 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...' + echo '🚀 Committing trunk...' svn commit trunk \ --username "$SVN_USERNAME" \ @@ -219,16 +219,7 @@ jobs: --non-interactive \ -m "Update trunk to 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" + echo "✅ Trunk updated to version ${VALIDATED_PLUGIN_VERSION}" - name: Compress and upload trunk contents as an artifact if: inputs.DRY_RUN == true @@ -238,3 +229,34 @@ jobs: path: ${{ env.SVN_REPO_ROOT }}/trunk include-hidden-files: true compression-level: 1 #Minimal compression - we don't want to waste resources for this + + create_tag: + needs: push_trunk + if: inputs.DRY_RUN != true + environment: wordpress-org-release + runs-on: ubuntu-latest + steps: + - name: Install subversion + run: | + sudo apt-get update -y + sudo apt-get install -y subversion + + - name: Create SVN tag + env: + SVN_USERNAME: ${{ secrets.SVN_USERNAME }} + SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} + run: | + set -euo pipefail + + echo '🚀 Creating tag...' + + svn copy \ + "https://plugins.svn.wordpress.org/${{ inputs.SVN_PLUGIN_SLUG }}/trunk" \ + "https://plugins.svn.wordpress.org/${{ inputs.SVN_PLUGIN_SLUG }}/tags/${{ inputs.PLUGIN_VERSION }}" \ + --username "$SVN_USERNAME" \ + --password "$SVN_PASSWORD" \ + --no-auth-cache \ + --non-interactive \ + -m "Tagging version ${{ inputs.PLUGIN_VERSION }}" + + echo "✅ Version ${{ inputs.PLUGIN_VERSION }} was published to WordPress.org" From 3618ab49bf9b3f1cff3e1ffd8405ef4046eea9cd Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Tue, 28 Apr 2026 18:53:23 +0300 Subject: [PATCH 52/64] Only explicitly exclude sensitive files and .svn --- .github/workflows/wordpress-org-release.yml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index d6f9ba496..fde6221d0 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -164,18 +164,9 @@ jobs: --exclude='.git' \ --exclude='.svn' \ --exclude='auth.json' \ + --exclude='.npmrc' \ --exclude='.env' \ --exclude='.env.*' \ - --exclude='composer.json' \ - --exclude='composer.lock' \ - --exclude='package.json' \ - --exclude='package-lock.json' \ - --exclude='yarn.lock' \ - --exclude='node_modules' \ - --exclude='.github' \ - --exclude='.ddev' \ - --exclude='.idea' \ - --exclude='.vscode' \ --exclude='.distignore' \ --exclude-from='.distignore' \ ./ "$SVN_REPO_ROOT/trunk/" From da3e14c5b2be8cd438b73da1e5e42c42d49b7e3f Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Tue, 28 Apr 2026 19:35:42 +0300 Subject: [PATCH 53/64] Remove check for SVN conflicts There is no way we can get a conflict in our workflow --- .github/workflows/wordpress-org-release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index fde6221d0..c1691ee68 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -196,7 +196,6 @@ jobs: [ -d "$SVN_REPO_ROOT" ] || { echo "❌ SVN_REPO_ROOT not found"; exit 1; } cd "$SVN_REPO_ROOT" - svn status trunk | grep -q '^C' && { echo "❌ SVN conflicts in trunk"; exit 1; } svn status trunk | grep -q '^[ADMR!~]' || { echo "❌ No changes in trunk"; exit 1; } # WordPress.org SVN doesn't support SSH keys or tokens. From 1cc8ec1759fc930381145f3762aa201f25997997 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Mon, 11 May 2026 18:00:46 +0300 Subject: [PATCH 54/64] Revert "Split workflow into two jobs" This reverts commit 73720493e48867088ac2effdf07f72b9641e1a83. --- .github/workflows/wordpress-org-release.yml | 58 +++++++-------------- 1 file changed, 18 insertions(+), 40 deletions(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index c1691ee68..5c47c988f 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -37,7 +37,7 @@ on: required: true jobs: - push_trunk: + update_svn_from_git: env: SVN_REPO_PATH: "${{ github.workspace }}/svn_repository" SVN_REPO_ROOT: "${{ github.workspace }}/svn_repository/${{ inputs.SVN_PLUGIN_SLUG }}" @@ -129,10 +129,10 @@ jobs: 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 @@ -157,7 +157,7 @@ jobs: set -euo pipefail touch .distignore # Ensure file exists so --exclude-from doesn't fail - + rsync -rc \ --delete \ --delete-excluded \ @@ -174,10 +174,10 @@ jobs: - 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 @@ -185,7 +185,7 @@ jobs: done fi - - name: Commit trunk to SVN repository + - name: Commit changes to SVN repository if: inputs.DRY_RUN != true env: SVN_USERNAME: ${{ secrets.SVN_USERNAME }} @@ -200,7 +200,7 @@ jobs: # 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 trunk...' + echo '🚀 Committing...' svn commit trunk \ --username "$SVN_USERNAME" \ @@ -209,7 +209,16 @@ jobs: --non-interactive \ -m "Update trunk to version ${VALIDATED_PLUGIN_VERSION}" - echo "✅ Trunk updated to 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 @@ -219,34 +228,3 @@ jobs: path: ${{ env.SVN_REPO_ROOT }}/trunk include-hidden-files: true compression-level: 1 #Minimal compression - we don't want to waste resources for this - - create_tag: - needs: push_trunk - if: inputs.DRY_RUN != true - environment: wordpress-org-release - runs-on: ubuntu-latest - steps: - - name: Install subversion - run: | - sudo apt-get update -y - sudo apt-get install -y subversion - - - name: Create SVN tag - env: - SVN_USERNAME: ${{ secrets.SVN_USERNAME }} - SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} - run: | - set -euo pipefail - - echo '🚀 Creating tag...' - - svn copy \ - "https://plugins.svn.wordpress.org/${{ inputs.SVN_PLUGIN_SLUG }}/trunk" \ - "https://plugins.svn.wordpress.org/${{ inputs.SVN_PLUGIN_SLUG }}/tags/${{ inputs.PLUGIN_VERSION }}" \ - --username "$SVN_USERNAME" \ - --password "$SVN_PASSWORD" \ - --no-auth-cache \ - --non-interactive \ - -m "Tagging version ${{ inputs.PLUGIN_VERSION }}" - - echo "✅ Version ${{ inputs.PLUGIN_VERSION }} was published to WordPress.org" From 5e930b75c60a4f1454a11cbb4ed4ca0e39426523 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Mon, 11 May 2026 18:30:40 +0300 Subject: [PATCH 55/64] Make creating a tag conditional --- .github/workflows/wordpress-org-release.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 5c47c988f..838cd3113 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -26,6 +26,12 @@ on: 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 @@ -209,6 +215,17 @@ jobs: --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}" \ From 02357c2d998159c2a067df19aaf0e854f46c7d1d Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Mon, 11 May 2026 19:21:18 +0300 Subject: [PATCH 56/64] Remove extra new line --- .github/workflows/wordpress-org-release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index 838cd3113..df3c62539 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -215,7 +215,6 @@ jobs: --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: From d3a463b44cf2fbdc13195de5e1b450a00a539c26 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Mon, 11 May 2026 19:51:24 +0300 Subject: [PATCH 57/64] Skip version check when updating trunk only --- .github/workflows/wordpress-org-release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index df3c62539..c8eb1fd22 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -143,6 +143,7 @@ jobs: 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 From 513b778d074464fcc822e2b5add407b0d2dcb165 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Mon, 11 May 2026 19:54:10 +0300 Subject: [PATCH 58/64] Remove extra space --- .github/workflows/wordpress-org-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index c8eb1fd22..ab7a711b9 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -217,7 +217,7 @@ jobs: -m "Update trunk to version ${VALIDATED_PLUGIN_VERSION}" - name: Create a new tag - if: inputs.UPDATE_TRUNK_ONLY == false && inputs.DRY_RUN != true + if: inputs.UPDATE_TRUNK_ONLY == false && inputs.DRY_RUN != true env: SVN_USERNAME: ${{ secrets.SVN_USERNAME }} SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} From a9414c55321547fcf320bc06de8949d88ff334e2 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Mon, 11 May 2026 20:38:00 +0300 Subject: [PATCH 59/64] Add documentation --- docs/wordpress-org-release.md | 89 +++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 docs/wordpress-org-release.md diff --git a/docs/wordpress-org-release.md b/docs/wordpress-org-release.md new file mode 100644 index 000000000..17debb1a1 --- /dev/null +++ b/docs/wordpress-org-release.md @@ -0,0 +1,89 @@ +# WordPress.org Release + +This reusable workflow publishes a WordPress plugin to the [WordPress.org plugin directory](https://wordpress.org/plugins/) via SVN. + +To achieve that, this workflow: + +1. Validates that `PLUGIN_VERSION` is formatted as `MAJOR.MINOR.PATCH` +2. Checks out the Git repository at `GIT_REF` +3. Verifies that the version in the plugin file header and `readme.txt` `Stable tag` both match `PLUGIN_VERSION` +4. Checks out the WordPress.org SVN repository (trunk is fully checked out; tag contents are never fetched — only tag names are listed when needed for the version check) +5. Verifies the version does not already exist as an SVN tag (skipped when `UPDATE_TRUNK_ONLY=true`) +6. Synchronizes the Git working directory to SVN trunk via `rsync`, respecting `.distignore` and excluding sensitive files like `auth.json`, `.env`, and `.npmrc` +7. Commits trunk to SVN (or uploads it as an artifact in `DRY_RUN` mode) +8. Creates an SVN tag from trunk (skipped when `UPDATE_TRUNK_ONLY=true` or `DRY_RUN=true`) + +> [!NOTE] +> This workflow intentionally fails if the version already exists as an SVN tag. There is no amendment flow. + +## Simple usage example + +```yml +name: Publish to WordPress.org +on: + workflow_dispatch: + inputs: + PLUGIN_VERSION: + description: 'Version to publish (MAJOR.MINOR.PATCH)' + required: true + GIT_REF: + description: 'Git tag or branch to publish' + required: true + UPDATE_TRUNK_ONLY: + description: 'Only update trunk, skip tag creation' + type: boolean + default: true +jobs: + publish: + uses: inpsyde/reusable-workflows/.github/workflows/wordpress-org-release.yml@main + with: + SVN_PLUGIN_SLUG: my-plugin + PLUGIN_VERSION: ${{ inputs.PLUGIN_VERSION }} + GIT_REF: ${{ inputs.GIT_REF }} + UPDATE_TRUNK_ONLY: ${{ inputs.UPDATE_TRUNK_ONLY == 'true' }} + secrets: + SVN_USERNAME: ${{ secrets.SVN_USERNAME }} + SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} + GITHUB_USER_SSH_KEY: ${{ secrets.GITHUB_USER_SSH_KEY }} +``` + +## Staged release (trunk first, tag later) + +To verify trunk on WordPress.org before publishing, run the workflow twice with the same inputs — first with `UPDATE_TRUNK_ONLY: true` (the default), then with `UPDATE_TRUNK_ONLY: false` once trunk looks correct. + +> [!WARNING] +> When `UPDATE_TRUNK_ONLY=true`, the `Stable tag` in `readme.txt` must point to an **already-released** version. If it references a version that doesn't exist as an SVN tag yet, WordPress.org may fall back to serving trunk as the stable release. + +## Configuration parameters + +### Inputs + +| Name | Default | Description | +|---|---|---| +| `SVN_PLUGIN_SLUG` | — | WordPress.org plugin slug (e.g. `my-plugin`) | +| `PLUGIN_VERSION` | — | Version to publish, must be `MAJOR.MINOR.PATCH` | +| `GIT_REF` | — | Git ref to publish (tag, branch, or commit SHA) | +| `DRY_RUN` | `false` | Upload trunk as an artifact instead of committing to SVN | +| `UPDATE_TRUNK_ONLY` | `true` | Sync trunk only; skip tag creation | + +### Secrets + +| Name | Required | Description | +|---|---|---| +| `SVN_USERNAME` | yes | WordPress.org SVN username | +| `SVN_PASSWORD` | yes | WordPress.org SVN password | +| `GITHUB_USER_SSH_KEY` | yes | SSH key used to check out the Git repository | + +> [!NOTE] +> WordPress.org SVN does not support SSH keys or tokens. The `SVN_USERNAME` and `SVN_PASSWORD` secrets are the only supported authentication method. + +## File exclusions + +The following files are always excluded from the SVN sync, regardless of `.distignore`: + +- `.git`, `.svn` +- `.env`, `.env.*` +- `auth.json`, `.npmrc` +- `.distignore` itself + +Additional exclusions can be specified via a `.distignore` file in the repository root (same format used by `wp dist-archive`). From 3093a63a04b16c1d4e5232bfc2be623e20127c31 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Tue, 12 May 2026 18:47:40 +0300 Subject: [PATCH 60/64] Update documentation --- docs/wordpress-org-release.md | 68 +++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/docs/wordpress-org-release.md b/docs/wordpress-org-release.md index 17debb1a1..a0b9392aa 100644 --- a/docs/wordpress-org-release.md +++ b/docs/wordpress-org-release.md @@ -18,6 +18,70 @@ To achieve that, this workflow: ## Simple usage example +This workflow cannot be triggered directly. Create a workflow file in your plugin's repository that calls it via `uses:`, as shown below. + +```yml +name: Publish to WordPress.org +on: + workflow_dispatch: + inputs: + PLUGIN_VERSION: + description: 'Version to publish (MAJOR.MINOR.PATCH)' + required: true + GIT_REF: + description: 'Git tag or branch to publish' + required: true + UPDATE_TRUNK_ONLY: + description: 'Only update trunk, skip tag creation' + type: boolean + default: true +jobs: + publish: + uses: inpsyde/reusable-workflows/.github/workflows/wordpress-org-release.yml@main + with: + SVN_PLUGIN_SLUG: my-plugin + PLUGIN_VERSION: ${{ inputs.PLUGIN_VERSION }} + GIT_REF: ${{ inputs.GIT_REF }} + UPDATE_TRUNK_ONLY: ${{ inputs.UPDATE_TRUNK_ONLY == 'true' }} + secrets: + SVN_USERNAME: ${{ secrets.SVN_USERNAME }} + SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} + GITHUB_USER_SSH_KEY: ${{ secrets.GITHUB_USER_SSH_KEY }} +``` + +## Trigger on Git tag push + +If your release process creates a Git tag named after the version (e.g. `1.2.3`), the version can be derived directly from the tag — no manual input needed: + +```yml +name: Publish to WordPress.org +on: + push: + tags: ['[0-9]+.[0-9]+.[0-9]+'] +jobs: + publish: + uses: inpsyde/reusable-workflows/.github/workflows/wordpress-org-release.yml@main + with: + SVN_PLUGIN_SLUG: my-plugin + PLUGIN_VERSION: ${{ github.ref_name }} + GIT_REF: ${{ github.ref }} + UPDATE_TRUNK_ONLY: false + secrets: + SVN_USERNAME: ${{ secrets.SVN_USERNAME }} + SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} + GITHUB_USER_SSH_KEY: ${{ secrets.GITHUB_USER_SSH_KEY }} +``` + +> [!NOTE] +> This pattern requires tags to be named as bare versions (`1.2.3`, not `v1.2.3`). If your project uses `v`-prefixed tags, strip the prefix before passing it: `PLUGIN_VERSION: ${{ github.ref_name }}` would need to become a separate step that outputs `${GITHUB_REF_NAME#v}`. + +> [!WARNING] +> The version derived from the Git tag must match the `Version:` header in the main plugin file and the `Stable tag` in `readme.txt`. The workflow will fail if they don't all agree. Make sure these are updated in the same commit that the tag points to. + +## Advanced usage: requiring manual approval before tagging + +To require a manual approval step before the SVN tag is created, add an `environment:` key to the calling job and configure protection rules (required reviewers, wait timers, etc.) for that environment in your repository settings under **Settings → Environments**. + ```yml name: Publish to WordPress.org on: @@ -35,6 +99,7 @@ on: default: true jobs: publish: + environment: wordpress-org-release # enforces protection rules configured in repository settings uses: inpsyde/reusable-workflows/.github/workflows/wordpress-org-release.yml@main with: SVN_PLUGIN_SLUG: my-plugin @@ -47,6 +112,9 @@ jobs: GITHUB_USER_SSH_KEY: ${{ secrets.GITHUB_USER_SSH_KEY }} ``` +> [!NOTE] +> The `environment:` key alone does nothing — protection rules must be explicitly configured in repository settings. An environment with no rules configured provides no approval gate. + ## Staged release (trunk first, tag later) To verify trunk on WordPress.org before publishing, run the workflow twice with the same inputs — first with `UPDATE_TRUNK_ONLY: true` (the default), then with `UPDATE_TRUNK_ONLY: false` once trunk looks correct. From 94a0e038a9e4d24d78d14a968efd7b35b504f373 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Tue, 12 May 2026 18:52:32 +0300 Subject: [PATCH 61/64] Update documentation --- docs/wordpress-org-release.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/wordpress-org-release.md b/docs/wordpress-org-release.md index a0b9392aa..3a5b652d6 100644 --- a/docs/wordpress-org-release.md +++ b/docs/wordpress-org-release.md @@ -57,7 +57,7 @@ If your release process creates a Git tag named after the version (e.g. `1.2.3`) name: Publish to WordPress.org on: push: - tags: ['[0-9]+.[0-9]+.[0-9]+'] + tags: ['[0-9]*.[0-9]*.[0-9]*'] jobs: publish: uses: inpsyde/reusable-workflows/.github/workflows/wordpress-org-release.yml@main @@ -126,13 +126,13 @@ To verify trunk on WordPress.org before publishing, run the workflow twice with ### Inputs -| Name | Default | Description | -|---|---|---| -| `SVN_PLUGIN_SLUG` | — | WordPress.org plugin slug (e.g. `my-plugin`) | -| `PLUGIN_VERSION` | — | Version to publish, must be `MAJOR.MINOR.PATCH` | -| `GIT_REF` | — | Git ref to publish (tag, branch, or commit SHA) | -| `DRY_RUN` | `false` | Upload trunk as an artifact instead of committing to SVN | -| `UPDATE_TRUNK_ONLY` | `true` | Sync trunk only; skip tag creation | +| Name | Required | Default | Description | +|---|---|---|---| +| `SVN_PLUGIN_SLUG` | yes | — | WordPress.org plugin slug (e.g. `my-plugin`) | +| `PLUGIN_VERSION` | yes | — | Version to publish, must be `MAJOR.MINOR.PATCH` | +| `GIT_REF` | yes | — | Git ref to publish (tag, branch, or commit SHA) | +| `DRY_RUN` | no | `false` | Upload trunk as an artifact instead of committing to SVN | +| `UPDATE_TRUNK_ONLY` | no | `true` | Sync trunk only; skip tag creation | ### Secrets From 42464c41199a92013e69eb68723c37b774a253bf Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Tue, 12 May 2026 19:11:33 +0300 Subject: [PATCH 62/64] Update documentation --- docs/wordpress-org-release.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/wordpress-org-release.md b/docs/wordpress-org-release.md index 3a5b652d6..462b556d2 100644 --- a/docs/wordpress-org-release.md +++ b/docs/wordpress-org-release.md @@ -16,6 +16,9 @@ To achieve that, this workflow: > [!NOTE] > This workflow intentionally fails if the version already exists as an SVN tag. There is no amendment flow. +> [!IMPORTANT] +> The plugin's SVN repository must already exist on WordPress.org before running this workflow — including in `DRY_RUN` mode. Initial plugin submission requires a separate manual process via the [WordPress.org plugin submission form](https://wordpress.org/plugins/developers/add/). + ## Simple usage example This workflow cannot be triggered directly. Create a workflow file in your plugin's repository that calls it via `uses:`, as shown below. From 736ff07bd3f11a55ff7dffb3f104f7c04e8a0a53 Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Tue, 12 May 2026 19:16:34 +0300 Subject: [PATCH 63/64] Add plugin slug validation --- .github/workflows/wordpress-org-release.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/wordpress-org-release.yml b/.github/workflows/wordpress-org-release.yml index ab7a711b9..03e8122b7 100644 --- a/.github/workflows/wordpress-org-release.yml +++ b/.github/workflows/wordpress-org-release.yml @@ -54,6 +54,20 @@ jobs: 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 }} From 8b570af3f6777acf39bfcf14e22b72c37e220b6e Mon Sep 17 00:00:00 2001 From: Kyrylo Date: Tue, 12 May 2026 19:40:26 +0300 Subject: [PATCH 64/64] Update documentation --- docs/wordpress-org-release.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/wordpress-org-release.md b/docs/wordpress-org-release.md index 462b556d2..770c7ba3e 100644 --- a/docs/wordpress-org-release.md +++ b/docs/wordpress-org-release.md @@ -123,7 +123,10 @@ jobs: To verify trunk on WordPress.org before publishing, run the workflow twice with the same inputs — first with `UPDATE_TRUNK_ONLY: true` (the default), then with `UPDATE_TRUNK_ONLY: false` once trunk looks correct. > [!WARNING] -> When `UPDATE_TRUNK_ONLY=true`, the `Stable tag` in `readme.txt` must point to an **already-released** version. If it references a version that doesn't exist as an SVN tag yet, WordPress.org may fall back to serving trunk as the stable release. +> When `UPDATE_TRUNK_ONLY=true`, the version existence check is skipped. Do not leave trunk with a `Stable tag` pointing to a non-existent SVN tag — [WordPress.org will serve the plugin from trunk instead](https://developer.wordpress.org/plugins/wordpress-org/how-your-readme-txt-works/#how-the-readme-is-parsed). Keep `Stable tag` pointing to the latest published version. + +> [!NOTE] +> WordPress.org reads `readme.txt` from the tag that `Stable tag` points to, not from trunk. Updating `readme.txt` in trunk alone will not update the plugin page — a new tag must be created. ## Configuration parameters