3 Commits
Author SHA1 Message Date
allan 127f10fba9 Merge pull request 'docs(build): pin the deploy tooling, correct the hook macro-scope note' (#18) from docs/pin-deploy-and-hook-scope into main
Publish to docs.datacontroller.io / Deploy docs (push) Successful in 1m29s
Reviewed-on: #18
2026-10-15 18:56:57 +00:00
dc 8a22e28a46 docs(developer-guide): correct the LIBREF/DS macro-scope note
The post-edit hook section claimed a `%let` "creates a new variable in the
hook's own scope and is silently discarded" while `call symputx` updates the
existing one. That is not how SAS resolves it: LIBREF and DS already exist in
an enclosing symbol table (mpe_loader's local table), and a macro only gets a
new local when the name is absent from every enclosing table, so both forms
assign to the same variable. Reworded to state that, and to keep the practical
advice (call symputx is explicit and does not depend on the enclosing scope
still holding the name).

Raised in review of #16.
2026-10-15 18:28:36 +00:00
dc 8ed0f16004 docs(build): pin the deploy tooling versions and disable install scripts
The publish workflow installed cloudron-surfer, the mkdocs pip set and
@marp-team/marp-cli with no version pins, so a breaking or compromised upstream
release would ship straight to the live site on the next merge to main.

- pin cloudron-surfer@6.4.1, mkdocs==1.6.1, mkdocs-material==9.7.7,
  fontawesome_markdown==0.2.6, mkdocs-redirects==1.2.3 and
  @marp-team/marp-cli@4.5.1 (the versions the site builds with today)
- add .npmrc with ignore-scripts=true and save-exact=true; neither npm package
  ships an install/preinstall/postinstall hook, so nothing is skipped
2026-10-15 18:28:36 +00:00
3 changed files with 23 additions and 9 deletions

No files matched your search

+10 -7
View File
@@ -31,19 +31,22 @@ jobs:
apt install -y ./google-chrome*.deb; apt install -y ./google-chrome*.deb;
export CHROME_BIN=/usr/bin/google-chrome export CHROME_BIN=/usr/bin/google-chrome
# Deploy tooling is pinned to exact versions: the workflow builds whatever
# is committed, and an unpinned `latest` would let a breaking or
# compromised upstream release ship straight to the live site.
- name: Install Surfer - name: Install Surfer
run: | run: |
npm -g install cloudron-surfer npm -g install cloudron-surfer@6.4.1
- name: build site - name: build site
run: | run: |
pip install mkdocs pip install mkdocs==1.6.1
pip install mkdocs-material pip install mkdocs-material==9.7.7
pip install fontawesome_markdown pip install fontawesome_markdown==0.2.6
pip install mkdocs-redirects pip install mkdocs-redirects==1.2.3
mkdocs build --clean mkdocs build --clean
mkdir site/slides mkdir site/slides
npx @marp-team/marp-cli slides/innovation/innovation.md -o ./site/slides/innovation/index.html npx @marp-team/marp-cli@4.5.1 slides/innovation/innovation.md -o ./site/slides/innovation/index.html
npx @marp-team/marp-cli slides/if/if.md -o site/if.pdf --allow-local-files --html=true npx @marp-team/marp-cli@4.5.1 slides/if/if.md -o site/if.pdf --allow-local-files --html=true
- name: Deploy docs - name: Deploy docs
run: surfer put --token ${{ secrets.SURFERKEY }} --server docs.datacontroller.io site/* / run: surfer put --token ${{ secrets.SURFERKEY }} --server docs.datacontroller.io site/* /
+11
View File
@@ -0,0 +1,11 @@
# npm configuration for this repo's CI and local installs.
#
# ignore-scripts keeps package install scripts (an arbitrary-code execution
# point) from running during the deploy workflow. Both npm packages the
# workflow installs - cloudron-surfer and @marp-team/marp-cli - ship no
# install, preinstall or postinstall hook, so nothing is skipped.
#
# save-exact pins anything installed from here to an exact version rather than
# a caret range.
ignore-scripts=true
save-exact=true
@@ -102,9 +102,9 @@ From that moment the changeset is an approval against `ORDERS.ORDERS`. The appro
![A change submitted against the mirror, raised against the real table](/img/approval-routed.png) ![A change submitted against the mirror, raised against the real table](/img/approval-routed.png)
### The detail that will bite you ### Reassigning LIBREF and DS
Use `call symputx`, not `%let`. `LIBREF` and `DS` are not declared `%local` in `mpe_loader`, and the hook is included into that scope - so `call symputx` finds the existing variable and updates it, while a `%let` creates a new variable in the hook's own scope and is silently discarded. The hook runs, the log looks clean, and the changeset goes to the mirror anyway. `LIBREF` and `DS` are ordinary macro variables inside `mpe_loader`, which creates them with `%let` and then updates them from the staged row. A `%let libref=ORDERS;` reassigns them just as well as the `call symputx` above: both statements assign to the *existing* variable, because it lives in an enclosing symbol table (`mpe_loader`'s local table) and SAS only creates a new local when the name is absent from every enclosing table. `call symputx` is used above because it is explicit about which variable is being set, and because it does not depend on the enclosing scope still holding the name - a wrapper macro that declared `%local libref` would turn a bare `%let` into an assignment to that shadow instead.
### Other things to watch ### Other things to watch