Skip to content

Sync ako/mxcli: 12 fixes (check refuses like/between/in, demo user in place, dateFormat spelling, mxcli test fresh DB); CI quick-checks first - #1722

Merged
ako merged 46 commits into
mendixlabs:mainfrom
ako:main
Nov 2, 2026

Conversation

@ako

@ako ako commented Nov 2, 2026

Copy link
Copy Markdown
Collaborator

Syncs ako/mxcli:main into upstream: 17 commits on top of v0.30.0, 12 upstream issues fixed, plus a CI reordering. Two of the commits are a deliberate control pair (an unformatted file added, then reverted) and cancel out.

check: refuse what the build rejects

Writes that lost or mangled data

describe

diff-local

mxcli test

CI: no-compile checks first

A new quick-checks job runs fmt-check, check-findings, check-wiki-pages, check-skill-index and check-test-timeouts on a bare checkout (about a second each), and every other job needs it. Before, an unformatted Go file failed Lint Go ~24 minutes into build-and-test while every integration leg ran regardless. go vet and check-tunnel-deps need the package graph, so they stay in build-and-test, with vet moved ahead of the tests. integration-passed still fails when quick-checks makes the integration legs skip; the control pair proved it

claude and others added 30 commits November 2, 2026 13:00
An unformatted Go file failed Lint Go ~24 min into build-and-test, while
every integration leg ran regardless: ~100 runner-minutes for a known-red
result, and at the 20-concurrent-job cap it delayed other PRs too.

A quick-checks job now runs fmt-check, check-findings, check-wiki-pages,
check-skill-index and check-test-timeouts on a bare checkout (no parser,
no submodules, no Go cache; each takes about a second, verified on a
fresh worktree, with an unformatted-file control). Every other job needs
it. go vet and check-tunnel-deps load the package graph, so they stay in
build-and-test, with vet moved ahead of Test. integration-passed still
fails when quick-checks makes the integration legs skip.

ci-local follows the same order and set; lint-go is replaced by its two
halves, fmt-check and vet.

Refs #1887

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011oK82simPxcdrRu9PUSPcQ
…guage (#1869)

describableMessage chose the alphabetically first language, so on an
en_US project with de_DE enabled describe printed the German text, and a
drop + create from that output stored it under en_US. It now uses the
rule every other described text follows (#702): the project default,
then en_US, then the first non-empty one. pickTextTranslation is split
into pickTextLanguage so the describer can name the languages it did not
print.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Proves on a live run that quick-checks fails fast and no other job
starts (#1887). Reverted by the next commit.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011oK82simPxcdrRu9PUSPcQ
The control did its job on run 41452346684: quick-checks failed at gofmt
23 s in, every other job was skipped without a runner, and
integration-passed went red (#1887).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011oK82simPxcdrRu9PUSPcQ
fix(describe): print the concurrency error message in the default language (#1869)
ci: run the no-compile checks first and gate every job on them
…te (#1855)

`mxcli test` on an mdl 0 `.test.mdl` printed one MDL-V1-SLASH and one
MDL-DEPR001 per test, about the script the runner generated rather than the
author's file: the per-test generators kept `CREATE OR REPLACE MICROFLOW` and a
`/` after every `END;` under mdl 0, and mdl 0 warns on both. The canonical
spelling is valid under every version, so the generators now always write
`CREATE OR MODIFY` and `END;` alone; only the header follows the suite.

Closes #1855

Co-Authored-By: Claude Opus 5.5 <[email protected]>
)

The endpoint runner injects the endpoint script, which creates the MxTest
module, and then the test-flow script, which began with its own
`CREATE MODULE MxTest;`. exec answered the second create with "Module 'MxTest'
already exists" on every run. Every caller of GenerateTestFlows runs it into a
project that already holds the module (the --local boot after the endpoint
script; --watch and --attach into a project hosting the endpoint), so the
statement is dropped.

Closes #1856

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…1863)

A `/** … */` comment above `alter entity M.E add attribute X: …;` was read
by nothing: the alter visitor only reads a comment written inside the
statement, so exec reported success and the attribute had no
documentation, with only a later check warning MDL089.

The statement's comment now documents the attribute when the alter (or a
bulk `alter entities`) adds exactly one attribute with no comment of its
own. Two adds, or an attribute already documented, keep the comment
detached so check still warns.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
A suite with one test that does not build ended in "Passed: 0, Errors: 1,
Skipped: 108": the build error was on its ERROR row, one line among a hundred
identical "not run" rows. resultsForBuildFailure now marks the result, and
PrintResults repeats each rejected test's errors, with its file, directly above
the summary line.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…#1834)

A serve process that stopped answering ended `mxcli test --local` in "serve
build request ... context deadline exceeded", and the next run passed with
nothing changed. StartLocalApp now restarts the serve process and builds once
more on a timeout (net.Error.Timeout), and only then: a failed build or a
refused connection is returned as it is.

Closes #1834

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…pelling (#1864)

MDL-WIDGET18 accepts a parameter's dateFormat and enumFormat in any case,
but formattingInfoFromParamFormat copied the value verbatim, so
`dateFormat: custom` was stored as "custom" — not a Mendix enum value — and
the runtime showed the default format. The converter now canonicalises
both through pages.CanonicalDateFormat and the new CanonicalEnumFormat,
as the date picker's path already did.

The converter feeds every ClientTemplateParameter FormattingInfo (dynamic
text, Data grid 2 column templates, the ALTER PAGE column path), so all
of them are covered.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…1853)

`mxcli test --local --db-type hsqldb` booted on the file database the previous
run left in deployment/data/database/hsqldb/<app>_test, so data a previous run
committed or seeded stayed, an idempotent init skipped seeding, and tests failed
on stale data. LocalAppOptions gains FreshFileDB, which removes that one
database before the boot; only the test runner sets it, so `run --local
--db-type hsqldb` keeps the developer's data.

Closes #1853

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…1835)

The MDL expression rule is shared with OQL and admits LIKE, NOT LIKE,
BETWEEN, IN and MATCH, but the visitor returned only the left operand for
them: `retrieve … where Name like 'A-%'` was stored as `[Name]`, and check
and exec both passed before the build failed with CE0161. In an expression
`$s like 'A%'` was stored as `$s`.

The visitor now keeps the comparison as written, and check reports MDL091
(already exec-enforced) naming the operator — CE0161 in a retrieve
constraint, CE0117 in an expression — with the XPath/expression spelling
of the same test. IS NULL / IS NOT NULL are reported the same way.

Measured on mxbuild 11.12.2: every OQL form fails; starts-with(),
not(contains()), >= and <=, = or =, = empty, startsWith() and a qualified
enumeration value (the issue's other shape, already written as 'VALUE')
build clean.

Mirror of mendixlabs#1686.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…#1881)

describe page suppressed PopupWidth/PopupHeight at 0, Studio Pro's
auto-size, so a reviewer reading DESCRIBE could not tell an auto-size
pop-up from one whose size was never set (mendixlabs#1713).

On a page whose layout is a ModalPopup layout both are now printed, 0
included; other pages still print only a non-zero size. The layout is
resolved by FormCall.Form's qualified name: Studio Pro pages carry no
FormCall.Layout ID, so keying on it did nothing on a real page.

Verified on the Studio Pro-authored testapp page
Administration.ChangePasswordForm (Atlas_Core.PopupLayout, 0/0), including
describe -> exec -> describe as a fixed point.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…#1867)

`git diff --name-status <ref>` lists tracked files only, so units added
under mprcontents/ without `git add` -- a new module's pages and flows --
were missing from diff-local and its "new" count (mendixlabs#1709).

In single-ref mode diff-local now also asks `git ls-files --others
--exclude-standard` and reports each untracked .mxunit as new. A range
compares two commits and is unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
)

`declare $L String = 'x' + if $c then 'a' else 'b';` passed check and
exec, then mx check failed with CE0117: Mendix's expression grammar takes
an if-expression only where a whole expression goes, MDL's anywhere.

check now reports MDL-IFOPERAND01, exec-enforced, for an IfThenElseExpr
that is the direct operand of a binary operator or a unary minus, in
microflows and nanoflows alike (the shared per-expression hook), and
suggests the parenthesised form.

Measured on mxbuild 11.12.2, one microflow per shape: `+ if`, `and if`,
`= if`, `-if` and the same in a return are CE0117; the parenthesised
form, an if whose else branch takes the `+`, an if as a function or not()
argument and an if as an else branch build clean.

Mirror of mendixlabs#1710.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
create or modify demo user removed an existing user and added it back,
which appended it: it moved to the end of the list and every later user
shifted an index, so `mxcli diff` showed other demo users' names,
passwords and entities changing (mendixlabs#1701).

AddDemoUser already updates a user by name in place, so the remove is
dropped. The test mock of AddDemoUser now honours that contract instead
of always appending.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…atabase

The hsqldb half of #1853 removed the file database before the boot; PostgreSQL's
`<app>_test` database had the same carry-over (a test asserting an empty table
failed on the second run). FreshFileDB becomes FreshDB, and on PostgreSQL it
runs `DROP OWNED BY CURRENT_USER` as the app role inside the scratch database
once it is ensured: the database stays, and the dev loop's database owned by
the same role is out of reach. The test runner sets it for every --local run.

Refs #1853

Co-Authored-By: Claude Opus 5.5 <[email protected]>
fix(check): refuse like/between/in/is null instead of dropping them (#1835)
# Conflicts:
#	CHANGELOG.md
#	mdl/executor/validate_microflow.go
…er-add-attribute-doc

# Conflicts:
#	CHANGELOG.md
…amictext-dateformat-custom

# Conflicts:
#	CHANGELOG.md
…f-local-untracked

# Conflicts:
#	CHANGELOG.md
…up-dimensions-describe

# Conflicts:
#	CHANGELOG.md
…o-user-in-place

# Conflicts:
#	CHANGELOG.md
fix(check): refuse an unparenthesised if-expression as an operand (#1868)
fix(test): no "Module 'MxTest' already exists" on a clean project (#1856)
fix(test): no MDL-V1-SLASH / MDL-DEPR001 per test on a headerless suite (#1855)
fix(test): each --local test run starts on an empty test database (#1853)
ako added 16 commits November 2, 2026 20:00
fix(test): build error above the summary; retry once on a serve timeout (#1834)
fix(describe): print a pop-up page's width and height when they are 0 (#1881)
fix(diff-local): list untracked units as new against the working copy (#1867)
…er-add-attribute-doc

# Conflicts:
#	CHANGELOG.md
…amictext-dateformat-custom

# Conflicts:
#	CHANGELOG.md
…o-user-in-place

# Conflicts:
#	CHANGELOG.md
…er-add-attribute-doc

# Conflicts:
#	CHANGELOG.md
fix(security): modify a demo user in place (#1859)
…er-add-attribute-doc

# Conflicts:
#	CHANGELOG.md
…amictext-dateformat-custom

# Conflicts:
#	CHANGELOG.md
fix(visitor): store a doc comment above alter entity … add attribute (#1863)
…amictext-dateformat-custom

# Conflicts:
#	CHANGELOG.md
fix(pages): store a dynamic-text parameter's dateFormat in Mendix's spelling (#1864)
@ako
ako merged commit 6094f47 into mendixlabs:main Nov 2, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment