V5 breaking changes - #436
Conversation
BREAKING CHANGE: * mcf_xxx macros: insert_cmplib option removed (CMPLIB is now checked automatically), and wrap= now defaults to YES * mf_getuniquelibref.sas: deprecated maxtries parameter removed * mp_abort.sas: redundant type= parameter removed * mp_coretable.sas: removed, use the standalone mddl_dc_* macros in the ddl folder instead * mp_getddl.sas: renamed to mp_ds2ddl.sas, and SHOWLOG now defaults to YES instead of NO * mp_testservice.sas: renamed to mp_execute.sas
allanbowe
left a comment
There was a problem hiding this comment.
Hermes Agent Code Review
Verdict: Comment - No blocking issues. The PR is well-structured and the breaking changes are clearly documented. A few observations below.
Summary
This PR applies all planned v5 breaking changes: removing deprecated parameters (insert_cmplib=, maxtries=, type=), removing mp_coretable.sas (replaced by mddl_dc_* macros), renaming mp_getddl.sas to mp_ds2ddl.sas, and renaming mp_testservice.sas to mp_execute.sas. 30 files changed across macros, tests, docs, and the generated all.sas.
What's done well
- Clean rename of
mp_getddl->mp_ds2ddl: I diffed the oldmp_getddl.sasbody against the newmp_ds2ddl.sasbody - the implementation is byte-identical apart from the macro name, file name, andshowlogdefault. No logic was lost or silently changed in the move. - Latent bug fixed: The old
mp_ds2ddl.saswrapper hardcodedflavour=SASwhen delegating tomp_getddl, silently ignoring the caller'sflavour=parameter. The merged version correctly passes&flavourthrough. This is a positive side effect of the merge. - No stale references: I searched all of
base/,server/,tests/, andfcmp/- there are zero remaining references tomp_getddl,mp_testservice,mp_coretable, orinsert_cmplib. All callers and docs were updated. mf_getuniquelibrefcleanup is correct:maxtriesis now a%localvariable computed from the prefix length, covering the full range of possible librefs. The deprecated parameter was indeed redundant.mp_aborttype=removal is safe: Confirmedtypewas never referenced anywhere in the macro body - it was a dead parameter.- Test updates are thorough: All affected tests (
mcf_*.test.sas,mp_filterstore.test.1/2.sas,mp_lockanytable.test.sas,mp_lib2inserts.test.sas) were updated to use the new macro names and signatures. - README and AGENTS.md updates are accurate: The breaking changes section was rewritten from future-tense to past-tense, and the
hasMacroNameInMendlint rule is now correctly documented.
Observations (non-blocking)
-
showlog=YESdefault has a ripple effect:mp_lib2inserts.sascalls%mp_ds2ddl(sashelp, schema=work, fref=tempref)without settingshowlog=. With the old wrapper (which defaulted toNO), this was silent. Now it will dump DDL to the log. If that's undesired in themp_lib2insertscontext, setshowlog=NOexplicitly there. (See inline comment onmp_ds2ddl.sas.) -
PGSQLflavour is undocumented: Theflavour=parameter docs list onlySASandTSQL, but the macro body handlesPGSQLtoo. Pre-existing, but v5 is a good time to document it. (See inline comment.) -
Test coverage is thin for the merged macro:
mp_ds2ddl.test.sasonly testsflavour=TSQL. TheSAS(default) andPGSQLcode paths are untested. Pre-existing frommp_getddl.test.sas, but worth improving. Also, the test file is missing a trailing newline. -
No test for
mp_execute: The renamedmp_testservice->mp_executehas no test (requires a live SASjs server). Understandable, just noting.
Security & correctness
- No security concerns: no user input handling, no injection vectors, no secrets.
- No logic errors introduced: all changes are parameter removals, renames, and doc updates.
- The
mddl_dc_*macros in theddl/folder acceptlibds=and are direct drop-in replacements for the oldmp_coretabledispatch - confirmed they exist and have matching signatures.
Reviewed by Hermes Agent
There was a problem hiding this comment.
4gl-reviewer Incremental Code Review
Verdict: Comment — The new commits address several items from our initial review. Acknowledging the fixes below and flagging a few new observations.
✅ Fixes from our initial review (acknowledged)
- PGSQL flavour documented —
@li PGSQLadded to theflavour=parameter docs inmp_ds2ddl.sas. ✅ Fixed. constraints_usedscope leak fixed — Changed from%global(insideaddConst) to%local(declared outsideaddConst, inmp_ds2ddl's scope).call symputinside the nested macro will correctly update the parent-scope variable. No more global symbol table pollution. ✅ Fixed.- SAS flavour test added —
mp_ds2ddl.test.sasnow testsflavour=SAS(the default) in addition toflavour=TSQL, withmp_assertscopeguards on both. ✅ Fixed. - Missing newline at end of file —
mp_ds2ddl.test.sasnow ends with a newline. ✅ Fixed. mp_executetest added — Newtests/x-platform/mp_execute.test.sascreates a real web service viamx_createwebserviceand executes it throughmp_execute, verifying the dataset round-trips correctly. Good use ofmp_assertscopewith an ignorelist for JSON libname engine vars. ✅ Fixed.mp_validatecolFORMAT regex improved — Now accepts numeric format names (4.,8.2,12.) via the[0-9]+alternation. I validated the regex against all 18 test cases (8 good, 10 bad) — all pass correctly. (This change was merged to main via PR #435 and is not part of this PR's diff, but the test cases inmp_validatecol.test.saswere updated in this PR.) ✅ Fixed.
⚠️ New observations (non-blocking)
-
Dead code in
mp_searchdata.test.sas— The assertion was changed fromiftrue=("&warntxt" = "")toiftrue=("%superq(syswarningtext)"="%superq(initwarningtext)"), which is more robust. However, thewarntxtblock (the%let warntxt=...anddata _null_step that conditionally clears it) is now dead code — the new assertion never references&warntxt. Consider removing the warntxt block for clarity. (See inline comment.) -
PGSQL flavour still untested — While PGSQL is now documented in the param docs (fixing our previous comment), there is still no test for the
flavour=PGSQLcode path inmp_ds2ddl.test.sas. The PGSQL branch has significant unique logic (schema detection viadictionary.libnames, 1600-column Postgres limit, PostgreSQL-specific DDL syntax). A basic smoke test would be valuable. (See inline comment.) -
CI workflow:
skills updatewithout error handling — The new CI step runsnpx --yes skills update --project --yeswithout any error guard. If theskillsnpm package is unavailable or thesasjs/skillsrepo is temporarily inaccessible, the workflow step will fail and block the branch push forall.sasupdates (since it's in the same job). (See inline comment.) -
showlog=YESdefault ripple onmp_lib2inserts— This was flagged in our initial review.mp_lib2inserts.sas:8still calls%mp_ds2ddl(sashelp, schema=work, fref=tempref)without settingshowlog=NO. The verbose DDL output in the log from this internal call may be undesired. Still not addressed — noting again as non-blocking.
✅ What's done well in the new commits
mp_validatecolregex fix is correct — The non-capturing group(?:[_a-z\$]\w{0,31}|[0-9]+)cleanly handles both named and numeric format names. Test cases are comprehensive (8 valid, 10 invalid patterns).mp_executetest is well-structured — Creates a real service, sends data through it, and verifies the round-trip. Themp_assertscopewithignorelistfor JSON libname engine vars is a thoughtful touch.mp_assertscopeadditions tomp_ds2ddltest — Good practice to verify no macro variable scope leaks after the%global→%localfix.- Lint passes clean —
npx @sasjs/cli lintreports all files conform to@sasjs/lintcode style. - Test coverage at 47% (120/253 macros covered) —
mp_execute,mp_ds2ddl,mp_validatecol, andmp_searchdataare all covered. .npmignoreadditions — Addingskills-lock.jsonand.env*to.npmignoreis correct (lockfile shouldn't be published;.env*prevents accidental secret leakage).- Agent skills are well-documented — README addition clearly explains what the skills are and how to install them. The
skills-lock.jsonwith computed hashes ensures reproducibility.
Incremental review by 4gl-reviewer[bot] — comparing 262a199 → 5ea28e3
There was a problem hiding this comment.
Hermes Agent Code Review — Follow-up
Verdict: Approve — all issues from the incremental review are resolved.
Fixes confirmed
- ✅ CI
continue-on-error—notmain.ymlskills update step now hascontinue-on-error: truewith explanatory comment. A transient npm/github outage will no longer fail the workflow. - ✅ PGSQL flavour test —
mp_ds2ddl.test.sasnow includes a PGSQL test block withmp_assertscopeguards, covering the previously untested code path. - ✅ Dead code removed —
mp_searchdata.test.saswarntxtblock (7 lines) removed. The assertion now cleanly compares againstinitwarningtext.
No remaining issues. LGTM.
Reviewed by Hermes Agent (GitHub App)
Test Coverage Report
Overall: 120/253 macros covered (47%) PR-changed macros
16 of 17 PR-changed macros have test coverage. The only gap ( The new tests added in this PR (PGSQL flavour, SAS flavour, Generated by Hermes Agent (GitHub App) |
|
🎉 This PR is included in version 5.0.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |

feat!: apply planned v5 breaking changes
Summary
This PR implements all the breaking changes listed in the README "Breaking Changes" section, which were planned for the next major release (v5). All of these changes were previously marked with the
@deprecateddoxygen tag or documented as upcoming.Breaking Changes
1.
mcf_xxxmacros —insert_cmplib=removed,wrap=defaults to YESThe
insert_cmplib=option has been removed from:fcmp/mcf_getfmttype.sasfcmp/mcf_length.sasfcmp/mcf_string2file.sasThe CMPLIB option is now checked automatically, with the value inserted only if needed, so the parameter was redundant. Additionally, the
wrap=option now defaults toYES(previouslyNO) — set it explicitly toNOif you rely on the old behaviour.Callers and tests updated accordingly (
mp_ds2csv.sas,mp_getmaxvarlengths.sas,mcf_getfmttype.test.sas,mcf_length.test.sas,mcf_string2file.test.sas).Migration: remove
insert_cmplib=from your%mcf_*()calls, and explicitly setwrap=NOif you do not want theproc fcmpwrapper.2.
mf_getuniquelibref.sas—maxtries=removedThe deprecated
maxtries=parameter has been removed (it was ignored — the value is computed automatically from the prefix length).Migration: remove
maxtries=from your%mf_getuniquelibref()calls.3.
mp_abort.sas—type=removedThe redundant
type=parameter has been removed. It was not referenced anywhere in the macro logic or by any caller in this library.Migration: remove
type=from your%mp_abort()calls.4.
mp_coretable.sas— removedReplaced by the standalone macros in the
ddlfolder:%mp_coretable(DIFFTABLE, libds=...)%mddl_dc_difftable(libds=...)%mp_coretable(FILTER_DETAIL, libds=...)%mddl_dc_filterdetail(libds=...)%mp_coretable(FILTER_SUMMARY, libds=...)%mddl_dc_filtersummary(libds=...)%mp_coretable(LOCKTABLE, libds=...)%mddl_dc_locktable(libds=...)%mp_coretable(MAXKEYTABLE, libds=...)%mddl_dc_maxkeytable(libds=...)Documentation references in
mp_stackdiffs.sas,mp_storediffs.sas,mp_retainedkey.sasandmp_filterstore.saswere updated, and the dependent tests (mp_filterstore.test.1/2.sas,mp_lockanytable.test.sas) now call themddl_dc_*macros directly.mp_coretable.test.saswas removed.5.
mp_getddl.sas— renamed tomp_ds2ddl.sasRenamed for consistency with the other
ds2xxxmacros. The previousmp_ds2ddl.saswrapper was removed and the full implementation now lives inmp_ds2ddl.sas. Theshowlog=default is nowYES(previouslyNO).References updated in
mp_lib2inserts.sas,mp_dsmeta.sas, and the tests (mp_getddl.test.sas→mp_ds2ddl.test.sas,mp_lib2inserts.test.sas).Migration: replace
%mp_getddl(libref, ds, ...)with%mp_ds2ddl(libref, ds, ...), and setshowlog=NOexplicitly if you relied on the old default.6.
mp_testservice.sas— renamed tomp_execute.sasThe macro doesn't actually test anything — it executes a SASjs web service on SAS 9 or Viya (wrapping
mx_testservice.sas). The signature is unchanged.Migration: replace
%mp_testservice(...)with%mp_execute(...).Other changes
AGENTS.mdupdated to document the existinghasMacroNameInMendlint rule (the closing%mendmust contain the macro name). The README previously stated the opposite.Verification
sasjs lintpasses on all files.all.sas,mc_*.sas) intentionally untouched — rebuilt by CI/CD.sasjs test) — to be run via CI.Versioning
The commit uses the
feat!:convention with aBREAKING CHANGE:footer, so semantic-release will cut v5.0.0 on merge.