1
0
mirror of https://github.com/sasjs/core.git synced 2025-12-11 14:34:35 +00:00

Compare commits

...

35 Commits

Author SHA1 Message Date
Allan Bowe
c58b5c7a52 Merge pull request #332 from sasjs/patches
fix: invalid macro variable in mp_lockanytable.sas
2023-04-07 11:30:04 +01:00
Allan Bowe
22c7e5b4dd Merge branch 'main' into patches 2023-04-07 11:29:30 +01:00
allan
244171f8c4 fix: failing test due to missing sashelp table, also added scope check 2023-04-06 13:41:02 +01:00
Allan Bowe
fd765e2d68 Merge pull request #333 from sasjs/vpn
github action vpn
2023-04-06 12:07:56 +01:00
840cb5ef44 chore: ci - sas9.4gl.io 2023-04-06 11:16:25 +02:00
918ce96fce chore: ci - jammy ubuntu 2023-04-05 23:07:35 +02:00
f1712c34e8 chore: ci - jammy ubuntu 2023-04-05 22:58:48 +02:00
11ec20b472 chore: ci - jammy ubuntu 2023-04-05 22:54:50 +02:00
f42f111462 chore: ci - jammy ubuntu 2023-04-05 22:49:45 +02:00
907725c5ba chore: ci - jammy ubuntu 2023-04-05 22:48:09 +02:00
95b78b91e1 chore: ci release 2023-04-05 22:46:17 +02:00
e4771b9c14 ci: trigger 2023-04-05 22:24:18 +02:00
ba8190883e chore: ci added vpn for sas9 2023-04-05 22:13:13 +02:00
allan
32dd057e83 fix: avoid open file handle when the variable to find is not provided (in mf_existvar)
Includes a test that was failing and is now passing
2023-04-05 15:29:53 +01:00
allan
7471bd42a4 fix: invalid macro variable in mp_lockanytable.sas 2023-04-05 14:55:00 +01:00
munja
702a4ecd3a chore(lint): adding lineendings rule (LF) 2023-03-31 13:58:30 +01:00
Allan Bowe
5da97295ff Merge pull request #330 from sasjs/issue329
fix: closes #329 by handling the case of unlocking a table that was n…
2023-02-16 14:35:29 +00:00
munja
dc556bdef0 fix: closes #329 by handling the case of unlocking a table that was never locked in mp_lockanytable.sas, also created a corresponding test plus an extra test to check for scope leakage. all.sas was regenerated. 2023-02-16 14:33:53 +00:00
Allan Bowe
111731bf35 Merge pull request #328 from sasjs/all-contributors/add-henrik-forsell
docs: add henrik-forsell as a contributor for doc
2023-02-15 09:32:09 +00:00
allcontributors[bot]
2c526cf9dd docs: update .all-contributorsrc [skip ci] 2023-02-15 09:31:52 +00:00
allcontributors[bot]
660e02193f docs: update README.md [skip ci] 2023-02-15 09:31:51 +00:00
Allan Bowe
00b4dee86e Merge pull request #327 from henrik-forsell/doc-fix
Changed documentation wording (Column to Dataset)
2023-02-15 09:28:50 +00:00
Henrik Forsell
3913825c22 Changed documentation wording (Column to Dataset) 2023-02-15 15:57:11 +13:00
Allan Bowe
0f143d603b Merge pull request #326 from sasjs/325-error-the-keyword-parameter-maxobs-was-not-defined-with-the-macro
fix: closes #325 by including maxobs param
2023-02-13 14:05:36 +00:00
munja
f1d5fa2c0a fix: closes #325 by including maxobs param 2023-02-13 14:01:43 +00:00
Allan Bowe
a88689428f fix: updating cycjimmy/semantic-release-action to v3 2023-01-25 12:56:38 +00:00
munja
8843fa8bfc fix: adding nrstr() wrapper in mm_adduser2group 2023-01-25 12:53:10 +00:00
Allan Bowe
22d046cf5c Merge pull request #324 from sasjs/servertestfixes
fix: updating ms_runstp and ms_testservice macros to cater for latest…
2023-01-06 13:15:11 +01:00
munja
29e3eb34aa fix: updating ms_runstp and ms_testservice macros to cater for latest response JSON formats in sasjs/server 2023-01-06 12:13:36 +00:00
munja
1af52a6683 fix: adding des= macro option to mf_abort 2023-01-02 11:26:21 +00:00
munja
fc0c96dd94 chore: merge 2022-12-30 12:41:08 +00:00
munja
b9c4882553 fix: linting issues 2022-12-30 12:38:34 +00:00
Allan Bowe
011b2b185c chore: removing broken badges in README 2022-12-28 20:25:05 +00:00
Allan Bowe
dbc23550ac Merge pull request #323 from sasjs/ms_getgroups
fix: increasing desc length to 256 in ms_getgroups
2022-12-28 21:21:35 +01:00
munja
8910840ccc fix: increasing desc length to 256 in ms_getgroups 2022-12-28 20:17:08 +00:00
29 changed files with 1083 additions and 567 deletions

View File

@@ -135,6 +135,15 @@
"contributions": [
"code"
]
},
{
"login": "henrik-forsell",
"name": "Henrik Forsell",
"avatar_url": "https://avatars.githubusercontent.com/u/109935936?v=4",
"profile": "https://github.com/henrik-forsell",
"contributions": [
"doc"
]
}
],
"contributorsPerLine": 7,

25
.github/vpn/config.ovpn vendored Normal file
View File

@@ -0,0 +1,25 @@
# Client
client
tls-client
dev tun
# this will connect with whatever proto DNS tells us (https://community.openvpn.net/openvpn/ticket/934)
proto tcp
remote vpn.4gl.io 7494
resolv-retry infinite
cipher AES-256-CBC
auth SHA256
script-security 2
keepalive 10 120
remote-cert-tls server
# Keys
ca ca.crt
cert user.crt
key user.key
tls-auth tls.key 1
# Security
nobind
persist-key
persist-tun
verb 3

View File

@@ -15,7 +15,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- name: Semantic Release
uses: cycjimmy/semantic-release-action@v2
uses: cycjimmy/semantic-release-action@v3
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@@ -21,6 +21,29 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
- name: Write VPN Files
run: |
echo "$CA_CRT" > .github/vpn/ca.crt
echo "$USER_CRT" > .github/vpn/user.crt
echo "$USER_KEY" > .github/vpn/user.key
echo "$TLS_KEY" > .github/vpn/tls.key
shell: bash
env:
CA_CRT: ${{ secrets.CA_CRT}}
USER_CRT: ${{ secrets.USER_CRT }}
USER_KEY: ${{ secrets.USER_KEY }}
TLS_KEY: ${{ secrets.TLS_KEY }}
- name: Install Open VPN
run: |
sudo apt install apt-transport-https
sudo wget https://swupdate.openvpn.net/repos/openvpn-repo-pkg-key.pub
sudo apt-key add openvpn-repo-pkg-key.pub
sudo wget -O /etc/apt/sources.list.d/openvpn3.list https://swupdate.openvpn.net/community/openvpn3/repos/openvpn3-jammy.list
sudo apt update
sudo apt install openvpn3=17~betaUb22042+jammy
- name: Start Open VPN 3
run: openvpn3 session-start --config .github/vpn/config.ovpn
- name: Install Doxygen
run: sudo apt-get install doxygen
@@ -31,16 +54,10 @@ jobs:
run: npm run lint
- name: Add client
run: echo "CLIENT=${{secrets.CLIENT}}"> .env.viya
- name: Add secret
run: echo "SECRET=${{secrets.SECRET}}" >> .env.viya
run: echo "CLIENT=${{secrets.SAS9_4GL_IO_CLIENT}}"> .env.server
- name: Add access token
run: echo "ACCESS_TOKEN=${{secrets.ACCESS_TOKEN}}" >> .env.viya
- name: Add refresh token
run: echo "REFRESH_TOKEN=${{secrets.REFRESH_TOKEN}}" >> .env.viya
run: echo "ACCESS_TOKEN=${{secrets.SAS9_4GL_IO_ACCESS_TOKEN}}" >> .env.server
- name: Build Project
run: npm run build
@@ -54,4 +71,4 @@ jobs:
SAS_USERNAME: ${{secrets.SAS_USERNAME}}
SAS_PASSWORD: ${{secrets.SAS_PASSWORD}}
ACCESS_TOKEN: ${{secrets.ACCESS_TOKEN}}
REFRESH_TOKEN: ${{secrets.REFRESH_TOKEN}}
REFRESH_TOKEN: ${{secrets.REFRESH_TOKEN}}

View File

@@ -4,6 +4,8 @@
"hasDoxygenHeader": true,
"hasMacroNameInMend": true,
"hasMacroParentheses": true,
"lineEndings": "lf",
"noGremlins": true,
"noNestedMacros": false,
"noSpacesInFileNames": true,
"maxLineLength": 300,

View File

@@ -2,8 +2,6 @@
[![npm package][npm-image]][npm-url]
[![Github Workflow][githubworkflow-image]][githubworkflow-url]
![npm](https://img.shields.io/npm/dt/@sasjs/core)
![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/@sasjs/core)
[![License](https://img.shields.io/apm/l/atomic-design-ui.svg)](/LICENSE)
![GitHub top language](https://img.shields.io/github/languages/top/sasjs/core)
[![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/sasjs/core)](https://github.com/sasjs/core/issues?q=is%3Aissue+is%3Aclosed)
[![GitHub issues](https://img.shields.io/github/issues-raw/sasjs/core)](https://github.com/sasjs/core/issues)
@@ -248,7 +246,7 @@ The following repositories are also worth checking out:
## Contributors ✨
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-12-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-13-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
@@ -256,22 +254,25 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="https://github.com/allanbowe"><img src="https://avatars.githubusercontent.com/u/4420615?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Allan Bowe</b></sub></a><br /><a href="#business-allanbowe" title="Business development">💼</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Code">💻</a> <a href="#content-allanbowe" title="Content">🖋</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Documentation">📖</a> <a href="#infra-allanbowe" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-allanbowe" title="Maintenance">🚧</a> <a href="#mentoring-allanbowe" title="Mentoring">🧑‍🏫</a> <a href="#question-allanbowe" title="Answering Questions">💬</a> <a href="https://github.com/sasjs/core/pulls?q=is%3Apr+reviewed-by%3Aallanbowe" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/rafgag"><img src="https://avatars.githubusercontent.com/u/69139928?v=4?s=100" width="100px;" alt=""/><br /><sub><b>rafgag</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=rafgag" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/tmoody"><img src="https://avatars.githubusercontent.com/u/79837106?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Trevor Moody</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=tmoody" title="Code">💻</a></td>
<td align="center"><a href="https://krishna-acondy.io/"><img src="https://avatars.githubusercontent.com/u/2980428?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Krishna Acondy</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=krishna-acondy" title="Code">💻</a> <a href="#infra-krishna-acondy" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#blog-krishna-acondy" title="Blogposts">📝</a> <a href="#content-krishna-acondy" title="Content">🖋</a> <a href="#ideas-krishna-acondy" title="Ideas, Planning, & Feedback">🤔</a> <a href="#video-krishna-acondy" title="Videos">📹</a></td>
<td align="center"><a href="https://github.com/saadjutt01"><img src="https://avatars.githubusercontent.com/u/8914650?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Muhammad Saad </b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=saadjutt01" title="Code">💻</a> <a href="#ideas-saadjutt01" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://www.erudicat.com/"><img src="https://avatars.githubusercontent.com/u/25773492?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yury Shkoda</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=YuryShkoda" title="Code">💻</a> <a href="#infra-YuryShkoda" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#video-YuryShkoda" title="Videos">📹</a></td>
<td align="center"><a href="https://github.com/medjedovicm"><img src="https://avatars.githubusercontent.com/u/18329105?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mihajlo Medjedovic</b></sub></a><br /><a href="#infra-medjedovicm" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/kkchandok"><img src="https://avatars.githubusercontent.com/u/46090627?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kkchandok</b></sub></a><br /><a href="#ideas-kkchandok" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/VladislavParhomchik"><img src="https://avatars.githubusercontent.com/u/83717836?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vladislav Parhomchik</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=VladislavParhomchik" title="Tests">⚠️</a> <a href="https://github.com/sasjs/core/pulls?q=is%3Apr+reviewed-by%3AVladislavParhomchik" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://github.com/vznesh"><img src="https://avatars.githubusercontent.com/u/28916792?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vignesh T.</b></sub></a><br /><a href="https://github.com/sasjs/core/issues?q=author%3Avznesh" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/yabwon"><img src="https://avatars.githubusercontent.com/u/9314894?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bart Jablonski</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=yabwon" title="Code">💻</a></td>
<td align="center"><a href="https://bandism.net/"><img src="https://avatars.githubusercontent.com/u/22633385?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ikko Ashimine</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=eltociear" title="Code">💻</a></td>
</tr>
<tbody>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/allanbowe"><img src="https://avatars.githubusercontent.com/u/4420615?v=4?s=100" width="100px;" alt="Allan Bowe"/><br /><sub><b>Allan Bowe</b></sub></a><br /><a href="#business-allanbowe" title="Business development">💼</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Code">💻</a> <a href="#content-allanbowe" title="Content">🖋</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Documentation">📖</a> <a href="#infra-allanbowe" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-allanbowe" title="Maintenance">🚧</a> <a href="#mentoring-allanbowe" title="Mentoring">🧑‍🏫</a> <a href="#question-allanbowe" title="Answering Questions">💬</a> <a href="https://github.com/sasjs/core/pulls?q=is%3Apr+reviewed-by%3Aallanbowe" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/sasjs/core/commits?author=allanbowe" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rafgag"><img src="https://avatars.githubusercontent.com/u/69139928?v=4?s=100" width="100px;" alt="rafgag"/><br /><sub><b>rafgag</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=rafgag" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tmoody"><img src="https://avatars.githubusercontent.com/u/79837106?v=4?s=100" width="100px;" alt="Trevor Moody"/><br /><sub><b>Trevor Moody</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=tmoody" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://krishna-acondy.io/"><img src="https://avatars.githubusercontent.com/u/2980428?v=4?s=100" width="100px;" alt="Krishna Acondy"/><br /><sub><b>Krishna Acondy</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=krishna-acondy" title="Code">💻</a> <a href="#infra-krishna-acondy" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#blog-krishna-acondy" title="Blogposts">📝</a> <a href="#content-krishna-acondy" title="Content">🖋</a> <a href="#ideas-krishna-acondy" title="Ideas, Planning, & Feedback">🤔</a> <a href="#video-krishna-acondy" title="Videos">📹</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/saadjutt01"><img src="https://avatars.githubusercontent.com/u/8914650?v=4?s=100" width="100px;" alt="Muhammad Saad "/><br /><sub><b>Muhammad Saad </b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=saadjutt01" title="Code">💻</a> <a href="#ideas-saadjutt01" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.erudicat.com/"><img src="https://avatars.githubusercontent.com/u/25773492?v=4?s=100" width="100px;" alt="Yury Shkoda"/><br /><sub><b>Yury Shkoda</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=YuryShkoda" title="Code">💻</a> <a href="#infra-YuryShkoda" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#video-YuryShkoda" title="Videos">📹</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/medjedovicm"><img src="https://avatars.githubusercontent.com/u/18329105?v=4?s=100" width="100px;" alt="Mihajlo Medjedovic"/><br /><sub><b>Mihajlo Medjedovic</b></sub></a><br /><a href="#infra-medjedovicm" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kkchandok"><img src="https://avatars.githubusercontent.com/u/46090627?v=4?s=100" width="100px;" alt="kkchandok"/><br /><sub><b>kkchandok</b></sub></a><br /><a href="#ideas-kkchandok" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/VladislavParhomchik"><img src="https://avatars.githubusercontent.com/u/83717836?v=4?s=100" width="100px;" alt="Vladislav Parhomchik"/><br /><sub><b>Vladislav Parhomchik</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=VladislavParhomchik" title="Tests">⚠️</a> <a href="https://github.com/sasjs/core/pulls?q=is%3Apr+reviewed-by%3AVladislavParhomchik" title="Reviewed Pull Requests">👀</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vznesh"><img src="https://avatars.githubusercontent.com/u/28916792?v=4?s=100" width="100px;" alt="Vignesh T."/><br /><sub><b>Vignesh T.</b></sub></a><br /><a href="https://github.com/sasjs/core/issues?q=author%3Avznesh" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yabwon"><img src="https://avatars.githubusercontent.com/u/9314894?v=4?s=100" width="100px;" alt="Bart Jablonski"/><br /><sub><b>Bart Jablonski</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=yabwon" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://bandism.net/"><img src="https://avatars.githubusercontent.com/u/22633385?v=4?s=100" width="100px;" alt="Ikko Ashimine"/><br /><sub><b>Ikko Ashimine</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=eltociear" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/henrik-forsell"><img src="https://avatars.githubusercontent.com/u/109935936?v=4?s=100" width="100px;" alt="Henrik Forsell"/><br /><sub><b>Henrik Forsell</b></sub></a><br /><a href="https://github.com/sasjs/core/commits?author=henrik-forsell" title="Documentation">📖</a></td>
</tr>
</tbody>
</table>
<!-- markdownlint-restore -->

121
all.sas
View File

@@ -30,7 +30,7 @@ options noquotelenmax;
**/
%macro mf_abort(mac=mf_abort.sas, msg=, iftrue=%str(1=1)
)/*/STORE SOURCE*/;
)/des='ungraceful abort' /*STORE SOURCE*/;
%if not(%eval(%unquote(&iftrue))) %then %return;
@@ -42,7 +42,8 @@ options noquotelenmax;
%mend mf_abort;
/** @endcond *//**
/** @endcond */
/**
@file
@brief de-duplicates a macro string
@details Removes all duplicates from a string of words. A delimeter can be
@@ -247,7 +248,8 @@ options noquotelenmax;
0
%end;
%mend mf_existfileref;/**
%mend mf_existfileref;
/**
@file
@brief Checks if a function exists
@details Returns 1 if the function exists, else 0. Note that this function
@@ -310,13 +312,17 @@ https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/baseplus.md#functionex
%local dsid rc;
%let dsid=%sysfunc(open(&libds,is));
%if &dsid=0 or %length(&var)=0 %then %do;
%if &dsid=0 %then %do;
%put %sysfunc(sysmsg());
0
0
%end;
%else %if %length(&var)=0 %then %do;
0
%let rc=%sysfunc(close(&dsid));
%end;
%else %do;
%sysfunc(varnum(&dsid,&var))
%let rc=%sysfunc(close(&dsid));
%sysfunc(varnum(&dsid,&var))
%let rc=%sysfunc(close(&dsid));
%end;
%mend mf_existvar;
@@ -2912,7 +2918,7 @@ run;
results. If it does not exist, it will be created, with the following format:
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|---|---|---|
|User Provided description|PASS|Column &inds contained ALL columns|
|User Provided description|PASS|Dataset &inds contained ALL columns|
@version 9.2
@author Allan Bowe
@@ -2986,7 +2992,7 @@ run;
results. If it does not exist, it will be created, with the following format:
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|---|---|---|
|User Provided description|PASS|Column &inds contained ALL columns|
|User Provided description|PASS|Dataset &inds contained ALL columns|
<h4> Related Macros </h4>
@@ -10449,7 +10455,7 @@ run;
data _null_;
putlog 'NOTE-' / 'NOTE-';
putlog "NOTE- &sysmacroname: table locked, waiting "@;
putlog "%sysfunc(sleep(&loop_inc)) seconds.. ";
putlog "%sysfunc(sleep(&loop_secs)) seconds.. ";
putlog "NOTE- (iteration &x of &loops)";
putlog 'NOTE-' / 'NOTE-';
run;
@@ -10482,7 +10488,10 @@ run;
where LOCK_LIB ="&lib" and LOCK_DS="&ds";
quit;
%if &syscc>0 %then %put syscc=&syscc sqlrc=&sqlrc;
%if &status=LOCKED %then %do;
%if &sqlobs=0 %then %do;
%put %str(WAR)NING: &lib..&ds has never been locked!;
%end;
%else %if &status=LOCKED %then %do;
data _null_;
putlog "&sysmacroname: unlocking &lib..&ds:";
run;
@@ -14059,7 +14068,8 @@ run;
filename __us2grp temp;
proc metadata in= "<UpdateMetadata><Reposid>$METAREPOSITORY</Reposid><Metadata>
<Person Id='&uuri'><IdentityGroups><IdentityGroup ObjRef='&guri' />
<Person Id='%nrstr(&uuri)'>
<IdentityGroups><IdentityGroup ObjRef='%nrstr(&guri)' />
</IdentityGroups></Person></Metadata>
<NS>SAS</NS><Flags>268435456</Flags></UpdateMetadata>"
out=__us2grp verbose;
@@ -14076,7 +14086,8 @@ run;
filename __us2grp clear;
%mend mm_adduser2group;/**
%mend mm_adduser2group;
/**
@file
@brief Assigns library directly using details from metadata
@details Queries metadata to get the libname definition then allocates the
@@ -16439,7 +16450,7 @@ data _null_;
put ' put " ""&wt"" : {"; ';
put ' put ''"nlobs":'' nlobs; ';
put ' put '',"nvars":'' nvars; ';
put ' %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y,maxobs=10 ';
put ' %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y ';
put ' ,maxobs=&workobs ';
put ' ) ';
put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
@@ -16539,9 +16550,11 @@ data _null_;
put ' ';
put '%mend mm_webout; ';
/* WEBOUT END */
put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL,showmeta=NO);';
put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL,showmeta=NO';
put ' ,maxobs=MAX';
put ');';
put ' %mm_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt,missing=&missing';
put ' ,showmeta=&showmeta';
put ' ,showmeta=&showmeta,maxobs=&maxobs';
put ' )';
put '%mend;';
run;
@@ -20121,7 +20134,7 @@ run;
put " ""&wt"" : {";
put '"nlobs":' nlobs;
put ',"nvars":' nvars;
%mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y,maxobs=10
%mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y
,maxobs=&workobs
)
data _null_; file _sjsref mod encoding='utf-8';
@@ -21525,7 +21538,7 @@ data _null_;
put ' put " ""&wt"" : {"; ';
put ' put ''"nlobs":'' nlobs; ';
put ' put '',"nvars":'' nvars; ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y,maxobs=10 ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y ';
put ' ,maxobs=&workobs ';
put ' ) ';
put ' data _null_; file &fref mod encoding=''utf-8'' termstr=lf; ';
@@ -21792,7 +21805,7 @@ filename &headref clear;
@param [in] uid= (0) Provide the userid on which to filter
@param [out] outds= (work.ms_getgroups) This output dataset will contain the
list of groups. Format:
|NAME:$32.|DESCRIPTION:$64.|GROUPID:best.|
|NAME:$32.|DESCRIPTION:$256.|GROUPID:best.|
|---|---|---|
|`SomeGroup `|`A group `|`1`|
|`Another Group`|`this is a different group`|`2`|
@@ -21828,7 +21841,7 @@ filename &headref clear;
%if %sysget(MODE)=desktop %then %do;
/* groups api does not exist in desktop mode */
data &outds;
length NAME $32 DESCRIPTION $64. GROUPID 8;
length NAME $32 DESCRIPTION $256. GROUPID 8;
name="&sysuserid";
description="&sysuserid (group - desktop mode)";
groupid=1;
@@ -21884,7 +21897,7 @@ libname &libref JSON fileref=&fref1;
%if "&user"="0" and "&uid"="0" %then %do;
data &outds;
length NAME $32 DESCRIPTION $64. GROUPID 8;
length NAME $32 DESCRIPTION $256. GROUPID 8;
if _n_=1 then call missing(of _all_);
set &libref..root;
drop ordinal_root;
@@ -21892,7 +21905,7 @@ libname &libref JSON fileref=&fref1;
%end;
%else %do;
data &outds;
length NAME $32 DESCRIPTION $64. GROUPID 8;
length NAME $32 DESCRIPTION $256. GROUPID 8;
if _n_=1 then call missing(of _all_);
set &libref..groups;
drop ordinal_:;
@@ -22104,8 +22117,9 @@ options &optval;
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquelibref.sas
@li mf_getuniquename.sas
@li mp_abort.sas
@li mp_chop.sas
**/
@@ -22218,7 +22232,10 @@ run;
run;
%end;
filename &outref temp lrecl=32767;
%local resp_path;
%let resp_path=%sysfunc(pathname(work))/%mf_getuniquename();
filename &outref "&resp_path" lrecl=32767;
/* prepare request*/
proc http method='POST' headerin=&authref in=&mainref out=&outref
url="&_sasjs_apiserverurl.&_sasjs_apipath?_program=&pgm%str(&)_debug=131";
@@ -22226,6 +22243,7 @@ proc http method='POST' headerin=&authref in=&mainref out=&outref
debug level=2;
%end;
run;
%if (&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
or &mdebug=1
%then %do;
@@ -22241,11 +22259,22 @@ or &mdebug=1
options &optval;
%if &outlogds ne _null_ or &mdebug=1 %then %do;
%local dumplib;
%let dumplib=%mf_getuniquelibref();
libname &dumplib json fileref=&outref;
%local matchstr chopout;
%let matchstr=SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784;
%let chopout=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop);
%mp_chop("&resp_path"
,matchvar=matchstr
,keep=LAST
,matchpoint=END
,outfile="&chopout"
,mdebug=&mdebug
)
data &outlogds;
set &dumplib..log;
infile "&chopout" lrecl=2000;
length line $2000;
line=_infile_;
%if &mdebug=1 %then %do;
putlog line=;
%end;
@@ -22372,50 +22401,38 @@ run;
)
/* SASjs services have the _webout embedded in wrapper JSON */
/* Files can also be very large - so use a dedicated macro to chop it out */
%local matchstr1 matchstr2 ;
%let matchstr1={"status":"success","_webout":{;
%let matchstr2=},"log":[{;
%let chopout1=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop1);
%let chopout2=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop2);
/* chop out JSON section */
%local matchstr chopout;
%let matchstr=SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784;
%let chopout=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop);
%mp_chop("%sysfunc(pathname(&fref1,F))"
,matchvar=matchstr1
,keep=LAST
,matchpoint=END
,offset=-1
,outfile="&chopout1"
,mdebug=&mdebug
)
%mp_chop("&chopout1"
,matchvar=matchstr2
,matchvar=matchstr
,keep=FIRST
,matchpoint=START
,offset=1
,outfile="&chopout2"
,offset=-1
,outfile="&chopout"
,mdebug=&mdebug
)
%if &outlib ne 0 %then %do;
libname &outlib json "&chopout2";
libname &outlib json "&chopout";
%end;
%if &outref ne 0 %then %do;
filename &outref "&chopout2";
filename &outref "&chopout";
%end;
%if &mdebug=0 %then %do;
filename &webref clear;
filename &fref1 clear;
filename &fref2 clear;
%end;
%else %do;
%put &sysmacroname exit vars:;
%put _local_;
%end;
%mend ms_testservice;/**
%mend ms_testservice;
/**
@file
@brief Send data to/from sasjs/server
@details This macro should be added to the start of each web service,
@@ -22558,7 +22575,7 @@ run;
put " ""&wt"" : {";
put '"nlobs":' nlobs;
put ',"nvars":' nvars;
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y,maxobs=10
%mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y
,maxobs=&workobs
)
data _null_; file &fref mod encoding='utf-8' termstr=lf;

View File

@@ -12,7 +12,7 @@
**/
%macro mf_abort(mac=mf_abort.sas, msg=, iftrue=%str(1=1)
)/*/STORE SOURCE*/;
)/des='ungraceful abort' /*STORE SOURCE*/;
%if not(%eval(%unquote(&iftrue))) %then %return;
@@ -24,4 +24,4 @@
%mend mf_abort;
/** @endcond */
/** @endcond */

View File

@@ -25,13 +25,17 @@
%local dsid rc;
%let dsid=%sysfunc(open(&libds,is));
%if &dsid=0 or %length(&var)=0 %then %do;
%if &dsid=0 %then %do;
%put %sysfunc(sysmsg());
0
0
%end;
%else %if %length(&var)=0 %then %do;
0
%let rc=%sysfunc(close(&dsid));
%end;
%else %do;
%sysfunc(varnum(&dsid,&var))
%let rc=%sysfunc(close(&dsid));
%sysfunc(varnum(&dsid,&var))
%let rc=%sysfunc(close(&dsid));
%end;
%mend mf_existvar;

View File

@@ -22,7 +22,7 @@
results. If it does not exist, it will be created, with the following format:
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|---|---|---|
|User Provided description|PASS|Column &inds contained ALL columns|
|User Provided description|PASS|Dataset &inds contained ALL columns|
@version 9.2
@author Allan Bowe

View File

@@ -41,7 +41,7 @@
results. If it does not exist, it will be created, with the following format:
|TEST_DESCRIPTION:$256|TEST_RESULT:$4|TEST_COMMENTS:$256|
|---|---|---|
|User Provided description|PASS|Column &inds contained ALL columns|
|User Provided description|PASS|Dataset &inds contained ALL columns|
<h4> Related Macros </h4>

View File

@@ -167,7 +167,7 @@ run;
data _null_;
putlog 'NOTE-' / 'NOTE-';
putlog "NOTE- &sysmacroname: table locked, waiting "@;
putlog "%sysfunc(sleep(&loop_inc)) seconds.. ";
putlog "%sysfunc(sleep(&loop_secs)) seconds.. ";
putlog "NOTE- (iteration &x of &loops)";
putlog 'NOTE-' / 'NOTE-';
run;
@@ -200,7 +200,10 @@ run;
where LOCK_LIB ="&lib" and LOCK_DS="&ds";
quit;
%if &syscc>0 %then %put syscc=&syscc sqlrc=&sqlrc;
%if &status=LOCKED %then %do;
%if &sqlobs=0 %then %do;
%put %str(WAR)NING: &lib..&ds has never been locked!;
%end;
%else %if &status=LOCKED %then %do;
data _null_;
putlog "&sysmacroname: unlocking &lib..&ds:";
run;

View File

@@ -81,7 +81,8 @@ run;
filename __us2grp temp;
proc metadata in= "<UpdateMetadata><Reposid>$METAREPOSITORY</Reposid><Metadata>
<Person Id='&uuri'><IdentityGroups><IdentityGroup ObjRef='&guri' />
<Person Id='%nrstr(&uuri)'>
<IdentityGroups><IdentityGroup ObjRef='%nrstr(&guri)' />
</IdentityGroups></Person></Metadata>
<NS>SAS</NS><Flags>268435456</Flags></UpdateMetadata>"
out=__us2grp verbose;
@@ -98,4 +99,4 @@ run;
filename __us2grp clear;
%mend mm_adduser2group;
%mend mm_adduser2group;

View File

@@ -546,7 +546,7 @@ data _null_;
put ' put " ""&wt"" : {"; ';
put ' put ''"nlobs":'' nlobs; ';
put ' put '',"nvars":'' nvars; ';
put ' %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y,maxobs=10 ';
put ' %mp_jsonout(OBJ,&wt,jref=_sjsref,dslabel=first10rows,showmeta=Y ';
put ' ,maxobs=&workobs ';
put ' ) ';
put ' data _null_; file _sjsref mod encoding=''utf-8''; ';
@@ -646,9 +646,11 @@ data _null_;
put ' ';
put '%mend mm_webout; ';
/* WEBOUT END */
put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL,showmeta=NO);';
put '%macro webout(action,ds,dslabel=,fmt=,missing=NULL,showmeta=NO';
put ' ,maxobs=MAX';
put ');';
put ' %mm_webout(&action,ds=&ds,dslabel=&dslabel,fmt=&fmt,missing=&missing';
put ' ,showmeta=&showmeta';
put ' ,showmeta=&showmeta,maxobs=&maxobs';
put ' )';
put '%mend;';
run;

668
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -33,6 +33,6 @@
"prepare": "git rev-parse --git-dir && git config core.hooksPath ./.git-hooks || true"
},
"devDependencies": {
"@sasjs/cli": "3.13.0"
"@sasjs/cli": "3.24.0"
}
}

View File

@@ -1,224 +1,224 @@
/**
@file
@brief Deploy repo as a SAS PACKAGES module
@details After every release, this program is executed to update the SASPAC
repo with the latest macros (and same version number).
The program is first compiled using sasjs compile, then executed using
sasjs run.
Requires the server to have SSH keys.
<h4> SAS Macros </h4>
@li mp_gitadd.sas
@li mp_gitreleaseinfo.sas
@li mp_gitstatus.sas
**/
/* get package version */
%mp_gitreleaseinfo(GITHUB,sasjs/core,outlib=splib)
data _null_;
set splib.root;
call symputx('version',substr(TAG_NAME,2));
run;
/* clone the source repo */
%let dir = %sysfunc(pathname(work))/core;
%put source clone rc=%sysfunc(GITFN_CLONE(https://github.com/sasjs/core,&dir));
/*
clone the target repo.
If you have issues, see: https://stackoverflow.com/questions/74082874
*/
options dlcreatedir;
%let dirOut = %sysfunc(pathname(work))/package;
libname _ "&dirOut.";
%put tgt clone rc=%sysfunc(GITFN_CLONE(
git@github.com:SASPAC/sasjscore.git,
&dirOut,
git,
%str( ),
/home/sasjssrv/.ssh/id_ecdsa.pub,
/home/sasjssrv/.ssh/id_ecdsa
));
/*
Prepare Package Metadata
*/
data _null_;
infile CARDS4;
file "&dirOut./description.sas";
input;
if _infile_ =: 'Version:' then put "Version: &version.";
else put _infile_;
CARDS4;
Type: Package
Package: SASjsCore
Title: SAS Macros for Application Development
Version: $(PLACEHOLDER)
Author: Allan Bowe
Maintainer: 4GL Ltd
License: MIT
Encoding: UTF8
DESCRIPTION START:
The SASjs Macro Core library is a component of the SASjs framework, the
source for which is avaible here: https://github.com/sasjs
Macros are divided by:
* Macro Functions (prefix mf_)
* Macro Procedures (prefix mp_)
* Macros for Metadata (prefix mm_)
* Macros for SASjs Server (prefix ms_)
* Macros for Viya (prefix mv_)
DESCRIPTION END:
;;;;
run;
/*
Prepare Package License
*/
data _null_;
file "&dirOut./license.sas";
infile "&dir/LICENSE";
input;
put _infile_;
run;
/*
Extract Core files into MacroCore Package location
*/
data members(compress=char);
length dref dref2 $ 8 name name2 $ 32 path $ 2048;
rc = filename(dref, "&dir.");
put dref=;
did = dopen(dref);
if did then
do i = 1 to dnum(did);
name = dread(did, i);
if name in
("base" "ddl" "fcmp" "lua" "meta" "metax" "server" "viya" "xplatform")
then do;
rc = filename(dref2,catx("/", "&dir.", name));
put dref2= name;
did2 = dopen(dref2);
if did2 then
do j = 1 to dnum(did2);
name2 = dread(did2, j);
path = catx("/", "&dir.", name, name2);
if "sas" = scan(name2, -1, ".") then output;
end;
rc = dclose(did2);
rc = filename(dref2);
end;
end;
rc = dclose(did);
rc = filename(dref);
keep name name2 path;
run;
%let temp_options = %sysfunc(getoption(source)) %sysfunc(getoption(notes));
options nosource nonotes;
data _null_;
set members;
by name notsorted;
ord + first.name;
if first.name then
do;
call execute('libname _ '
!! quote(catx("/", "&dirOut.", put(ord, z3.)!!"_macros"))
!! ";"
);
put @1 "./" ord z3. "_macros/";
end;
put @10 name2;
call execute("
data _null_;
infile " !! quote(strip(path)) !! ";
file " !! quote(catx("/", "&dirOut.", put(ord, z3.)!!"_macros", name2)) !!";
input;
select;
when (2 = trigger) put _infile_;
when (_infile_ = '/**') do; put '/*** HELP START ***//**'; trigger+1; end;
when (_infile_ = '**/') do; put '**//*** HELP END ***/'; trigger+1; end;
otherwise put _infile_;
end;
run;");
run;
options &temp_options.;
/*
Generate SASjsCore Package
*/
%GeneratePackage(
filesLocation=&dirOut
)
/**
* apply new version in a github action
* 1. create folder
* 2. create template yaml
* 3. replace version number
*/
%mf_mkdir(&dirout/.github/workflows)
%let desc=Version &version of sasjs/core is now on SAS PACKAGES :ok_hand:;
data _null_;
file "&dirout/.github/workflows/release.yml";
put "name: SASjs Core Package Publish Tag";
put "on:";
put " push:";
put " branches:";
put " - main";
put "jobs:";
put " update:";
put " runs-on: ubuntu-latest";
put " steps:";
put " - uses: actions/checkout@master";
put " - name: Make Release";
put " uses: alice-biometrics/release-creator/@v1.0.5";
put " with:";
put " github_token: ${{ secrets.GH_TOKEN }}";
put " branch: main";
put " draft: false";
put " version: &version";
put " description: '&desc'";
run;
/**
* Add, Commit & Push!
*/
%mp_gitstatus(&dirout,outds=work.gitstatus,mdebug=1)
%mp_gitadd(&dirout,inds=work.gitstatus,mdebug=1)
data _null_;
rc=gitfn_commit("&dirout"
,"HEAD","&sysuserid","sasjs@core"
,"FEAT: Releasing &version"
);
put rc=;
rc=git_push(
"&dirout"
,"git"
,""
,"/home/sasjssrv/.ssh/id_ecdsa.pub"
,"/home/sasjssrv/.ssh/id_ecdsa"
);
run;
/**
@file
@brief Deploy repo as a SAS PACKAGES module
@details After every release, this program is executed to update the SASPAC
repo with the latest macros (and same version number).
The program is first compiled using sasjs compile, then executed using
sasjs run.
Requires the server to have SSH keys.
<h4> SAS Macros </h4>
@li mp_gitadd.sas
@li mp_gitreleaseinfo.sas
@li mp_gitstatus.sas
**/
/* get package version */
%mp_gitreleaseinfo(GITHUB,sasjs/core,outlib=splib)
data _null_;
set splib.root;
call symputx('version',substr(TAG_NAME,2));
run;
/* clone the source repo */
%let dir = %sysfunc(pathname(work))/core;
%put source clone rc=%sysfunc(GITFN_CLONE(https://github.com/sasjs/core,&dir));
/*
clone the target repo.
If you have issues, see: https://stackoverflow.com/questions/74082874
*/
options dlcreatedir;
%let dirOut = %sysfunc(pathname(work))/package;
libname _ "&dirOut.";
%put tgt clone rc=%sysfunc(GITFN_CLONE(
git@github.com:SASPAC/sasjscore.git,
&dirOut,
git,
%str( ),
/home/sasjssrv/.ssh/id_ecdsa.pub,
/home/sasjssrv/.ssh/id_ecdsa
));
/*
Prepare Package Metadata
*/
data _null_;
infile CARDS4;
file "&dirOut./description.sas";
input;
if _infile_ =: 'Version:' then put "Version: &version.";
else put _infile_;
CARDS4;
Type: Package
Package: SASjsCore
Title: SAS Macros for Application Development
Version: $(PLACEHOLDER)
Author: Allan Bowe
Maintainer: 4GL Ltd
License: MIT
Encoding: UTF8
DESCRIPTION START:
The SASjs Macro Core library is a component of the SASjs framework, the
source for which is avaible here: https://github.com/sasjs
Macros are divided by:
* Macro Functions (prefix mf_)
* Macro Procedures (prefix mp_)
* Macros for Metadata (prefix mm_)
* Macros for SASjs Server (prefix ms_)
* Macros for Viya (prefix mv_)
DESCRIPTION END:
;;;;
run;
/*
Prepare Package License
*/
data _null_;
file "&dirOut./license.sas";
infile "&dir/LICENSE";
input;
put _infile_;
run;
/*
Extract Core files into MacroCore Package location
*/
data members(compress=char);
length dref dref2 $ 8 name name2 $ 32 path $ 2048;
rc = filename(dref, "&dir.");
put dref=;
did = dopen(dref);
if did then
do i = 1 to dnum(did);
name = dread(did, i);
if name in
("base" "ddl" "fcmp" "lua" "meta" "metax" "server" "viya" "xplatform")
then do;
rc = filename(dref2,catx("/", "&dir.", name));
put dref2= name;
did2 = dopen(dref2);
if did2 then
do j = 1 to dnum(did2);
name2 = dread(did2, j);
path = catx("/", "&dir.", name, name2);
if "sas" = scan(name2, -1, ".") then output;
end;
rc = dclose(did2);
rc = filename(dref2);
end;
end;
rc = dclose(did);
rc = filename(dref);
keep name name2 path;
run;
%let temp_options = %sysfunc(getoption(source)) %sysfunc(getoption(notes));
options nosource nonotes;
data _null_;
set members;
by name notsorted;
ord + first.name;
if first.name then
do;
call execute('libname _ '
!! quote(catx("/", "&dirOut.", put(ord, z3.)!!"_macros"))
!! ";"
);
put @1 "./" ord z3. "_macros/";
end;
put @10 name2;
call execute("
data _null_;
infile " !! quote(strip(path)) !! ";
file " !! quote(catx("/", "&dirOut.", put(ord, z3.)!!"_macros", name2)) !!";
input;
select;
when (2 = trigger) put _infile_;
when (_infile_ = '/**') do; put '/*** HELP START ***//**'; trigger+1; end;
when (_infile_ = '**/') do; put '**//*** HELP END ***/'; trigger+1; end;
otherwise put _infile_;
end;
run;");
run;
options &temp_options.;
/*
Generate SASjsCore Package
*/
%GeneratePackage(
filesLocation=&dirOut
)
/**
* apply new version in a github action
* 1. create folder
* 2. create template yaml
* 3. replace version number
*/
%mf_mkdir(&dirout/.github/workflows)
%let desc=Version &version of sasjs/core is now on SAS PACKAGES :ok_hand:;
data _null_;
file "&dirout/.github/workflows/release.yml";
put "name: SASjs Core Package Publish Tag";
put "on:";
put " push:";
put " branches:";
put " - main";
put "jobs:";
put " update:";
put " runs-on: ubuntu-latest";
put " steps:";
put " - uses: actions/checkout@master";
put " - name: Make Release";
put " uses: alice-biometrics/release-creator/@v1.0.5";
put " with:";
put " github_token: ${{ secrets.GH_TOKEN }}";
put " branch: main";
put " draft: false";
put " version: &version";
put " description: '&desc'";
run;
/**
* Add, Commit & Push!
*/
%mp_gitstatus(&dirout,outds=work.gitstatus,mdebug=1)
%mp_gitadd(&dirout,inds=work.gitstatus,mdebug=1)
data _null_;
rc=gitfn_commit("&dirout"
,"HEAD","&sysuserid","sasjs@core"
,"FEAT: Releasing &version"
);
put rc=;
rc=git_push(
"&dirout"
,"git"
,""
,"/home/sasjssrv/.ssh/id_ecdsa.pub"
,"/home/sasjssrv/.ssh/id_ecdsa"
);
run;

View File

@@ -539,7 +539,7 @@ data _null_;
put ' put " ""&wt"" : {"; ';
put ' put ''"nlobs":'' nlobs; ';
put ' put '',"nvars":'' nvars; ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y,maxobs=10 ';
put ' %mp_jsonout(OBJ,&wt,jref=&fref,dslabel=first10rows,showmeta=Y ';
put ' ,maxobs=&workobs ';
put ' ) ';
put ' data _null_; file &fref mod encoding=''utf-8'' termstr=lf; ';

View File

@@ -22,7 +22,7 @@
@param [in] uid= (0) Provide the userid on which to filter
@param [out] outds= (work.ms_getgroups) This output dataset will contain the
list of groups. Format:
|NAME:$32.|DESCRIPTION:$64.|GROUPID:best.|
|NAME:$32.|DESCRIPTION:$256.|GROUPID:best.|
|---|---|---|
|`SomeGroup `|`A group `|`1`|
|`Another Group`|`this is a different group`|`2`|
@@ -58,7 +58,7 @@
%if %sysget(MODE)=desktop %then %do;
/* groups api does not exist in desktop mode */
data &outds;
length NAME $32 DESCRIPTION $64. GROUPID 8;
length NAME $32 DESCRIPTION $256. GROUPID 8;
name="&sysuserid";
description="&sysuserid (group - desktop mode)";
groupid=1;
@@ -114,7 +114,7 @@ libname &libref JSON fileref=&fref1;
%if "&user"="0" and "&uid"="0" %then %do;
data &outds;
length NAME $32 DESCRIPTION $64. GROUPID 8;
length NAME $32 DESCRIPTION $256. GROUPID 8;
if _n_=1 then call missing(of _all_);
set &libref..root;
drop ordinal_root;
@@ -122,7 +122,7 @@ libname &libref JSON fileref=&fref1;
%end;
%else %do;
data &outds;
length NAME $32 DESCRIPTION $64. GROUPID 8;
length NAME $32 DESCRIPTION $256. GROUPID 8;
if _n_=1 then call missing(of _all_);
set &libref..groups;
drop ordinal_:;

View File

@@ -39,8 +39,9 @@
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mf_getuniquelibref.sas
@li mf_getuniquename.sas
@li mp_abort.sas
@li mp_chop.sas
**/
@@ -153,7 +154,10 @@ run;
run;
%end;
filename &outref temp lrecl=32767;
%local resp_path;
%let resp_path=%sysfunc(pathname(work))/%mf_getuniquename();
filename &outref "&resp_path" lrecl=32767;
/* prepare request*/
proc http method='POST' headerin=&authref in=&mainref out=&outref
url="&_sasjs_apiserverurl.&_sasjs_apipath?_program=&pgm%str(&)_debug=131";
@@ -161,6 +165,7 @@ proc http method='POST' headerin=&authref in=&mainref out=&outref
debug level=2;
%end;
run;
%if (&SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201)
or &mdebug=1
%then %do;
@@ -176,11 +181,22 @@ or &mdebug=1
options &optval;
%if &outlogds ne _null_ or &mdebug=1 %then %do;
%local dumplib;
%let dumplib=%mf_getuniquelibref();
libname &dumplib json fileref=&outref;
%local matchstr chopout;
%let matchstr=SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784;
%let chopout=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop);
%mp_chop("&resp_path"
,matchvar=matchstr
,keep=LAST
,matchpoint=END
,outfile="&chopout"
,mdebug=&mdebug
)
data &outlogds;
set &dumplib..log;
infile "&chopout" lrecl=2000;
length line $2000;
line=_infile_;
%if &mdebug=1 %then %do;
putlog line=;
%end;

View File

@@ -108,47 +108,34 @@ run;
)
/* SASjs services have the _webout embedded in wrapper JSON */
/* Files can also be very large - so use a dedicated macro to chop it out */
%local matchstr1 matchstr2 ;
%let matchstr1={"status":"success","_webout":{;
%let matchstr2=},"log":[{;
%let chopout1=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop1);
%let chopout2=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop2);
/* chop out JSON section */
%local matchstr chopout;
%let matchstr=SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784;
%let chopout=%sysfunc(pathname(work))/%mf_getuniquename(prefix=chop);
%mp_chop("%sysfunc(pathname(&fref1,F))"
,matchvar=matchstr1
,keep=LAST
,matchpoint=END
,offset=-1
,outfile="&chopout1"
,mdebug=&mdebug
)
%mp_chop("&chopout1"
,matchvar=matchstr2
,matchvar=matchstr
,keep=FIRST
,matchpoint=START
,offset=1
,outfile="&chopout2"
,offset=-1
,outfile="&chopout"
,mdebug=&mdebug
)
%if &outlib ne 0 %then %do;
libname &outlib json "&chopout2";
libname &outlib json "&chopout";
%end;
%if &outref ne 0 %then %do;
filename &outref "&chopout2";
filename &outref "&chopout";
%end;
%if &mdebug=0 %then %do;
filename &webref clear;
filename &fref1 clear;
filename &fref2 clear;
%end;
%else %do;
%put &sysmacroname exit vars:;
%put _local_;
%end;
%mend ms_testservice;
%mend ms_testservice;

View File

@@ -17,4 +17,24 @@
%mp_assert(
iftrue=(%mf_existvar(sashelp.class,isjustanumber)=0),
desc=Checking non existing var does not exist
)
data work.lockcheck;
a=1;
output;
stop;
run;
%mp_assert(
iftrue=(%mf_existvar(work.lockcheck,)=0),
desc=Checking non-provided var does not exist
)
proc sql;
update work.lockcheck set a=2;
%mp_assert(
iftrue=(&syscc=0),
desc=Checking the lock was released,
outds=work.test_results
)

View File

@@ -7,23 +7,35 @@
@li mp_assertcols.sas
@li mp_assertcolvals.sas
@li mp_assertdsobs.sas
@li mp_assertscope.sas
**/
/* valid filter */
%mp_getcols(sashelp.airline,outds=work.info)
/* make some data */
proc sql;
create table work.src(
SOME_DATETIME float format=datetime19.,
SOME_CHAR char(16),
SOME_NUM num,
SOME_TIME num format=time8.,
SOME_DATE num format=date9.
);
/* run macro, checking for scope leakage */
%mp_assertscope(SNAPSHOT)
%mp_getcols(work.src,outds=work.info)
%mp_assertscope(COMPARE)
%mp_assertdsobs(work.info,
desc=Has 3 records,
test=EQUALS 3,
desc=Has 5 records,
test=EQUALS 5,
outds=work.test_results
)
data work.check;
length val $10;
do val='NUMERIC','DATE','CHARACTER';
do val='NUMERIC','DATE','CHARACTER','DATETIME','TIME';
output;
end;
run;

View File

@@ -4,8 +4,10 @@
<h4> SAS Macros </h4>
@li mp_lockanytable.sas
@li mp_assert.sas
@li mp_assertcols.sas
@li mp_assertcolvals.sas
@li mp_assertscope.sas
@li mp_coretable.sas
**/
@@ -61,3 +63,18 @@ run;
desc=Ref is captured in unlock,
test=ANYVAL
)
/* attempt unlock of a table that was never locked */
%mp_lockanytable(UNLOCK,lib=no,ds=doesnotexist,ref=bye, ctl_ds=work.controller)
%mp_assert(
iftrue=(&syscc=0),
desc=Ability to unlock a table that was never locked,
outds=work.test_results
)
/* test for macro variable scope leakage */
%mp_assertscope(SNAPSHOT)
%mp_lockanytable(LOCK,lib=tmp,ds=testscope,ref=This Ref, ctl_ds=work.controller)
%mp_assertscope(COMPARE)

View File

@@ -4,7 +4,7 @@
@brief Testing mv_jobflow macro
@details One of the remote jobs aborts with syscc>0 - test to
make sure this comes back to the calling session
<h4> SAS Macros </h4>
@li mp_assert.sas
@li mv_createjob.sas

View File

@@ -3,7 +3,7 @@
@brief Testing mv_jobflow macro
@details All jobs complete successfully with syscc = 0 - test to
make sure this comes back to the calling session
<h4> SAS Macros </h4>
@li mp_assert.sas
@li mv_createjob.sas

View File

@@ -4,7 +4,7 @@
@brief Testing mv_registerclient.sas macro
@details Tests for successful registration. For this to work, the test
account must be an admin.
<h4> SAS Macros </h4>
@li mf_getuniquename.sas
@li mp_assertcolvals.sas

View File

@@ -1,10 +1,9 @@
/**
@file
@brief Testing mv_registerclient.sas macro
@details Tests for unsuccessful registration. To do this, overrides are
applied for the mf_loc.sas and mp_abort.sas macros.
<h4> SAS Macros </h4>
@li mp_assert.sas
@li mv_registerclient.sas

View File

@@ -1,60 +1,60 @@
/**
@file mfv_existsashdat.sas
@brief Checks whether a CAS sashdat dataset exists in persistent storage.
@details Can be used in open code, eg as follows:
%if %mfv_existsashdat(libds=casuser.sometable) %then %put yes it does!;
The function uses `dosubl()` to run the `table.fileinfo` action, for the
specified library, filtering for `*.sashdat` tables. The results are stored
in a WORK table (&outprefix._&lib). If that table already exists, it is
queried instead, to avoid the dosubl() performance hit.
To force a rescan, just use a new `&outprefix` value, or delete the table(s)
before running the function.
@param libds library.dataset
@param outprefix= (work.mfv_existsashdat) Used to store the current HDATA
tables to improve subsequent query performance. This reference is a prefix
and is converted to `&prefix._{libref}`
@return output returns 1 or 0
@version 0.2
@author Mathieu Blauw
**/
%macro mfv_existsashdat(libds,outprefix=work.mfv_existsashdat
);
%local rc dsid name lib ds;
%let lib=%upcase(%scan(&libds,1,'.'));
%let ds=%upcase(%scan(&libds,-1,'.'));
/* if table does not exist, create it */
%if %sysfunc(exist(&outprefix._&lib)) ne 1 %then %do;
%let rc=%sysfunc(dosubl(%nrstr(
/* Read in table list (once per &lib per session) */
proc cas;
table.fileinfo result=source_list /caslib="&lib";
val=findtable(source_list);
saveresult val dataout=&outprefix._&lib;
quit;
/* Only keep name, without file extension */
data &outprefix._&lib;
set &outprefix._&lib(where=(Name like '%.sashdat') keep=Name);
Name=upcase(scan(Name,1,'.'));
run;
)));
%end;
/* Scan table for hdat existence */
%let dsid=%sysfunc(open(&outprefix._&lib(where=(name="&ds"))));
%syscall set(dsid);
%let rc = %sysfunc(fetch(&dsid));
%let rc = %sysfunc(close(&dsid));
/* Return result */
%if "%trim(&name)"="%trim(&ds)" %then 1;
%else 0;
%mend mfv_existsashdat;
/**
@file mfv_existsashdat.sas
@brief Checks whether a CAS sashdat dataset exists in persistent storage.
@details Can be used in open code, eg as follows:
%if %mfv_existsashdat(libds=casuser.sometable) %then %put yes it does!;
The function uses `dosubl()` to run the `table.fileinfo` action, for the
specified library, filtering for `*.sashdat` tables. The results are stored
in a WORK table (&outprefix._&lib). If that table already exists, it is
queried instead, to avoid the dosubl() performance hit.
To force a rescan, just use a new `&outprefix` value, or delete the table(s)
before running the function.
@param libds library.dataset
@param outprefix= (work.mfv_existsashdat) Used to store the current HDATA
tables to improve subsequent query performance. This reference is a prefix
and is converted to `&prefix._{libref}`
@return output returns 1 or 0
@version 0.2
@author Mathieu Blauw
**/
%macro mfv_existsashdat(libds,outprefix=work.mfv_existsashdat
);
%local rc dsid name lib ds;
%let lib=%upcase(%scan(&libds,1,'.'));
%let ds=%upcase(%scan(&libds,-1,'.'));
/* if table does not exist, create it */
%if %sysfunc(exist(&outprefix._&lib)) ne 1 %then %do;
%let rc=%sysfunc(dosubl(%nrstr(
/* Read in table list (once per &lib per session) */
proc cas;
table.fileinfo result=source_list /caslib="&lib";
val=findtable(source_list);
saveresult val dataout=&outprefix._&lib;
quit;
/* Only keep name, without file extension */
data &outprefix._&lib;
set &outprefix._&lib(where=(Name like '%.sashdat') keep=Name);
Name=upcase(scan(Name,1,'.'));
run;
)));
%end;
/* Scan table for hdat existence */
%let dsid=%sysfunc(open(&outprefix._&lib(where=(name="&ds"))));
%syscall set(dsid);
%let rc = %sysfunc(fetch(&dsid));
%let rc = %sysfunc(close(&dsid));
/* Return result */
%if "%trim(&name)"="%trim(&ds)" %then 1;
%else 0;
%mend mfv_existsashdat;