From a27347851b62587dfb85c888ddf370eeb8c810c6 Mon Sep 17 00:00:00 2001
From: Philipp Stracker
Date: Wed, 6 May 2026 14:58:43 +0200
Subject: [PATCH 1/7] Exclude non-version tags from release detection
---
.github/workflows/build-and-distribute.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/build-and-distribute.yml b/.github/workflows/build-and-distribute.yml
index 4550d057..a0661ea2 100644
--- a/.github/workflows/build-and-distribute.yml
+++ b/.github/workflows/build-and-distribute.yml
@@ -139,7 +139,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_USER_SSH_KEY }}
run: |
# Fetch latest public release
- LATEST_RELEASE=$(git for-each-ref --sort=-creatordate --count=1 --format='%(refname:short)' refs/tags || echo "")
+ LATEST_RELEASE=$(git for-each-ref --sort=-creatordate --count=1 --format='%(refname:short)' 'refs/tags/[0-9]*' || echo "")
if [ -z "$LATEST_RELEASE" ]; then
echo "No releases found, using default version 0.0.0."
From 8bee3257ab56a19659804b28ca41f9174fd92bb5 Mon Sep 17 00:00:00 2001
From: Philipp Stracker
Date: Wed, 6 May 2026 16:16:23 +0200
Subject: [PATCH 2/7] Extract version tags with optional "v" prefix
New logic extracts the first tag that does not
have a "/" in it and starts with a digit, or the
letter "v" followed by a digit
---
.github/workflows/build-and-distribute.yml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/build-and-distribute.yml b/.github/workflows/build-and-distribute.yml
index a0661ea2..3b41080e 100644
--- a/.github/workflows/build-and-distribute.yml
+++ b/.github/workflows/build-and-distribute.yml
@@ -139,7 +139,10 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_USER_SSH_KEY }}
run: |
# Fetch latest public release
- LATEST_RELEASE=$(git for-each-ref --sort=-creatordate --count=1 --format='%(refname:short)' 'refs/tags/[0-9]*' || echo "")
+ LATEST_RELEASE=$(git for-each-ref --sort=-creatordate --format='%(refname:short)' refs/tags \
+ | grep -E '^v?[0-9]' \
+ | grep -v '/' \
+ | head -1 || echo "")
if [ -z "$LATEST_RELEASE" ]; then
echo "No releases found, using default version 0.0.0."
From df04f73e23381b0b5dca7cce017dd07cb3d9bc17 Mon Sep 17 00:00:00 2001
From: Philipp Stracker
Date: Wed, 6 May 2026 16:20:12 +0200
Subject: [PATCH 3/7] Prefer GH release API for latest release
Keep the existing tag based logic as fallback if
the release API fails for some reason
---
.github/workflows/build-and-distribute.yml | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/build-and-distribute.yml b/.github/workflows/build-and-distribute.yml
index 3b41080e..b3b613ba 100644
--- a/.github/workflows/build-and-distribute.yml
+++ b/.github/workflows/build-and-distribute.yml
@@ -139,10 +139,15 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_USER_SSH_KEY }}
run: |
# Fetch latest public release
- LATEST_RELEASE=$(git for-each-ref --sort=-creatordate --format='%(refname:short)' refs/tags \
- | grep -E '^v?[0-9]' \
- | grep -v '/' \
- | head -1 || echo "")
+ LATEST_RELEASE=$(gh release list --limit 1 --json tagName --jq '.[0].tagName' || echo "")
+
+ # Fallback: Fetch latest version tag (supports 1.2.3 and v1.2.3, ignores tags with slashes)
+ if [[ -z $LATEST_RELEASE ]]; then
+ LATEST_RELEASE=$(git for-each-ref --sort=-creatordate --format='%(refname:short)' refs/tags \
+ | grep -E '^v?[0-9]' \
+ | grep -v '/' \
+ | head -1 || echo "")
+ fi
if [ -z "$LATEST_RELEASE" ]; then
echo "No releases found, using default version 0.0.0."
From 37fbc05c85d592af4f24088a301a9ab8c7647b00 Mon Sep 17 00:00:00 2001
From: Philipp Stracker
Date: Wed, 13 May 2026 17:54:30 +0200
Subject: [PATCH 4/7] Remove fallback logic for LATEST_RELEASE lookup
---
.github/workflows/build-and-distribute.yml | 8 --------
1 file changed, 8 deletions(-)
diff --git a/.github/workflows/build-and-distribute.yml b/.github/workflows/build-and-distribute.yml
index b3b613ba..84c35813 100644
--- a/.github/workflows/build-and-distribute.yml
+++ b/.github/workflows/build-and-distribute.yml
@@ -141,14 +141,6 @@ jobs:
# Fetch latest public release
LATEST_RELEASE=$(gh release list --limit 1 --json tagName --jq '.[0].tagName' || echo "")
- # Fallback: Fetch latest version tag (supports 1.2.3 and v1.2.3, ignores tags with slashes)
- if [[ -z $LATEST_RELEASE ]]; then
- LATEST_RELEASE=$(git for-each-ref --sort=-creatordate --format='%(refname:short)' refs/tags \
- | grep -E '^v?[0-9]' \
- | grep -v '/' \
- | head -1 || echo "")
- fi
-
if [ -z "$LATEST_RELEASE" ]; then
echo "No releases found, using default version 0.0.0."
LATEST_RELEASE="0.0.0"
From 1304d5cb4673ffa2b5cc397adee91b50d13d8651 Mon Sep 17 00:00:00 2001
From: Philipp Stracker
Date: Thu, 21 May 2026 12:56:19 +0200
Subject: [PATCH 5/7] Document change in LATEST_RELEASE detection
---
docs/build-and-distribute.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/build-and-distribute.md b/docs/build-and-distribute.md
index c1284cab..cc40679b 100644
--- a/docs/build-and-distribute.md
+++ b/docs/build-and-distribute.md
@@ -29,10 +29,10 @@ This approach keeps source code separate from build artifacts while maintaining
If no `PACKAGE_VERSION` is provided, the workflow automatically:
-1. Fetches the latest tag from the repository
+1. Fetches the latest GitHub Release from the repository
2. Strips the `dev/` prefix from the branch name and normalizes it to be semver-compatible
3. Creates a pre-release version like `1.2.3-main` or `2.0.0-abc-123`
-4. Falls back to `0.0.0-{branch}` if no tags exist
+4. Falls back to `0.0.0-{branch}` if no published release exists
**Examples:**
@@ -121,7 +121,7 @@ jobs:
| `PHP_TOOLS` | `''` | PHP tools supported by shivammathur/setup-php to be installed |
| `COMPOSER_ARGS` | `'--no-dev --prefer-dist --optimize-autoloader'` | Set of arguments passed to Composer when gathering production dependencies |
| `PACKAGE_NAME` | `''` | The name of the package (falls back to the repository name) |
-| `PACKAGE_VERSION` | `''` | The new package version. If not provided, will use latest tag version with branch name as pre-release identifier |
+| `PACKAGE_VERSION` | `''` | The new package version. If not provided, will use the latest GitHub Release version with branch name as pre-release identifier |
| `PRE_SCRIPT` | `''` | Run custom shell code before creating the release archive |
| `BUILT_BRANCH_NAME` | `''` | Override the automatic build branch naming (defaults to stripping `dev/` prefix from origin branch) |
From 057b338af9795ce822bd83aea2a624e997921f2f Mon Sep 17 00:00:00 2001
From: Philipp Stracker
Date: Thu, 21 May 2026 13:01:19 +0200
Subject: [PATCH 6/7] Document semver requirement and format samples
---
docs/build-and-distribute.md | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/docs/build-and-distribute.md b/docs/build-and-distribute.md
index cc40679b..c6799a2a 100644
--- a/docs/build-and-distribute.md
+++ b/docs/build-and-distribute.md
@@ -42,6 +42,34 @@ If no `PACKAGE_VERSION` is provided, the workflow automatically:
This ensures every build has a unique, meaningful version identifier that traces back to both the base release and the source branch.
+### GitHub Release tag format
+
+The latest GitHub Release tag is used as the base for `PACKAGE_VERSION` and is validated by `npm version` against semver. Release tags must therefore exactly match this pattern:
+
+```
+[v]MAJOR.MINOR.PATCH[-IDENTIFIER]
+```
+
+
+Valid and invalid samples
+
+**Valid:**
+- `1.2.3`
+- `v1.2.3`
+- `1.2.3-alpha`
+- `1.2.3-feature.1`
+- `1.2.3-2026-05-21`
+
+**Invalid:**
+- `1.2` → missing PATCH
+- `1.2.3.4` → too many segments
+- `1.2.3-` → empty identifier
+- `v.1.2.3` → dot after `v`
+- `a.b.c` → non-numeric segments
+- `release/1.2.3` → contains a slash
+
+
+
## Simple usage example
### WordPress Plugin/Theme or PHP Library
From 77b623e301217708dc7474343ec49fb7e4166e37 Mon Sep 17 00:00:00 2001
From: Philipp Stracker
Date: Thu, 21 May 2026 13:02:27 +0200
Subject: [PATCH 7/7] Lint the updated Markdown file
---
docs/build-and-distribute.md | 27 ++++++++++++++-------------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/docs/build-and-distribute.md b/docs/build-and-distribute.md
index c6799a2a..f7618ac0 100644
--- a/docs/build-and-distribute.md
+++ b/docs/build-and-distribute.md
@@ -54,6 +54,7 @@ The latest GitHub Release tag is used as the base for `PACKAGE_VERSION` and is v
Valid and invalid samples
**Valid:**
+
- `1.2.3`
- `v1.2.3`
- `1.2.3-alpha`
@@ -61,6 +62,7 @@ The latest GitHub Release tag is used as the base for `PACKAGE_VERSION` and is v
- `1.2.3-2026-05-21`
**Invalid:**
+
- `1.2` → missing PATCH
- `1.2.3.4` → too many segments
- `1.2.3-` → empty identifier
@@ -139,20 +141,19 @@ jobs:
### Inputs
-| Name | Default | Description |
-|-----------------------|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------|
-| `NODE_OPTIONS` | `''` | Space-separated list of command-line Node options |
-| `NODE_VERSION` | `18` | Node version with which the assets will be compiled |
-| `NPM_REGISTRY_DOMAIN` | `'https://npm.pkg.github.com/'` | Domain of the private npm registry |
-| `PHP_VERSION` | `'8.2'` | PHP version with which the PHP tools are to be executed |
-| `PHP_EXTENSIONS` | `''` | PHP extensions supported by shivammathur/setup-php to be installed or disabled |
-| `PHP_TOOLS` | `''` | PHP tools supported by shivammathur/setup-php to be installed |
-| `COMPOSER_ARGS` | `'--no-dev --prefer-dist --optimize-autoloader'` | Set of arguments passed to Composer when gathering production dependencies |
-| `PACKAGE_NAME` | `''` | The name of the package (falls back to the repository name) |
+| Name | Default | Description |
+|-----------------------|--------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|
+| `NODE_OPTIONS` | `''` | Space-separated list of command-line Node options |
+| `NODE_VERSION` | `18` | Node version with which the assets will be compiled |
+| `NPM_REGISTRY_DOMAIN` | `'https://npm.pkg.github.com/'` | Domain of the private npm registry |
+| `PHP_VERSION` | `'8.2'` | PHP version with which the PHP tools are to be executed |
+| `PHP_EXTENSIONS` | `''` | PHP extensions supported by shivammathur/setup-php to be installed or disabled |
+| `PHP_TOOLS` | `''` | PHP tools supported by shivammathur/setup-php to be installed |
+| `COMPOSER_ARGS` | `'--no-dev --prefer-dist --optimize-autoloader'` | Set of arguments passed to Composer when gathering production dependencies |
+| `PACKAGE_NAME` | `''` | The name of the package (falls back to the repository name) |
| `PACKAGE_VERSION` | `''` | The new package version. If not provided, will use the latest GitHub Release version with branch name as pre-release identifier |
-| `PRE_SCRIPT` | `''` | Run custom shell code before creating the release archive |
-| `BUILT_BRANCH_NAME` | `''` | Override the automatic build branch naming (defaults to stripping `dev/` prefix from origin branch) |
-
+| `PRE_SCRIPT` | `''` | Run custom shell code before creating the release archive |
+| `BUILT_BRANCH_NAME` | `''` | Override the automatic build branch naming (defaults to stripping `dev/` prefix from origin branch) |
#### A note on `BUILT_BRANCH_NAME`