8646381044f1cd68c68eec079c24a5c7945eb13d
1831
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8646381044 |
Merge pull request 'fix(mocks): restore the sas9 separators and convert the sasjs lineage capture' (#479) from fix/463-sas9-getdata-separators into release/7.23
Reviewed-on: #479 |
||
|
|
caa58771bf |
fix(mocks): emit the sasjs lineage capture through webout()
The capture assigned its body to _webout in one template literal, and that literal was not JSON: raw line breaks inside the graphviz label and an unescaped quote in labelloc = "t". fromsas, clickableids, info and flatdata are members now, written as string literals that keep the label's quotes and line breaks, with the envelope supplied by the runtime. sas/mocks/test/sasjs-webout.test.js holds the six services that set their own content headers, and pins this capture's members. CONTRIBUTING.md lists the same six. |
||
|
|
67631133f9 |
test(mocks): pin the missing-separator branches and check a delimited drive
Each fault shape the tree repairs now has a case that builds it - drive, OMSOBJ, BUILTIN and DOMAIN - so a heuristic that stops detecting one fails the suite instead of leaving only the exact-value assertion behind. A drive letter is path-initial when nothing word-like precedes it, so a path after <, >, =, [ or a comma is checked too; prose that puts a word before a colon still is not a drive. |
||
|
|
f1ba6362cc |
test(mocks): build the UNC cases from the code point
The two cases added for a path after a tag and after a comma were written as single backslashes in the source, so each one evaluated to a value with no separator at all and pinned nothing. The value is now assembled from String.fromCharCode, with an assertion that it starts with the two separators the case needs. |
||
|
|
755083bb49 |
test(mocks): fail a service that emits no member, and drop the history from the header
A service whose payload does not arrive as (kind, name, rows) contributed no members and passed the tree-wide test with nothing checked; the loop now records the file with no members captured. The header describes what the values and the test do. The ticket numbers it carried are gone: AGENTS.md allows a tracker reference only as a link, and the behaviour reads without one. |
||
|
|
0e74ab58a1 |
test(mocks): pin the tree's scope and name the service that cannot run
A file that does not emit through webout() and is not a listed helper fails a scope test, so a renamed emitter shrinks the run set loudly instead of leaving the replay over an empty set. Every webout kind is captured, a service that needs a global the sandbox lacks names itself in the error, and the header states the scope the scan covers. |
||
|
|
c9119101a4 |
test(mocks): describe the separator rule as it applies to the webout() tree
The header described the captures as live template literals, which this tree no longer carries; the values now travel through webout() and the same backslash is one escape away from the same damage. |
||
|
|
676cdf6fdd |
test(mocks): run only the services that emit, and widen the UNC exception
The replay covers the files that call webout(), so a shared module added to the tree is skipped instead of failing with a require error, while the _webout assertion still reads every file - a service that writes its own body cannot slip past the filter. A UNC prefix is legal after any character that is not a word character, a colon or another separator, so a path inside a tag or after a comma keeps its prefix instead of reading as a doubled separator. |
||
|
|
88cc68e2f9 |
test(mocks): anchor the doubled-separator rule and resolve sibling requires
The whole-tree check treated any two consecutive backslashes as a fault, so a UNC library path (\\server\share\...) failed on a correct value. A run of two is now legal only where a UNC path puts it - the start of a value or of a quoted path - and two separators anywhere else, plus any run of three, are still a fault. faultsIn gains a case for each direction. The sandbox require delegated relative requests to this test file's own require, so a service requiring a sibling module resolved it under sas/mocks/test. A relative request now resolves from the service file; builtins and absolute paths delegate unchanged. |
||
|
|
bafbe201ce |
fix(mocks): restore the two separators the sas9 getdata recording lost
getdata's ENGINEHOST metadata rows carried a Windows path and an account name with no separators, which SAS writes and the rest of this tree already has: the rows read C:DataControllerDC996664mpe_x_test.sas7bdat and BUILTINAdministrators, against refreshlibinfo's C:\DataController\ DC996664 library and BUILTIN\Administrators owner in the same recording. Both values now carry single separators. sas/mocks/test/sas9-separators.test.js replays all 36 files of the tree under a webout() stub and fails on a doubled separator, or a missing one in an OMSOBJ URI, a drive path or a BUILTIN/DOMAIN account. It also pins the two corrected rows and asserts that no service assigns _webout. |
||
|
|
109711b9a0 |
fix(viewer): key the export menu so Handsontable keeps it
Sites / deploy (push) Successful in 3m19s
The CSV / Excel / PDF export submenu never reached the screen. HOT's
ExportFile plugin contributes a context-menu entry under the reserved key
`export_file`, and ContextMenu's ItemsFactory.setPredefinedItems folds the
plugin's entry over the grid's entry at the same key. That folded entry
carries `hidden() { return this.getSettings().exportFile === undefined }`,
and no grid in this app sets `exportFile`, so the whole item - submenu and
all - was filtered out of the menu. Seen on the 7.22.0 build: the viewer's
context menu offers Copy with header, Copy header only and Show labels, and
nothing else, so the client-side PDF export could not be reached at all.
Give the item a key of the app's own, EXPORT_MENU_KEY, and use it at the
three grids that build the menu (viewer, editor, viewboxes). The submenu
keys move with it.
export-menu.spec.ts pins both halves against a real grid, because the
merge happens inside the plugin at menu-build time and no unit test of the
item object can see it: configured under `export_file` the item is absent,
configured under EXPORT_MENU_KEY it is present.
|
||
|
|
6bf7f9ba0d |
ci(docs): give the SAS docs deploy the Cloudron password that exists
Sites / deploy (push) Successful in 3m19s
The 7.22 release's sas-docs job failed with surfer's "Run surfer config first, or provide --server ... --password" message, and its log shows SURFER_PASSWORD empty - the CODE_DATACONTROLLER_IO secret resolves to nothing. Authenticate with WEBDOC_DATACONTROLLER_IO, the password the typedoc job in this same workflow already uses: a Cloudron app password belongs to the user, and the same user owns both docs apps, so one credential covers both. |
||
|
|
205adf0a2b |
ci: put the remaining workflows on the node version the build uses
build.yaml, lighthouse.yaml and sites.yaml were moved to Node 24.15.0 on
2026-10-28 (
|
||
|
|
f3d1eb11d1 |
ci(release): attach cypress evidence only on failure
Sites / deploy (push) Successful in 3m17s
The release workflow recorded video for every spec and uploaded cypress-videos.zip on every run, green or red. Recording eleven specs costs encode time each run and the recording is only ever opened after a failure, so run with video=false,screenshotOnRunFailure=true - the same pair build.yaml already passes - and zip screenshots plus videos only under if: failure(). |
||
|
|
e07246ac68 |
chore(release): 7.22.0 [skip ci]
# [7.22.0](https://git.datacontroller.io/dc/dc/compare/v7.21.0...v7.22.0) (2026-11-05) ### Bug Fixes * **browse:** accept legal folder names, cap the walk, and lock the read ([v7.22.0 |
||
|
|
39e8ffdbdd |
Merge pull request 'feat: Release/7.22' (#407) from release/7.22 into main
Reviewed-on: #407 |
||
|
|
6f7f2d189f |
Merge pull request 'fix(deploy): drop the browse gate, and ask for the admin group before the directory' (#478) from fix/7.22-browse-window-and-order into release/7.22
Reviewed-on: #478 |
||
|
|
5c646913e4 |
fix(deploy): ask for the admin group before the staging directory on SASjs
The SASjs Server / SAS9 screen put the DC Staging Directory first and the admin group second, the reverse of the Viya screen, so the operator was asked to pick a location before being told who administers DC. It now asks for the admin group first and the directory last, with the copy reordered to match. A rendered-order spec covers it: it reads the labels off the rendered template and fails if the directory comes first again. |
||
|
|
912fae448b |
fix(makedata): let the browse actions live as long as the service does
DIRLIST and WRITECHECK were refused once the appLoc had a settings.sas, on the argument that a failed run could leave that file behind. That is what makes the gate wrong: a failed run is exactly when the deploy screen still needs to list and probe directories, and any appLoc configured earlier refuses them for good. The window needs no separate clock - a successful run deletes this program, so once DC is configured there is nothing left here to call. Removed from both variants (server checks the drive over HTTP, Viya checks the filesystem; neither is needed), and the two tests that asserted the refusal go with it. The macros themselves are covered by mpe_dirlist.test.sas and mpe_writecheck.test.sas. Seen on sas.4gl.io: a deployment to /Public/app/dc477 answered BROWSE with "DIRLIST and WRITECHECK are only available until DC is configured". |
||
|
|
eef91ce989 |
Merge pull request 'fix(7.22): clear the makedata poll on destroy, and close the release-gate findings' (#477) from fix/7.22-release-followups into release/7.22
Reviewed-on: #477 |
||
|
|
c808c41333 |
fix(deploy): stop the makedata poll outliving its screen, and align the release gates
The release pipeline went red at
|
||
|
|
ed678f0b46 |
fix(test): let the dirlist and writecheck results reach the caller on Viya
Both test programs pointed _webout at a temporary file so the macros under test could write their JSON answer, then tried to hand the fileref back with `filename _webout "&_webout_path" mod;`. On Viya's JES _webout is a filesrvc fileref, whose pathname() is empty, so that statement fails with "Invalid physical name" and the temporary file stays in place. The term program's %webout(OPEN) assigns _webout itself (filesrvc on JES, temp elsewhere), so the restore is not needed at all; the two programs now leave the fileref to it. Observed on the nextviya estate: the suite reports 64/64 of the tests that produced results, with mpe_dirlist and mpe_writecheck absent from the results JSON and "Invalid physical name" in their logs. |
||
|
|
28157faeca |
Merge pull request 'fix(deploy): unclamp the folder picker row and probe in the chosen context' (#476) from fix/deploy-folder-overlay into release/7.22
Reviewed-on: #476 |
||
|
|
e8cdc37a05 |
test(deploy): match the picker's requests with regexps, and sign in on a secured estate
The spec failed on CI: the browse button never appeared. Two causes, both
found by reproducing the CI estate locally (seeded drive):
- The intercept pattern '**/drive/folder**' does not match the request the
app makes ('/SASjsApi/drive/folder?_folderPath=...') in this Cypress
version, so the app saw the real drive, loaded the startup service and
never routed to the deploy screen. Both intercepts are now regexps, which
match deterministically. Verified on the seeded estate: the app routes to
#/deploy and the agreement card renders.
- A secured estate shows a login form first. The boot helper now waits for
one of the states it can act on (a visible login form, the agreement card,
or the deploy screen), signs in when the form is visible, then waits for
the deploy screen. The login form stays in the DOM hidden on other routes,
so visibility - not presence - decides.
|
||
|
|
677b03eddf |
test(deploy): bind the picker in the Viya order spec, and drop fixed waits
Review findings on #476. - The 'hands the picker the context' test declared only AutomaticComponent and HostComponent with NO_ERRORS_SCHEMA, so app-dc-location stayed an unknown element: the [computeContextName] binding was never applied and the assertion just repeated the fallback case. DcLocationComponent is now declared (SasService is already stubbed), and the test asserts the picker's own input - both before a selection (the configured fallback) and after one is chosen. Verified it bites: removing the binding from the template fails it. - The Cypress spec set the path nowhere before clicking Validate, so the assertion leaned on the field arriving pre-filled; a blank field would short-circuit with 'Type or pick a folder first' and fail for a reason unrelated to the layout. It now types the path explicitly. - The spec slept a fixed 4s after accepting the agreement, which turns a loaded CI runner into an intermittent failure. Both tests now share one boot helper whose readiness gate is the Browse button appearing. |
||
|
|
133092502c |
fix(deploy): unclamp the folder picker row and probe in the chosen context
Two defects on the deploy screens, found on staging. 1. The folder picker's outer row reused Clarity's 'clr-input-wrapper' class, whose 'max-height: var(--clr-forms-input-wrapper-height)' clamps the row to the input's height. The row is flex-wrap: wrap, so once the Browse/Validate buttons wrapped (or the row was simply taller than one input) they overflowed the clamp, and the folder browser panel - positioned after the collapsed box - rendered on top of the input, the buttons and the surrounding text. Measured on staging: panel top 256 against input 248-272 and buttons 280-304; with the class dropped the row contains all its children and the panel starts at 312. 2. The Viya screen asked for the DC directory before the compute context, but the folder listing and the write check run inside the chosen context, as its batch identity - so the probes could inspect a file system the deployment itself would not use. The fields are reordered (admin group, then batch id / compute context, then DC Loc last) and the picker now runs DIRLIST and WRITECHECK with the selected context in the adapter request config, which every Viya executor path honours. The SAS 9 / SASjs screens pass no context and behave exactly as before. Tests: a Cypress spec drives the real deploy screen estate - the picker row must contain its own children and the panel must start below them; both tests fail with the clamp reintroduced. A rendered TestBed spec pins the Viya field order (admin group < compute context < DC Loc) and fails with the old order. Unit specs pin the probe config: no context on SAS 9 / SASjs, the chosen context on Viya. |
||
|
|
1ea1965721 |
Merge pull request 'feat(mocks): restore a load, and record the diffs it needs' (#474) from feat/mocks-restore into release/7.22
Reviewed-on: #474 |
||
|
|
3573ce260f |
Merge pull request 'feat(mocks): add the control-table services the screens call' (#473) from feat/mocks-control-table-services into release/7.22
Reviewed-on: #473 |
||
|
|
1a9f59478b |
fix(mocks): resolve the audit table once, record lower-case md5, and report a failed audit write
Three review findings. - KEY_HASH was upper-cased after the digest. SAS md5() writes lower-case hex, so the mock's key hash did not match what a real audit table holds. The digest is stored as it comes out, and the test asserts lower case. - restore resolved MPE_TABLES.AUDIT_LIBDS per table, while the approval always appended to the control library's MPE_AUDIT: a table with its own audit table had its diffs written where restore never looked, and restore then refused with "No entry for <load>", which no later approval could fix. Resolution now lives in dcMockUtils.auditLibdsFor, called by both sides, and the approval reads and saves that table in its own libref. - An audit failure was only logged to the server console, leaving an approval with no diffs and no visible reason. It is still not allowed to undo the approval, but once the control tables are written the failure is raised as an abort that names the table and says the load can no longer be rewound. Two tests: one approves a table whose MPE_TABLES row names a different audit table and asserts the rows land there and not in the control library; one points AUDIT_LIBDS at a libref with no data folder and asserts the approval still lands and the response says the diffs could not be recorded. |
||
|
|
5ecc7bebec |
fix(mocks): fold the audit window, and append MPE_AUDIT under its lock
Two review findings on this branch. - editors/restore.js spread every audit row for the load into Math.min(...). MPE_AUDIT is append-only, so a long-lived estate would eventually exceed the engine's argument limit and the RangeError would surface as a failed restore of a perfectly restorable load. Folded into a reduce with an Infinity seed. - auditors/postdata.js appended to MPE_AUDIT as a read-modify-write outside any lock. postdata.sas locks the table it writes - MPE_REVIEW around its proc append, MPE_SUBMIT around its update - so the audit append now takes the MPE_AUDIT lock around a fresh read, the concat and the save, rather than reading the table up front and saving a copy that may be missing another approval's rows. 53 mock tests pass (node --test sas/mocks/test/). |
||
|
|
1a60c689f4 |
feat(mocks): restore a load, and record the diffs it needs
`editors/restore` had no mock, and the reason it could not have had one is that `postdata` wrote no audit rows: an approval applied the load and left nothing to rewind. Both halves are here. postdata (final approval): writes MPE_AUDIT the way %mp_storediffs does - one row per column, keyed by the md5 of the business-key values joined by '|', with move_type A/D/M, is_pk on the key columns, is_diff on a changed one, and the old and new value on their own typed columns. An append carries every column on the new side, a delete every column on the old side (which is what lets a restore put the row back), and a modification the keys plus only the columns that actually changed. A failure writing the audit is logged and does not undo an approval that has already landed. restore: mpe_checkrestore's two decidable checks (the table has an audit table; the load has entries in it) with their messages, then mp_stripdiffs' window - the load's timestamp and every change to that table from then on, because a restore reverts this load *and all subsequent ones*. Per business key the pre-window state is the earliest event: an append means the row is staged for deletion (`_____DELETE__THIS__RECORD_____=YES`), a delete means it is staged with the values the delete recorded, and a modification means each column takes its earliest old value while untouched columns keep the current one. The result goes through the same stageSubmission the editors use, so it arrives as a new submission with the reason `Restoring <loadref>` and is approved like any other - restore.sas never writes the base table either. The access and group/RLS checks are not emulated, consistent with the rest of the mocks: nothing enforces MPE_SECURITY there. Tests: 52 pass across the seven mock suites, 7 of them new. They drive a real approve and then read the staged rows back: append staged for deletion, modification staged with the pre-load value, delete staged with the row's values, and restoring the first of two loads reverting the second as well. With the base postdata and no restore service, all 7 fail. |
||
|
|
67d9cfd1bd |
fix(mocks): 0 is a closed TX_TO, a libref boundary, and the union of the row keys
Four review findings. - isCurrentOn counted TX_TO 0 as current. 0 is 01JAN1960 in SAS, so a real row with that window has been superseded; only a missing, null or blank TX_TO is open besides 31DEC9999. The fixtures are seeded with 31DEC9999 (253717919999) through an OPEN constant instead, and the 0 clause is gone. - The MPE_DATADICTIONARY filter compared DD_SOURCE against the libref without a boundary, so DC_JSLIB2.TABLE was excluded along with DC_JSLIB.TABLE. It now tests for the libref plus the dot, as the libds rewrite does. - The schema-less export took its column list from Object.keys(rows[0]), so a column that first appears in a later row was silently missing from the backup. The list is the union of the keys across the exported rows, in first-seen order. - control-tables.test.js imported readTable and never used it. |
||
|
|
e53c50d4e2 |
fix(mocks): one sasDatetimeNow, a documented TX_TO=0, and a shaped fallback export
Three review findings on this branch. - dcMockUtils defined sasDatetimeNow twice: once beside isCurrentRow with the epoch written inline and once in the mp_lockanytable section using SAS_EPOCH_MS. The second is the one the file already had; the duplicate is gone, so the epoch has one expression. - isCurrentRow treated TX_TO=0 as current without saying why, and reached that through Number(null) === 0. Both conventions are real: makedata writes 31DEC9999 for a row that was never superseded, and the fixtures in control-tables.test.js use 0 for the same thing. The clause stays and the comment now says which convention is which, plus that a missing, null or blank TX_TO (a table with no version column) is current too. Reading the column moved into isCurrentOn, because Array.filter passes the index as a second argument and would have handed a `column` parameter the row number. - admin/exportconfig used the schema only when it existed: with no columns in the table file it fell back to Object.keys(rows[0]), which exported the TX_/VER_/SELECTBOX_RK columns the spec drops and quoted every number. The fallback now applies the same drop prefixes and infers numeric typing from the rows, so a schema-less estate produces the same shape as a seeded one. A test writes a table file with rows and no columns and asserts both. All 46 mock tests pass (node --test sas/mocks/test/). |
||
|
|
5bf836e206 |
Merge pull request 'ci(build): restore the Angular cache after postinstall, where it survives' (#475) from ci/angular-cache-after-install into release/7.22
Reviewed-on: #475 |
||
|
|
00d37577f7 |
ci(build): restore the Angular cache after postinstall, where it survives
postinstall runs scripts/strip-clr-base64-fonts.mjs, which edits Clarity's CSS
inside node_modules and then deletes client/.angular/cache - because the
builder treats node_modules as immutable and would otherwise serve styles built
from the unstripped file. Measured on the Angular 20 builder: a marker
@font-face injected into clr-ui.min.css was absent from a warm build's CSS
(28s) and present in a cold one (88s).
The restore used to run before the install, so that clear deleted the entry
before anything could use it - run
|
||
|
|
1e2a6bb168 |
Merge pull request 'ci(build): cache the client npm downloads, and keep Angular's disk cache in CI' (#472) from ci/cache-client-builds into release/7.22
Reviewed-on: #472 |
||
|
|
a1615ee8a7 |
feat(mocks): add the control-table services the screens call
Three services the Angular app calls had no mock at all, so on the mock estate the Excel-map screen, the system screen's refresh and the config export either failed or showed nothing: - editors/getxlmaps - the rules and info of one map. Reads MPE_XLMAP_RULES and MPE_XLMAP_INFO for the current rows of that XLMAP_ID, orders by sheet and range id, and coalesces the target to DC_JSLIB.MPE_XLMAP_DATA - the same five columns, order and fallback getxlmaps.sas uses. - admin/refreshcatalog - a libref is optional and must be well formed (Invalid libref otherwise), and the reply is sasparams with the completion message the screen displays. A mock estate has no catalogue to rewrite, which the service says rather than pretending. - admin/exportconfig - a member per non-empty table, named <libref>.<TABLE>.csv, with the per-table treatment exportconfig.sas applies: TX_* dropped, a version filter, the `where also` exclusions, and the control-library name rewritten to the target libref (including the DC_MACROS value and the LIBREF.TABLE of a map target). Zipped as DCBACKUP.zip. The version test and the control-table reader were local to startupservice; they now live in dcMockUtils (isCurrentRow, sasDatetimeNow, and makeControlTableLoader for controlTable), so the rule that decides a row is current exists once. The harness gains the session's stpsrv_header.txt and _SASJS_USERNAME, so a service that streams a file can be exercised: exportconfig is asserted both ways - the zip where the runtime has Buffer, the content listing where it does not. Tests: 45 pass across the six mock suites, 8 of them new. With the three services removed, all 8 new cases fail. |
||
|
|
ce8c41c5db |
ci(build): drop the Angular cache step, which bought nothing across runs
Run
|
||
|
|
c732d7593c |
ci(build): restore the caches after the secret scan
The gitleaks step scans the working tree with --no-git, and the Angular cache
holds webpack/babel JSON full of `{ token: ... }` fragments. Restoring it
before the scan put those files in the tree and the gate failed on run 3174
with a wall of generic-api-key findings in
client/.angular/cache/20.3.41/babel-webpack/*.json.
Both cache steps now run immediately after the scan. The npm download cache
only helps the client's npm ci, which is after that point anyway; the Angular
cache only helps the tests and the build, which are later still.
|
||
|
|
f88e053887 |
ci(build): state the cache invariant in the step comments, not one run's numbers
The comments cited run 3170 and a timing measured on one 4 vCPU box. Both go stale and read as a guarantee about a particular runner. They now state the invariant the workflow relies on: an unreachable cache server degrades restore and save to a warning, so the job stays green. The timing figures stay in the PR description, where they are evidence for this change rather than a promise the workflow makes. |
||
|
|
768755dd37 |
ci(build): namespace the cache keys by base branch
act_runner's cache handler scopes entries to the repository (each entry is stamped with its repo and checked on read), not to a ref, so a pull request into one branch could seed the entry another branch's build restores. The base branch is now part of both keys and both restore-key prefixes. A save against an unreachable cache server is already a warning, not a failure: run 3170 landed on runner4.4gl.io and logged four '::warning::Failed to save: reserveCache failed: Request timeout' lines with the job completing green. |
||
|
|
5f8f668c66 |
ci(build): keep Angular's disk cache in CI so the cache step has something to save
The first run of these cache steps showed the npm entry saving (234 MB) and the Angular one reporting 'Path Validation Error: Path(s) specified in the action for caching do(es) not exist'. Angular keeps its persistent cache in memory when CI is set, so no .angular/cache directory existed to upload; the disk cache is only used outside CI by default. client/angular.json now sets cli.cache.environment to "all", which is the supported switch for that. Verified locally with CI=true: after removing .angular/cache, a build recreates it (396 MB). |
||
|
|
9d30e1855f |
ci(build): restore the npm downloads and the Angular build cache
The runner's cache server is reachable from job containers on two of the three boxes now, so these are the first cache entries in this repo that can actually come back. Probe evidence, four dispatches of a throwaway two-job workflow: - save on runner.4gl.io, restore on runner2.4gl.io: miss (each act_runner runs its own cache server, so entries belong to the box that saved them) - save and restore on runner2.4gl.io: cache-hit=true, the stamp came back - save on runner4.4gl.io: "Failed to save: reserveCache failed: Request timeout" - that box still runs the old runner config Two caches, both keyed on client/package-lock.json so a dependency change invalidates them, with prefix restore-keys so the previous entry still lands: - ~/.npm, for the client's npm ci (81s cold, measured on run 3132) - client/.angular/cache, for the production build (109s cold, 118s -> 33s with a warm cache on a 4 vCPU box) and the two Karma runs, which share it Per run the arithmetic while runner4 is still on the old config is about 1/3 x (+80s: two restores and two saves timing out at 20s each) plus 2/3 x (-100s), so it is a net improvement already and a clear one once the third box is deployed. On an old box both steps only warn and the job stays green. actions/cache does not save a second entry for an existing key, so the Angular cache refreshes when the lockfile changes; the v1- prefix is there to force a reset by hand if the win decays. |
||
|
|
40624c0a4c |
Merge pull request 'fix(deploy): make the folder picker work on both estates' (#471) from fix/deploy-picker into release/7.22
Reviewed-on: #471 |
||
|
|
5f338ff437 |
fix(deploy): match the documented SYSSCPL set and stop guessing at the cap
Review findings on #471. The platform rule now checks the documented tokens exactly (['WIN', 'DNTHOST']) instead of their first letters, so an unlisted token beginning with W or D no longer silently gets the drive path back. brDirList raised TRUNCATED whenever it saw rows.length >= maxobs, which included the check made after the last permitted row was added: a listing of exactly maxobs folders with a file sorting after them reported itself truncated although nothing was refused. The flag is now set only where a row is actually refused, and the early exit remains the walk bound. Two new cases pin the shape the picker depends on: a listing of exactly MAXOBS entries is TRUNCATED='N', and a DEPTH=2 browse numbers children at 1 and grandchildren at 2 with no LEVEL 0 row. Both, plus the existing parent-level and write-probe cases, fail against release/7.22's service. Tests: 37 pass across the five mock suites, client spec 9/9. |
||
|
|
f0769b46aa |
Merge pull request 'ci(build): skip the cold build when the Cypress job will not run' (#470) from ci/faster-build-job into release/7.22
Reviewed-on: #470 |
||
|
|
ecc87021c3 |
fix(build): publish the changed-path decision and pin the matcher with tests
Two review findings on the first two commits. The two jobs no longer decide separately. Build-and-ng-test now publishes `client` as a job output and Build-and-test-development consumes it instead of re-diffing the base branch: a base commit landing between the two decisions could make the Cypress job expect an artifact the build job had already skipped, and the failure would read as a missing artifact. An empty output (the build job could not decide) still runs everything. The path list is now a PATHS variable the script can be asked about directly (`--match` with a file list on stdin), and tests/cypress-changes.test.sh pins one case per alternative plus the negatives (a sas/ service, docs, the Lighthouse workflow, a "clientx/" directory, the sas lockfile). The build job runs the test, so dropping an alternative is red rather than a suite that silently stops covering a class of change. Checked the test fails when the pattern is mutated. |
||
|
|
48df795202 |
fix(build): treat a sas/package.json bump as a Cypress input
The Cypress job installs the CLI from the version sas/package.json pins (`CLI_VERSION=$(node -p "...dependencies['@sasjs/cli']")` in "Deploy mocked services"), so bumping that pin changes what the suite runs without touching anything under sas/mocks/. A pull request that only bumped it would have been skipped by both jobs. The sas lockfile stays out of the set: the job installs that CLI globally by version string, so the lockfile cannot change what it resolves. |
||
|
|
fb38309e98 |
fix(deploy): make the folder picker work on both estates
Three defects behind staging's "Invalid parent" and the picker that could not list a subfolder. Found by running the real mpe_dirlist on sas.4gl.io, not by reading it. 1. The browser host answers SYSSCPL "browser". The client looked for the first letter of a unix token (L/H/A/S) and fell through to the Windows default for anything else, so the deploy screen pre-filled C:\DataController on a POSIX runtime, which the server then refused as an invalid parent. Windows is now recognised by its own tokens (WIN, DNTHOST); anything else, including a value the list has never seen, gets the POSIX path. 2. mpe_dirlist emitted a non-blank parent's children at LEVEL 0, because mp_dirlist numbers a folder's contents with the folder's own level. The picker keeps LEVEL>0 for a non-root listing, so every row was discarded and a subfolder could never be browsed. The children are shifted to start at 1; a blank parent still lists the platform roots at 0. Verified on the estate: /tmp at DEPTH=1 returns levels [1], a blank parent returns [0, 1] (the root, then its children). 3. The mock's write probe generated one name and wrote it, truncating a file that was already called that; mpe_writecheck tries up to ten names with fileexist()=0 first. The mock now does the same and reports 'No free name for the write probe' when all ten are taken. The mock's DIRLIST now matches the estate's shape too: children at LEVEL 1, roots at 0 followed by their children, and the cap stops the walk at MAXOBS rather than slicing afterwards. Tests: 35 pass across the five mock suites (makedata-actions 15, two of them new: the probe collision and a folder that cannot be written to), sasjs lint clean, client spec 8/8 with the new platform cases and 2 failing without the fix. |
||
|
|
6830d873e5 |
ci(build): skip the cold build when the Cypress job will not run, and stop installing Cypress in the lint job
The build job spent 402s on every pull request (run 3132, release/7.22). Two of its steps were work nobody consumed: - `npx cypress install` (11s, measured 17:07:05-17:07:16) downloaded and unzipped the Cypress binary into a job that only runs Karma, eslint, the licence checker, the mock service tests and `ng build`. Cypress runs in Build-and-test-development, which installs its own binary. - The production build (109s) and the client-dist upload exist only to feed the Cypress job, which already skips pull requests that touch nothing it exercises. On those pull requests the artifact was uploaded and never downloaded. The changed-path decision now lives in .gitea/scripts/cypress-changes.sh and both jobs call it, so the build job's gate cannot drift from the Cypress job's skip. The script keeps the existing fail-open rule: anything it cannot decide (no base ref, failed fetch, failed diff) writes no output, and every caller gates on `!= 'false'`, so the work still runs. |