Skip to content

cli/cmd: manifest-aware tt run and tt test - #1378

Draft
bigbes wants to merge 10 commits into
v3from
bigbes/tntp-9957-run-test
Draft

bigbes wants to merge 10 commits into
v3from
bigbes/tntp-9957-run-test

Conversation

@bigbes

@bigbes bigbes commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

tt run and tt test are the two workflow shortcuts over a manifest package.

tt run [ARGS...]

Replaces the environment-driven command. The working directory must hold
app.manifest.toml and nothing else is required — no tt.yaml, no tt
environment, and none is looked for. The interpreter is the one the package
bundles under _runtime/ when it has one and the host's tarantool otherwise;
TT_USE_SYSTEM_TARANTOOL=1 forces the host's either way. Arguments reach
Tarantool untouched, -- included, and tt replaces itself with the interpreter,
so signals and the exit code are Tarantool's own.

The project root is the working directory and is never searched for upwards, so
which package runs is exactly the directory the shell is in.

tt test [SUB-PATH] [-- LUATEST-ARGS...]

Builds the package, makes sure a runner is in .rocks/, then execs luatest under
the same interpreter tt run would choose. Tests come from test/, or tests/
when there is no test/; a sub-path narrows the run to one directory or one file
and must exist, so a typo is an error rather than a run of nothing the runner
would report as a pass. Everything after -- is luatest's, and so is the exit
code.

luatest need not be declared. When [dev_dependencies] does not name it and the
tree does not already hold it, build.EnsureDevRocks resolves it as an implicit
* requirement on top of the declared dev set, pinned to the lock's own picks,
and installs what is missing. app.manifest.toml and app.manifest.lock are
left byte-identical: writing either would change the manifest hash and leave the
next --locked build refusing a lock the test run made stale.

Shape

  • cli/manifest/run — project root, interpreter selection, exec, test-directory
    choice, luatest script lookup. Stdlib only, unit-tested on fixtures, and added
    to the strict .golangci.yml path list.
  • resolve.Engine.ResolveDevExtra — the dev closure widened by requirements the
    manifest does not declare, returned rather than written. A declared name wins
    over the caller's, so an implicit * never widens a constraint the author
    wrote.
  • build.EnsureDevRocks — resolves that closure and installs what the tree does
    not already hold at the resolved version, so a second run fetches nothing.
  • cli/running: running.Run, RunInfo, RunOpts and Instance.Run are gone.
    They served the old tt run and had no other caller.

Notes for review

  • tt test builds with the tt environment's Tarantool (tarantoolInfo(), needed
    for rockspec evaluation and cc flags) while running under the selected one.
    They differ only for a project that carries a bundled _runtime/, which is an
    installed package rather than a developer checkout; such a project with no host
    tarantool at all cannot currently tt test, though it can tt run.
  • luatest is fed to the interpreter from its per-rock copy under
    share/tarantool/rocks/luatest/<version>/bin/luatest rather than from
    .rocks/bin/luatest, because LuaRocks may deploy a console script as a
    /bin/sh launcher with an interpreter path baked in at install time — which
    would ignore the selection.
  • A directory reaches luatest with a trailing separator; without one luatest
    reads the argument as a test group name and refuses it as invalid.
  • Two integration cases reach a registry and are marked slow. The rest install
    a fake luatest into the project tree, which is what lets the whole
    build-and-exec path run offline.

Part of TNTP-9957

Add cli/manifest/run: the project-root check, the interpreter
selection a workflow command makes before handing over, and the
exec that replaces the tt process with it.

The bundled runtime under _runtime/ wins over the host's
interpreter, since a with-deps package was installed precisely to
carry its own; TT_USE_SYSTEM_TARANTOOL inverts that. Locating
luatest's entry script lives here too, because tt test needs the
same selection plus a script to feed it.

The package is added to the strict .golangci.yml path list.

Part of TNTP-9957
Replace the environment-driven tt run with the manifest-aware one.
The command now needs only app.manifest.toml in the working
directory: no tt.yaml, no instances_enabled, no tt environment at
all. Arguments still reach Tarantool untouched, and tt still
replaces itself with the interpreter, so this is a change of which
binary is chosen and what has to exist first, not of how the
process behaves once it starts.

Correct the argument example while rewriting the help: Tarantool
hands '--' to the script along with everything else after the
script name.

Part of TNTP-9957
Add Engine.ResolveDevExtra: the dev closure of a manifest widened
by requirements the caller supplies, resolved against the versions
a lock already chose and returned rather than written.

A command may need a rock the project never declared - a test
runner, above all - and such a requirement is not a statement the
author made about the package. Writing it into app.manifest.toml
or app.manifest.lock would change the manifest hash and make the
lock stale, so the closure is handed back for the caller to
materialize and both files stay byte-identical.

A name the manifest already declares wins over the caller's, so an
implicit '*' never widens a constraint the author wrote.

Part of TNTP-9957
Add EnsureDevRocks: resolve dev requirements the manifest does not
declare on top of the ones it does, pinned to the lock's own
picks, and install what the tree is missing.

The lock is read and never written, so a project whose tests need
a runner it never declared gets that runner in .rocks/ without its
manifest hash moving and without the next --locked build refusing
a lock the test run made stale.

Rocks the tree already holds at the resolved version are skipped:
this closure is resolved on every call, unlike the lock's, which a
build materializes once per lock change.

Part of TNTP-9957
Add tt test: build the package, make sure a runner is in .rocks/,
then exec luatest under the same Tarantool tt run would choose.

Tests come from test/, or tests/ when there is no test/; one
sub-path narrows the run and must exist, so a typo is an error
rather than a run of nothing the runner would report as a pass.
Everything after '--' is luatest's, and so is the exit code.

luatest need not be declared. When [dev_dependencies] does not
name it and the tree does not already hold it, it is resolved as
an implicit '*' requirement and installed; the manifest and the
lock are left byte-identical, so a test run never makes the lock
stale.

A directory is handed to luatest with a trailing separator: it
reads a bare name as a test group and refuses it as invalid.

Part of TNTP-9957
Rewrite the tt run suite for the manifest-aware command and add
one for tt test beside it: both stand on the same project fixture,
the same fake bundled interpreter and the same fake runner, so the
shared machinery is exercised once.

The cases that only described the old environment-driven command
are gone, and the test_app/ scripts with them.

Only two cases reach a registry, and both are marked slow. The
rest install a fake luatest into the project tree, which is what
lets tt test run its whole build-and-exec path offline: with a
runner already there, nothing is resolved or fetched.

Part of TNTP-9957
running.Run, RunInfo, RunOpts and Instance.Run existed only to
serve the environment-driven tt run and now have no caller: the
command selects its own interpreter and execs it. Keeping the
interface method would advertise a capability nothing reaches.

Also correct the tt install tarantool-dev example, which pointed
at tt run to show the binary it had just installed.

Part of TNTP-9957
Record the new tt test command and the change of what tt run
means: the package in the working directory rather than an
instance of a tt environment, with no tt.yaml involved.

Use an already-known rock name in the dev-resolution test so the
spell checker needs no new vocabulary.

Part of TNTP-9957
tt run no longer reads the tt environment config, so the case
asserting it refuses without one described the command it
replaced. Say in the test what the remaining cases have in common,
so the next command added is filed by the same rule.

Part of TNTP-9957
The lock-identity case runs with a runner already in the tree, so
it never reaches the implicit resolution and would stay green over
a version that wrote that requirement into the lock. Point at the
two cases that do reach it, so the next reader does not take this
one for more than it is.

Part of TNTP-9957
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant