A remote cache scope is now the branch, named owner/repo:branch, so a laptop on a branch reads what CI built there. Each task asks the remote one key, and the local cache never splits by scope. --cache-scope is gone and run.affectedBase is now baseBranch.
A remote cache scope is now the branch. A laptop that checks out a
pull request’s branch reads what CI already built for it, and each task
asks the remote one key instead of two.
This release is breaking for anyone who set a cache scope, used
run.affectedBase, or runs a bare --affected on the base branch. Read
the breaking changes first.
A pull request’s cache scope was pr-<n>. A laptop on the same branch
could not name it, so it rebuilt what CI had already built there. A
scoped run also asked the remote two keys per task, main’s and then the
scope’s, and a scope split the local cache too.
Now the scope is <owner>/<repo>:<branch>. On GitHub Actions,
github() from @vzn/vx-ci names it from the event: a pull request
from feat-x is acme/app:feat-x, and a fork’s is eve/app:feat-x. A
checkout with a remote cache derives the same name from .git, with no
network, and has none on the base branch.
Run
Scope
Remote writes
push to the default branch
none
the default keys
push to, or pull request from, feat-x
acme/app:feat-x
that scope only
pull request from a fork’s feat-x
eve/app:feat-x
that scope only
Each task asks the remote one key. A task the branch changed (its
declared inputs match a changed file, or a dependsOn task’s do) reads
the scope’s entry; every other task reads main’s, so a README edit
leaves build on main’s entry. CI saves every task it builds under the
scope, so a branch never writes main’s keys.
The local cache never knows a scope. What a laptop fetches for its
branch it keeps under the task key, so the same inputs hit locally on
any branch, main included. The summary’s info row names the scope:
What a branch changed is the diff from a pull request’s base commit
(github() reads it from the event, so fetch-depth: 2 is enough), else
from the merge base with origin/<baseBranch>. Git is asked for that
diff only at a scoped run’s first remote call, so a run the local cache
answers asks it nothing more. VX_CACHE_SCOPE names a scope by hand,
for a CI with a detached HEAD, and an empty value turns it off. See
Cache scopes and tokens.
A bare --affected on the base branch guessed HEAD~1, which is wrong
after any push of more than one commit. It now
compares with the same base the cache scope uses, and on the base
branch it asks for the commit to compare with:
Terminal window
$vxrunbuild--affected--dry
✗vxrun--affectedhasnodefaultonthebasebranch (main): name the last good commit, --affected=<sha>
run.affectedBase is now baseBranch, a branch name, read from
VX_BASE_BRANCH. Unset, it is origin/HEAD’s branch, then main, then
master.
A local cache hit copies plain files instead of unpacking an archive, a remote hit is decompressed once straight into the store, remote downloads and uploads set their own pace, a cache server learns each request's scope, GitLab CI gets branch scopes, [...] in a task glob is a character class, and vx upgrade re-locks.
Editing a file: or link: dependency, or patching one, now rebuilds what uses it. A hit brings back empty folders and symlinks as the build left them. A remote cache token lives in your keychain or comes from GitHub OIDC, warm runs are faster at scale, and Ctrl-C stops at once.
vx init installs vx for you, a cache server keeps branches apart by the CI token instead of trusting the client, a slow download gives way to running the task, and a local hit copies its files out unchecked.
Turborepo, Nx and other product names are trademarks of their owners. vx is not affiliated with or endorsed by them.