Skip to content

Mx createfile - #438

Merged
allanbowe merged 11 commits into
mainfrom
mx_createfile
Aug 17, 2026
Merged

Mx createfile#438
allanbowe merged 11 commits into
mainfrom
mx_createfile

Conversation

@allanbowe

Copy link
Copy Markdown
Member

rename mp_execute to mx_execute (should have been part of the v5 release)

also added a new macro (mx_createfile) and associated test

@4gl-reviewer

4gl-reviewer Bot commented Aug 17, 2026

Copy link
Copy Markdown

Test Coverage Report

Overall coverage: 120/253 macros (47%)

Generated by npx @sasjs/cli c (target: server, SASJS server type).

PR-Changed Macros Coverage

Macro File Status
mx_createfile xplatform/mx_createfile.sas ✅ Covered (has tests/x-platform/mx_createfile.test.sas)
mx_execute xplatform/mx_execute.sas ✅ Covered (has tests/x-platform/mx_execute.test.sas)
mp_ds2csv base/mp_ds2csv.sas ✅ Covered (has tests/base/mp_ds2csv.test.1.sas, .2.sas)
ms_testservice server/ms_testservice.sas ✅ Covered (has tests/serveronly/ms_testservice.test.sas)

Notes

  • All four PR-changed macros have corresponding test files and are included in the compile/coverage analysis.
  • The coverage table lists only uncovered macros; none of the PR-changed macros appear in that list.
  • mx_createfile.test.sas tests all three platform branches (SASJS, SAS9/SASMETA, SASVIYA) with platform-specific verification logic.
  • Coverage is compile-time only (dependency resolution from doxygen headers); runtime test execution requires a live SAS server.

Generated by Hermes Agent (GitHub App)

call symputx('shortloc',shortloc,'l');
run;
data _null_;
infile &inref lrecl=32767;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion — no input validation for inref=0

The SAS 9 branch does infile &inref lrecl=32767; but the default is inref=0. If the macro is called without specifying inref=, this will resolve to infile 0 which produces a confusing SAS error rather than a clear validation message. The other branches (SASJS, SASVIYA) delegate to ms_createfile/mv_createfile which may handle this, but the SAS 9 branch has open data _null_ steps that will fail opaquely.

Consider adding an early guard at the top of the macro:

%if &inref=0 %then %do;
  %put %str(ERR)OR: &sysmacroname requires a valid inref fileref;
  %return;
%end;

This is also consistent with how mx_execute validates its inputs via %mp_abort.

data _null_;
filepath=symget('filepath');
name=scan(filepath,-1,'/');
shortloc=substr(filepath,1,length(filepath)-length(name)-1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning — edge case: filepath with no / separator

name=scan(filepath,-1,'/') and shortloc=substr(filepath,1,length(filepath)-length(name)-1) assume filepath contains at least one /. If a caller passes a bare filename (e.g. settings.sas with no path), shortloc becomes empty or negative-length, which can cause unexpected behaviour in the downstream mv_createfile(path=...) / mm_createstp(tree=...) calls.

The same pattern exists in the SAS 9 branch (line 87) and in the existing mx_getcode.sas macro, so this is a pre-existing convention — but worth noting since mx_createfile is new code. Consider documenting that filepath must be a full path, or adding a guard.

Comment thread xplatform/mx_createfile.sas Outdated
run;
data _null_;
infile &inref lrecl=32767;
file "%sysfunc(getoption(work))/%superq(name).sas" lrecl=32767;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion — temp file not cleaned up

file "%sysfunc(getoption(work))/%superq(name).sas" lrecl=32767;

This writes a physical .sas file to the WORK directory as a temporary step for mm_createstp. The file is never deleted after mm_createstp loads it. Since WORK is cleaned up at session end this is not a leak in practice, but for long-running sessions or mdebug=1 workflows, consider cleaning up:

filename _tmp "%sysfunc(getoption(work))/%superq(name).sas";
%* ... after mm_createstp ...
%if &mdebug=0 %then %do;
  data _null_;
    rc=fdelete('_tmp');
  run;
  filename _tmp clear;
%end;

Comment thread xplatform/mx_createfile.sas Outdated
,mdebug=&mdebug
)
%end;
%else %put &sysmacroname: &platform is unsupported!!!;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion — unsupported platform only logs, doesn't set &syscc

%else %put &sysmacroname: &platform is unsupported!!!;

This silently continues after printing a message. For comparison, mx_execute uses %put %str(ERR)OR: Unrecognised platform: &platform; (note the ERRORtrick to avoid the SAS ERROR keyword). Consider elevating to an actual error condition by setting&sysccor calling%mp_abortso downstream code doesn't proceed with a false sense of success. This pattern also exists inmx_getcode` so it's a pre-existing convention, but new code could improve on it.

%inc testref2;
%end;
%mend check_content;
%check_content()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion — check_content macro doesn't handle SASVIYA platform

The check_content macro handles SASJS and SAS9/SASMETA but has no %else %if &platform=SASVIYA branch. For Viya, mx_createfile creates a SAS Content file via mv_createfile, but the test doesn't read it back to verify the content. The assert_result macro does check file existence via %mfv_existfile for Viya, but not content correctness.

This means on Viya, the test only verifies the file exists, not that its content is correct (%let test1=SUCCESS;). Consider adding a Viya branch to check_content that fetches and executes the file content, or document that Viya content verification is deferred.

%mp_assertscope(COMPARE,
desc=Test 1: mx_createfile does not leak scope,
ignorelist=MC0_JADP1LEN MC0_JADP2LEN MC0_JADP3LEN MC0_JADPNUM
MC0_JADVLEN MC2_JADP1LEN MC2_JADP2LEN MC2_JADPNUM MC2_JADVLEN

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks Good — scope leakage test with ignorelist

Good use of %mp_assertscope(SNAPSHOT) / %mp_assertscope(COMPARE, ...) to catch macro-variable scope leakage, consistent with the testing conventions. The ignorelist for JSON libname engine variables (MC0_JADP*, MC2_JADP*, VIYAPROPERTIES, VIYATYPEDEFNAME) shows attention to platform-specific noise.

@4gl-reviewer 4gl-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hermes Agent Code Review

Verdict: Comment — No blocking issues; the PR is well-structured and safe to merge after considering the suggestions below.


Critical

None. The rename is complete with no dangling references to mp_execute or mx_testservice anywhere in the codebase. All dependent macros (mf_getplatform, mm_createstp, ms_createfile, mv_createfile, mf_uid, mfv_existfile) exist and are correctly declared in the doxygen headers.

Warnings

  • inref=0 default in SAS 9 branch (xplatform/mx_createfile.sas:92): The data _null_; infile &inref ... step will fail with a confusing SAS error if inref is left at its default 0. The SASJS and SASVIYA branches delegate to macros that may handle this more gracefully, but the SAS 9 branch has open data step code. An early validation guard (%if &inref=0 %then ...) would make the macro more robust. See inline comment.

  • filepath with no / separator (xplatform/mx_createfile.sas:69): The scan/substr path-splitting logic assumes at least one / in filepath. A bare filename would produce an empty/negative shortloc. This is a pre-existing convention (same pattern in mx_getcode.sas) but worth documenting for new code. See inline comment.

Suggestions

  • Temp file cleanup in SAS 9 branch (xplatform/mx_createfile.sas:93): The physical .sas file written to WORK for mm_createstp is never explicitly deleted. Not a real leak (WORK is session-scoped) but cleaner to remove, especially in mdebug=0 mode.

  • Unsupported platform handling (xplatform/mx_createfile.sas:105): The %else %put ... is unsupported!!! branch only logs and does not set &syscc or abort. mx_execute uses the %str(ERR)OR: pattern for the same case. Consider elevating to an error condition so callers are aware. Pre-existing convention in mx_getcode.

  • Viya content verification in test (tests/x-platform/mx_createfile.test.sas:57): The check_content macro handles SASJS and SAS9/SASMETA but not SASVIYA. On Viya, only file existence is verified (via mfv_existfile), not content correctness. Adding a Viya branch to read back and verify content would make the test fully cross-platform.

  • all.sas missing trailing newline: The generated all.sas file no longer ends with a newline character (confirmed via od -c). The previous version on main did. Since this is a generated file, the CI build should fix this, but it's worth noting.

Looks Good

  • Clean rename: mp_executemx_execute is thorough — all references in .sas files, test files, all.sas, README.md, and ms_testservice.sas are updated. No lingering references to the old names.
  • Architectural correctness: Moving mp_execute to mx_execute correctly follows the mp_ macros must never reference mx_ macros convention documented in the updated skill files. The old mp_execute was a thin wrapper calling mx_testservice, which was an architectural violation.
  • New mx_createfile macro: Well-documented with doxygen header, proper platform dispatching via mf_getplatform(), correct use of %superq() for quoting, and sensible delegation to platform-specific macros (ms_createfile, mv_createfile, mm_createstp).
  • Test quality: mx_createfile.test.sas correctly uses %mp_assertscope for scope leakage detection, wraps platform-branching code in %macro wrappers (as per the testing conventions), and uses %mf_uid() for unique test artefact naming.
  • Lint passes: npx @sasjs/cli lint passes with no warnings.
  • Compile passes: npx @sasjs/cli c succeeds with all PR-changed macros covered by test files.

Reviewed by Hermes Agent (GitHub App)

@4gl-reviewer 4gl-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hermes Agent Code Review

Verdict: Comment — The follow-up commit (ee43f9d fix: pr review feedback) cleanly addresses every item from the prior review. The macro and tests are in good shape; one minor suggestion remains below.


Critical

None.

Warnings

None.

Suggestions

  • fref allocated unconditionally but only used on SAS 9 (xplatform/mx_createfile.sas:62): %let fref=%mf_getuniquefileref(); runs at macro entry on every platform, but &fref is only bound to a filename (filename &fref "...") and cleaned up inside the SAS 9 / SASMETA branch. On the SASJS and SASVIYA paths the generated fileref is allocated (via filename(fname,,temp,...) inside mf_getuniquefileref) and then never used or cleared. Not a real leak (temp filerefs auto-clear at session end), but it's an unnecessary allocation on 2 of 3 platforms. Consider moving the %let fref=%mf_getuniquefileref(); (and the %local fref;) into the SAS 9 branch so it is only created when needed. See inline comment.

Looks Good

  • Prior feedback fully addressed: The fix: pr review feedback commit adds the inref=0 validation guard, documents that filepath must contain a / delimiter, cleans up the SAS 9 temp file via fdelete + filename ... clear (now using mf_getuniquefileref per the new AGENTS.md convention), elevates the unsupported-platform branch to %str(ERR)OR: + syscc=1012, and adds a SASVIYA content-verification branch to the test. All six prior review points are resolved.
  • New AGENTS.md convention: Documenting "Always use mf_getuniquefileref when assigning filerefs" is a good guardrail and the macro now follows it.
  • Clean rename: mp_executemx_execute (rename of mx_testservice) is complete with no dangling references; the mp_mx_ boundary convention is respected.
  • Lint passes: npx @sasjs/cli lint passes with no warnings.
  • Compile + coverage: npx @sasjs/cli c -t server succeeds; all PR-changed macros (mx_createfile, mx_execute, mp_ds2csv, ms_testservice) are covered by test files. See the separate Test Coverage Report comment.

Reviewed by Hermes Agent (GitHub App)

Comment thread xplatform/mx_createfile.sas Outdated
@4gl-reviewer

4gl-reviewer Bot commented Aug 17, 2026

Copy link
Copy Markdown

Test Coverage Report

Ran npx @sasjs/cli c -t server (compile/coverage) locally against PR branch mx_createfile @ 1012a02e.

Overall coverage: 120/253 macros (47%)

PR-changed macros

Macro File Test Coverage
mx_createfile xplatform/mx_createfile.sas ✅ Covered (tests/x-platform/mx_createfile.test.sas)
mx_execute xplatform/mx_execute.sas ✅ Covered (tests/x-platform/mx_execute.test.sas)
mp_ds2csv base/mp_ds2csv.sas ✅ Covered
ms_testservice server/ms_testservice.sas ✅ Covered
mp_execute base/mp_execute.sas ➖ Removed (renamed to mx_execute)

All PR-changed macros that remain in the repo have corresponding test files and are covered.

Compile / lint status

  • npx @sasjs/cli c -t server — ✔ success (output in sasjsbuild/)
  • npx @sasjs/cli lint — ✔ all files pass @sasjs/lint code style
  • CI checks on 1012a02e — ✔ test (lts/iron) success, ✔ Analyze (python) success

Generated by Hermes Agent (GitHub App)

@allanbowe
allanbowe merged commit dd4c94d into main Aug 17, 2026
2 checks passed
@allanbowe
allanbowe deleted the mx_createfile branch August 17, 2026 12:26
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 5.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@4gl-reviewer 4gl-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hermes Agent Code Review

Verdict: Comment — PR already merged; this reviews the commits pushed after the previous review (9aabeb9, 7e0bba9, b8811db). No blocking issues found.

What changed in the new commits

  • 9aabeb9 fix: pr feedback: Moved %local fref / %let fref=%mf_getuniquefileref() out of the common preamble and into the SAS9 branch only. This avoids allocating an unused fileref on SASJS/Viya. The relocation is correct — %local is resolved at macro compile time, so the late declaration still scopes fref locally to mx_createfile.
  • 7e0bba9, b8811db: auto-regenerated all.sas and agent skill docs. Verified all.sas contains mx_createfile/mx_execute with no stale mp_execute/mx_testservice references anywhere in the tree.

Critical

(none)

Warnings

(none)

Suggestions

  • Root-level file edge case in the path-parsing substr (see inline on line 77).
  • The path-parsing DATA step is duplicated verbatim between the SASVIYA and SAS9 branches (see inline on line 95).
  • The inref=0 early-return guard (xplatform/mx_createfile.sas:64-67) is not exercised by a negative test — mx_createfile.test.sas always passes a valid fileref. Consider adding a test that asserts the ERROR/early-return when inref is omitted.
  • No validation that filepath actually contains a / delimiter. A malformed path silently yields empty shortloc/name, which then get passed downstream to mv_createfile/mm_createstp.

Looks Good

  • Rename is complete and consistent across base/mp_ds2csv.sas, server/ms_testservice.sas, test files, and all.sas.
  • &sysmacroname is used throughout mx_execute.sas, so internal logging adapts to the new name automatically.
  • All PR-changed macros (mx_createfile, mx_execute, mx_getcode) have associated test files and are reported as covered by npx @sasjs/cli c (see the separate coverage report comment).

Reviewed by Hermes Agent (GitHub App)

data _null_;
filepath=symget('filepath');
name=scan(filepath,-1,'/');
shortloc=substr(filepath,1,length(filepath)-length(name)-1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edge case — root-level file. For a path like /settings (which satisfies the documented "must contain at least one /" contract), length(filepath)-length(name)-1 evaluates to 0, so shortloc becomes an empty string rather than /.

shortloc=substr(filepath,1,length(filepath)-length(name)-1);

On SASVIYA this would then pass path= (empty) to mv_createfile. Consider either tightening the contract to require a parent directory, or special-casing the root, e.g.:

if shortloc='' then shortloc='/';

data _null_;
filepath=symget('filepath');
name=scan(filepath,-1,'/');
shortloc=substr(filepath,1,length(filepath)-length(name)-1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated path-parsing. This DATA step (extracting name and shortloc from filepath) is identical to the one in the SASVIYA branch above (lines 74-80). Consider computing name/shortloc once before the platform if/else so the logic isn't duplicated. (If you'd rather not run it for the SASJS branch where it's unused, a small helper macro would also remove the duplication.)

@4gl-reviewer

4gl-reviewer Bot commented Aug 17, 2026

Copy link
Copy Markdown

Test Coverage Report

Ran npx @sasjs/cli c against the PR branch (b8811db, target server).

Overall coverage: 120/253 macros (47%)

PR-changed macros:

Macro Source File Test File Status
mx_createfile xplatform/mx_createfile.sas tests/x-platform/mx_createfile.test.sas ✅ Covered
mx_execute xplatform/mx_execute.sas (renamed from mx_testservice) tests/x-platform/mx_execute.test.sas ✅ Covered
mx_getcode xplatform/mx_getcode.sas (doc-only change) tests/x-platform/mx_getcode.test.sas ✅ Covered
mp_execute base/mp_execute.sas (removed) tests/x-platform/mp_execute.test.sas (removed) N/A — deleted
mp_ds2csv base/mp_ds2csv.sas (doc-only change) tests/base/mp_ds2csv.test.sas ✅ Covered

Note: npx @sasjs/cli c verifies test-file wiring and compilation against the server (SASjs) target. The platform-dependent branches inside mx_createfile (SASJS / SASVIYA / SAS9) can only be executed on their respective runtimes, so per-branch runtime coverage is not reflected here. The inref=0 early-return guard in mx_createfile is not exercised by any test.

Generated by Hermes Agent (GitHub App)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant