Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc0aaf9272 | ||
|
|
f6ea46a93e | ||
|
|
2b289c6763 |
+6
-2
@@ -2,9 +2,9 @@
|
||||
Contributors: kristianwind
|
||||
Tags: woocommerce, discount, email, shipping, coupon
|
||||
Requires at least: 5.8
|
||||
Tested up to: 7.1
|
||||
Tested up to: 7.1.2
|
||||
Requires PHP: 7.4
|
||||
Stable tag: 1.6.1
|
||||
Stable tag: 1.6.2
|
||||
WC requires at least: 6.0
|
||||
WC tested up to: 11.1.0
|
||||
License: GPLv2 or later
|
||||
@@ -96,6 +96,10 @@ The most specific match wins: exact email, then domain, then partial match.
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 1.6.2 =
|
||||
* Declares compatibility with WordPress 7.1.2 and WooCommerce 11.1.2, both tested. No functional change.
|
||||
|
||||
|
||||
= 1.6.1 =
|
||||
* The status label on the Nolimit dashboard card is now readable. It was white text on a light overlay, which on this plugin's green gave 3.5:1 where 4.5:1 is the accessibility minimum.
|
||||
|
||||
|
||||
@@ -60,10 +60,15 @@ done
|
||||
git diff --quiet && { echo "Nothing actually changed on disk — check the sed patterns." >&2; exit 1; }
|
||||
|
||||
branch="compat/tested-up-to-$current_wp-wc-$current_wc"
|
||||
git config user.name "compatibility check"
|
||||
git config user.email "noreply@localhost"
|
||||
git checkout -b "$branch"
|
||||
git commit -am "Tested against WordPress $current_wp and WooCommerce $current_wc
|
||||
# The identity is scoped to THIS commit with `git -c`, never written to the
|
||||
# clone. `git config user.name` persists in .git/config, so every later commit
|
||||
# in this working copy — a release days afterwards, by a person — would be
|
||||
# authored by the robot with no Co-Authored-By trailer. git announces a
|
||||
# MISSING identity and says nothing about a wrong one, so that is silent.
|
||||
# Signing this one commit as the robot is right: it is not a person's.
|
||||
git -c user.name="compatibility check" -c user.email="noreply@localhost" \
|
||||
commit -am "Tested against WordPress $current_wp and WooCommerce $current_wc
|
||||
|
||||
$(printf '%s\n' "${changed[@]}")
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ ci_load_conf() {
|
||||
# leaves the floors empty, every comparison becomes a no-op, and the hollow
|
||||
# checks these were added to fix come back silently — the same shape of bug.
|
||||
local missing=
|
||||
for var in PLUGIN_SLUG PLUGIN_MAIN TEXT_DOMAIN NEEDS_WOOCOMMERCE MIN_SHIPPED_PHP_FILES MIN_TRANSLATION_CALLS RELEASE_REPO WPMGR_MENU_SHA OLD_PLUGIN_NAME; do
|
||||
for var in PLUGIN_SLUG PLUGIN_MAIN TEXT_DOMAIN NEEDS_WOOCOMMERCE MIN_SHIPPED_PHP_FILES MIN_TRANSLATION_CALLS RELEASE_REPO WPMGR_MENU_SHA OLD_PLUGIN_NAME MIN_SITE_ASSERTIONS; do
|
||||
[ -n "${!var:-}" ] || missing="$missing $var"
|
||||
done
|
||||
if [ -n "$missing" ]; then
|
||||
|
||||
@@ -103,3 +103,9 @@ WPMGR_MENU_SHA=75b04eb4fe9eda0119312075accf2fc77de244e5c6b759d624a8b1d254c0fc99
|
||||
# can fail when it reappears in text a user reads — a sentence that goes stale
|
||||
# breaks nothing by itself, which is why it survives.
|
||||
OLD_PLUGIN_NAME="WooCommerce Email Discount Manager"
|
||||
|
||||
# The fewest assertions a complete run of tests/smoke.php prints. Verified by
|
||||
# ci/site-test.sh rather than only inside the file: a smoke file runs in
|
||||
# function scope, so a `return` partway through skips its own floor and the
|
||||
# run reports green having tested two thirds of what it claims.
|
||||
MIN_SITE_ASSERTIONS=60
|
||||
|
||||
@@ -205,6 +205,54 @@ ann=$(ci_php ci/check-textdomain.php "$TEXT_DOMAIN" selftest-dotted 2>&1 \
|
||||
&& ok "the annotated path exists on disk: $ann" \
|
||||
|| bad "the annotated path is not a file: '$ann'"
|
||||
|
||||
# ------------------------------------------------------- the clone's git identity
|
||||
# 🔴 Grade 2 evidence: the exact line ci/bump-tested-up-to.sh carried until
|
||||
# 2026-09-25, not an arbitrary `git config`. That line writes .git/config, so
|
||||
# every later commit in the clone — a release, by a person — is authored by the
|
||||
# robot with no trailer. Six such commits in one sibling plugin, two in
|
||||
# another. git warns about an identity it cannot FIND and never about a wrong
|
||||
# one, so nothing in the repository ever says so.
|
||||
echo
|
||||
echo "→ ci/static.sh must catch a ci/ script that configures the clone"
|
||||
cd "$work/repo"
|
||||
cp ci/build-zip.sh "$work/build-zip.orig"
|
||||
for scope in '' '--local' '--global'; do
|
||||
cp "$work/build-zip.orig" ci/build-zip.sh
|
||||
line="git config ${scope:+$scope }user.name \"compatibility check\""
|
||||
printf '%s\n' "$line" >> ci/build-zip.sh
|
||||
# The plant must BE there before any verdict is believed. A `printf` that
|
||||
# silently went somewhere else leaves the control state, and every assertion
|
||||
# below then passes while proving nothing — a hollow probe wearing the
|
||||
# costume of the most rigorous thing in the suite.
|
||||
if [ "$(grep -cF "$line" ci/build-zip.sh)" -lt 1 ]; then
|
||||
bad "could not stage the git-identity fixture for '${scope:-no flag}'"
|
||||
continue
|
||||
fi
|
||||
id_out=$(./ci/static.sh 2>&1 || true)
|
||||
if printf '%s' "$id_out" | grep -q 'sets a git identity that outlives it'; then
|
||||
ok "flagged git config ${scope:-(no flag)} user.name"
|
||||
else
|
||||
bad "NOT FLAGGED: git config ${scope:-(no flag)} user.name — the clone keeps the robot's name"
|
||||
fi
|
||||
done
|
||||
|
||||
# The correct form must NOT fire, or the fix trips the check that exists to
|
||||
# protect it and the next person deletes one of the two.
|
||||
cp "$work/build-zip.orig" ci/build-zip.sh
|
||||
printf '%s\n' 'git -c user.name="compatibility check" -c user.email=x commit -m y' >> ci/build-zip.sh
|
||||
scoped_out=$(./ci/static.sh 2>&1 || true)
|
||||
printf '%s' "$scoped_out" | grep -q 'sets a git identity that outlives it' \
|
||||
&& bad "FALSE POSITIVE on 'git -c user.name=… commit' — that is the fix, not the fault" \
|
||||
|| ok "ignored the scoped 'git -c … commit' form"
|
||||
cp "$work/build-zip.orig" ci/build-zip.sh
|
||||
|
||||
# And the passing line must carry a number: "every script is clean" reads the
|
||||
# same over zero files as over eleven.
|
||||
clean_out=$(./ci/static.sh 2>&1 || true)
|
||||
printf '%s' "$clean_out" | grep -qE "^ [0-9]+ scripts in ci/ leave the clone's git identity alone" \
|
||||
&& ok "the git-identity check reports how many scripts it read" \
|
||||
|| bad "the git-identity check printed no count — it cannot tell 11 scripts from 0"
|
||||
|
||||
# ------------------------------------------------------------------- plugin.conf
|
||||
echo
|
||||
echo "→ the floors must be required, not defaulted"
|
||||
|
||||
+31
-1
@@ -177,9 +177,39 @@ wp plugin list --name="$PLUGIN_SLUG" --field=status | grep -qx active \
|
||||
|| { echo "The plugin did not stay active after activation." >&2; exit 1; }
|
||||
echo " activated $(wp plugin get "$PLUGIN_SLUG" --field=version)"
|
||||
|
||||
# 🔴 The output is captured and the summary checked HERE, by the caller.
|
||||
#
|
||||
# A smoke file cannot assert about its own early exit: `wp eval-file` runs it
|
||||
# in function scope, so a `return` partway through skips everything after it —
|
||||
# including any floor the file carries at the bottom. Measured: truncating
|
||||
# tests/smoke.php before the shipping section ran two thirds of the assertions
|
||||
# and this script reported green, because the file's own floor was one of the
|
||||
# things never reached.
|
||||
#
|
||||
# So the number the file prints is verified against MIN_SITE_ASSERTIONS out
|
||||
# here, where an early return cannot reach. The floor inside the file stays as
|
||||
# well; it catches a short run that still gets to the end.
|
||||
for f in ${SITE_TESTS:-}; do
|
||||
ci_step "$f"
|
||||
wp eval-file "wp-content/plugins/$PLUGIN_SLUG/$f"
|
||||
out=$(wp eval-file "wp-content/plugins/$PLUGIN_SLUG/$f" 2>&1) || { printf '%s\n' "$out"; exit 1; }
|
||||
printf '%s\n' "$out"
|
||||
|
||||
case "$f" in
|
||||
*smoke*)
|
||||
ran=$(printf '%s' "$out" | sed -n -E 's/^All ([0-9]+) assertions passed.*/\1/p' | tail -1)
|
||||
if [ -z "$ran" ]; then
|
||||
echo
|
||||
ci_fail "$f printed no assertion total. It exited before its summary — which is what a file that returned halfway through looks like, and it cannot report that about itself."
|
||||
exit 1
|
||||
fi
|
||||
if [ "$ran" -lt "$MIN_SITE_ASSERTIONS" ]; then
|
||||
echo
|
||||
ci_fail "$f ran only $ran assertions, expected at least $MIN_SITE_ASSERTIONS. Part of the suite did not run."
|
||||
exit 1
|
||||
fi
|
||||
echo " $ran assertions, at or above the floor of $MIN_SITE_ASSERTIONS"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
ci_step "PHP notices and deprecations"
|
||||
|
||||
@@ -307,6 +307,36 @@ elif [ "$fails" = "$before" ]; then
|
||||
echo " $secrets_scanned tracked files read, nothing that looks like a key or a private key"
|
||||
fi
|
||||
|
||||
ci_step "no ci/ script configures the clone it was handed"
|
||||
# `git config user.name` writes .git/config and OUTLIVES the script. A helper
|
||||
# that sets an identity before committing therefore renames every later commit
|
||||
# in that working copy, including a release made by a person days afterwards
|
||||
# and with no Co-Authored-By trailer. git announces an identity it cannot FIND
|
||||
# and says nothing about one that is wrong, so the missing case is loud and
|
||||
# this one is silent: nothing fails, nothing warns, and the author is only
|
||||
# visible to somebody reading `git log` for another reason.
|
||||
#
|
||||
# ci/bump-tested-up-to.sh did this until it was scoped to `git -c … commit`,
|
||||
# which still signs its own commit as the robot — correct, that one is not a
|
||||
# person's — without touching the clone. Measured across the family: six
|
||||
# misattributed hand commits in one sibling, two in another, including
|
||||
# releases. This tree was clean and one run away.
|
||||
#
|
||||
# Any flag, not just --local: --global sets the whole machine's identity, which
|
||||
# is the same fault one scope wider and reaches every repository on the box.
|
||||
#
|
||||
# The rule: a script may configure ITSELF, never the working copy it was
|
||||
# handed. Reported by the Nolimit Security session 2026-09-25.
|
||||
scripts_scanned=$(git ls-files 'ci/*.sh' | wc -l)
|
||||
if [ "$scripts_scanned" -lt 1 ]; then
|
||||
note_fail "The git-identity scan found no ci/*.sh files at all, so it proved nothing."
|
||||
elif git ls-files -z 'ci/*.sh' \
|
||||
| xargs -0 grep -nE '^[^#]*git config([[:space:]]+--[a-z-]+)*[[:space:]]+user\.'; then
|
||||
note_fail "A ci/ script sets a git identity that outlives it. Scope it to the one commit with 'git -c user.name=… commit', which does not write .git/config."
|
||||
else
|
||||
echo " $scripts_scanned scripts in ci/ leave the clone's git identity alone"
|
||||
fi
|
||||
|
||||
ci_step "no placeholders left in the plugin header"
|
||||
# The header is the plugin's business card: wp-admin shows the author and the
|
||||
# links to whoever installs it, so a placeholder there survives for as long as
|
||||
|
||||
+17
-1
@@ -31,6 +31,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
* that it can.
|
||||
*/
|
||||
$GLOBALS['wc_edm_failures'] = 0;
|
||||
$GLOBALS['wc_edm_passes'] = 0;
|
||||
( static function () { ++$GLOBALS['wc_edm_failures']; } )();
|
||||
if ( 1 !== $GLOBALS['wc_edm_failures'] ) {
|
||||
echo "The failure counter does not reach the verdict: this file cannot go red.\n";
|
||||
@@ -47,6 +48,7 @@ $GLOBALS['wc_edm_failures'] = 0;
|
||||
*/
|
||||
function wc_edm_ok( $what, $condition, $detail = '' ) {
|
||||
if ( $condition ) {
|
||||
++$GLOBALS['wc_edm_passes'];
|
||||
printf( " ok %s\n", $what );
|
||||
return;
|
||||
}
|
||||
@@ -799,8 +801,22 @@ if ( $GLOBALS['wc_edm_failures'] > 0 ) {
|
||||
printf( "%d assertion(s) failed on WordPress %s.\n", $GLOBALS['wc_edm_failures'], get_bloginfo( 'version' ) );
|
||||
exit( 1 );
|
||||
}
|
||||
// The number, not just the word. "All assertions passed" is also what a file
|
||||
// that asserted nothing prints — which is the failure this whole suite exists
|
||||
// to catch everywhere else, and it was in the summary line the entire time.
|
||||
// A floor as well, for the same reason every count in ci/ has one: a run that
|
||||
// died early after a handful of assertions would otherwise read as a pass.
|
||||
if ( $GLOBALS['wc_edm_passes'] < 60 ) {
|
||||
printf(
|
||||
"Only %d assertions ran, which is too few to be a complete run.\n",
|
||||
$GLOBALS['wc_edm_passes']
|
||||
);
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
printf(
|
||||
"All assertions passed on WordPress %s with WooCommerce %s.\n",
|
||||
"All %d assertions passed on WordPress %s with WooCommerce %s.\n",
|
||||
$GLOBALS['wc_edm_passes'],
|
||||
get_bloginfo( 'version' ),
|
||||
defined( 'WC_VERSION' ) ? WC_VERSION : '?'
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Plugin URI: https://gitea.nolimit.dk/kw/woo-discount-manager
|
||||
* Update URI: https://gitea.nolimit.dk/kw/nolimit-discounts-dist
|
||||
* Description: Apply discounts and show/hide shipping methods based on the customer's email address (full address, domain or partial match).
|
||||
* Version: 1.6.1
|
||||
* Version: 1.6.2
|
||||
* Author: Kristian Wind
|
||||
* Author URI: https://gitea.nolimit.dk/kw
|
||||
* License: GPL-2.0-or-later
|
||||
@@ -12,7 +12,7 @@
|
||||
* Requires at least: 5.8
|
||||
* Requires PHP: 7.4
|
||||
* WC requires at least: 6.0
|
||||
* WC tested up to: 11.1.0
|
||||
* WC tested up to: 11.1.2
|
||||
* Requires Plugins: woocommerce
|
||||
*/
|
||||
|
||||
@@ -28,7 +28,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
define( 'WC_EDM_VERSION', '1.6.1' );
|
||||
define( 'WC_EDM_VERSION', '1.6.2' );
|
||||
define( 'WC_EDM_PLUGIN_FILE', __FILE__ );
|
||||
define( 'WC_EDM_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
|
||||
define( 'WC_EDM_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
|
||||
|
||||
Reference in New Issue
Block a user