# VCS Levels
## Description
The **VCS Level** of a Versio command is the extent to which that
command interacts with your Version Control System (VCS) (e.g. Git).
There are four such levels, ordered from minimal to maximal:
- **None**: The command does not interact with VCS at all: no commits,
pulls, merges, fetches, etc. are done. Tags are not searched for
version numbers, etc.; nor are they updated with new version numbers.
- **Local**: The command interacts with the VCS system only at the local
level: no network or remote interaction is allowed. Fetches, pulls
and pushes are not done: not even with tags. No effort is made to
ensure that the local repository is synchronized with any remote.
- **Remote**: The command interacts fully with the VCS system, including
a guarantee that the local repository is fully synced with the remote
both before and after the command executes.
- **Smart**: As "Remote", but also applies intelligence that requires
interaction with other VCS-related entities e.g. the GitHub API. For
example, commits in a GitHub-based repo can be grouped by Pull
Request (see [PR Scanning](./pr_scanning.md)).
### Vs Dry Run
The VCS Level is distinct from the idea of a "dry run". A "dry run" flag
prohibits a command from writing anything at any level, but doesn't
affect what is read. For example, the flags `--vcs-level=smart
--dry-run` can still read data from the GitHub remote and API, but will
not commit any changes. Using `--vcs-level=local` without `--dry-run`
will not read any data from the remote, nor will it write to the remote:
however, it may still write to the filesystem, and commit and tag any
changes to the local repository.
### Vs Pause
The VCS Level is distinct from the idea of a "pause". The "pause" flag
exits a command just before executing a stage (e.g. "commit"), but
otherwise doesn't affect operations or have any effect on the VCS level.
In fact, you can supply a different VCS level to commands with the
`--pause` and `--resume` commands, and that level will apply for the
portion of the operation it applies to.
You could, for example, run `versio -l smart release --pause commit` to
gather information and write new versions and changelogs based on pull
request information from the remote GitHub API, but then run `versio -l
local release --resume` to commit and tag only the local repo.
### Vs Current
The `--no-current` flag only works on some commands, and only when the
final VCS level is calculated as "local" (see "Calculation" below).
Normally all commands at the "local" level will verify that the repo is
current: i.e., it does not contain local modifications or untracked
files. Some commands don't make any changes though, so it may be safe to
run them without this check, depending on your workflow.
At a VCS level of "remote" or higher, the check is always done (the
`--no-current` flag is ignored) because only a current repo can be
reconciled with remote changes. At the level of "none", the VCS isn't
consulted in any case, so the flag is effectively ignored.
## Calculation
Every Versio command except for `init` and `schema` calculates the final
VCS level using three inputs, each of which is itself a range of levels:
1. The _preferred_ range is given by the user, or by the command itself
if the user doesn't provide it.
1. The _required_ range is the VCS range in which the command can
operate, and is provided by the command. Some commands can only act
if they can interact with the VCS system in certain ways. The max of
the required range is usually the highest value, "Smart".
1. The _detected_ range is the VCS levels supported by the current
working directory. Is it in a repo, does the repo have a remote, etc.
The min of the detected range is usually the lowest value, "None".
In the presence of these three ranges, the final VCS level is calculated
as the maximum of the intersection of all three ranges. For example, if
the preferred range is [Local, Remote], and the required range is
[Local, Smart], and the detected range is [None, Remote], then the
highest intersected value is 'Remote', which is what the command will
run as.
If there is no common intersection of the three ranges, then the command
will immediately fail without any attempt to read or write anything.
The `init` and `schema` commands do not interact with VCS, and so ignore
all VCS levels.
Most Versio commands try to find the `root` of a repository to run in:
this is either the base directory of the local VCS (if any is detected),
or it's the nearest (inclusive) ancestor from the current working
directory that contains a `.versio.yaml` config file. If neither such
directory can be found, then the current directory is used.
## Detection
Currently, Git is the only VCS that Versio understands; it creates the
detected range like this:
- The minimum of the range is always "None". The maximum of the range is
at least "None".
- If the working directory is a local working directory, and if the
directory is checked out of a branch, then the maximum is at least
"Local".
- Additionally, if the current branch has a configured remote, or if the
repository itself has exactly one remote, then the maximum is at least
"Remote".
- Additionally, if the remote URL starts with "https://github.com/" or
"git@github.com:", then the maximum is "Smart".
## Options
Normally, you don't have to do anything with VCS levels: the best level
for a command is picked naturally. However, you can alter the min and
maximum of the preferred range when you run Versio. There are three
command-line options you can use to set the preferred range:
- `vcs-level` (`-l`): This allow you specify both the max and min of the
preferred range in one shot. There are six possible arguments:
- The discreet levels `none`, `local`, `remote`, or `smart`, which
sets both the min and max of the preferred range to the given value.
- `max`, which sets the minimum to `none` and the maximum to `smart`.
This runs the command at the maximum allowable level, even if the
default for a command is lower.
- `auto`, which declines to set a default range, and allows the
command to set the default. This is the same as not providing any
default at all.
- `vcs-level-min` (`-m`) and `vcs-level-max` (`-x`): You must use these
options together, and can't use them with `vcs-level`. These manually
set the minimum and maximum level of the preferred range to one of
their four possible values `none`, `local`, `remote`, or `smart`. If
you set the max level below the min value, the preferred range is
considered empty, and the command will fail.
## Tips
- Use `vcs-level-max=local` to avoid incurring any network traffic.
- Use `versio -l local -c <command>` to run a versio command without
worrying about the state of your repository.
- Use `vcs-level-max=remote` to avoid using the GitHub API. All commands
can operate at this level, although your changelogs and sizing
calculation might suffer because of the lack of PRs/unsquash.