versio 0.8.5

Versio is a tool to manage and publish project versions.
Documentation
# Common Use Cases

These are some of the common ways that you might want to use Versio in
your own development. If you find a new or novel way to use Versio,
please let us know!

## Quick Start

Get up and running quickly with Versio in a new or existing project.

- Create and commit a simple config file:
  ```
  $ git pull
  $ versio init  # this creates .versio.yaml
  $ git add .versio.yaml .gitignore
  $ git commit -m "build: add versio management"
  $ git push
  $ versio release
  ```
- If you want to use the GitHub API for [PR scanning]./pr_scanning.md,
  you'll need to update your `~/.versio/prefs.toml` file: See the
  [Reference]./reference.md#github-api.
- After some [conventional
  commits](https://www.conventionalcommits.org/), update it:
  ```
  $ versio release
  Executing plan:
    project : 1.0.1 -> 1.1.0
  Changes committed and pushed.
  ```

## Add Versio to an existing Repo

If you've been releasing your project for a while before switching to
Versio, you might not want to scan your entire project history the first
time you release. You can tag the commit of your latest release to
indicate that's where Versio should pick up:

```
$ git tag -f versio-prev <last_release_commit>
```

You can add some JSON to indicate the current version of projects. This
is especially useful for `version: tags` style projects that don't have
a manifest file which lists their version.

```
$ git tag -f -a -m '{"versions":{"1":"0.1.2","2":"5.2.1"}}' \
      versio-prev <last_release_commit>
```

You can leave off the `last_release_commit` argument if you want to
start releasing from the latest commit.

In lieu of (or in addition to) using JSON, you can create separate tags
on the latest commit that indicate the versions of your projects, using
the projects' tag prefixes.

```
$ git tag -f proj_1_tag_prefix-v0.1.2
$ git tag -f v5.2.1
```

## View Project Versions

Since Versio knows where all your project versions are stored, it can
output them for you. It can even tell you the versions of projects as
they were set by the last execution of `versio release`.

- View current versions in "wide" format (which shows project IDs):
  ```
  $ versio show -w
  1. myproject    : 1.0.1
  2. otherproject : 1.0.1
  ```
- View a specific project version
  ```
  $ versio get --id 1
  myproject : 1.0.1
  ```
- Print just the version number
  ```
  $ versio get --id 1 -v
  1.0.1
  ```
- Show the latest-released versions:
  ```
  $ versio show --prev
  myproject    : 1.0.1
  otherproject : 1.0.1
  ```

  If you rely solely on Versio to update project numbers for you, then
  the last-released version will usually match the current version.

## Change a Project Version

If you want to manually set a version.

```
$ versio set --value 1.2.3
```

If you have more than one project configured, and you must supply the ID
or the name of the project you want to change.

```
$ versio set --id 1 --value 1.2.3
$ versio set --name my_proj --value 1.2.3
$ versio set --exact my_project --value 1.2.3
```

### Tags projects

By default, `set` has a default VCS level of `none` (see [VCS
Levels](./vcs_levels.md)), so it won't commit, tag, or push your new
version to a remote. This works great for most projects, allowing to you
make quick local changes to your manifest file. However, "version: tags"
projects have no manifest, and keep version numbers only in tags; `set`
by default performs no action for these. To change a version in the VCS,
you can use a different VCS level, like this:

```
$ versio -l max set --id 1 --value 1.2.3
```

## Create a New Configuration

To start using Versio, you should create a `.versio.yaml` config file in
your repo. Use the following command to do so. Make sure you're in the
top-level directory of your repository (or the top-level directory of
your non-version-controlled monorepo) when you do so:

```
$ versio init
```

This will scan your repo for existing projects, and create a new config
file with each of those projects listed. If you change later add,
remove, or change the location of your projects, you should edit this
file by hand to keep it up-to-date.

The `init` command will not scan hidden directories or file, or
directories or files listed in any `.gitignore` files. If you want to
include projects in hidden or ignored locations, you'll have to add
those by hand to the resulting `.versio.yaml` file.

## Gitflow / Oneflow

If you're using
[Gitflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow),
[Oneflow](https://www.endoflineblog.com/oneflow-a-git-branching-model-and-workflow),
or a similar process, you may have separate branchs for hotfixes or
maintained versions.

To use Versio in these flows, you can use the "prev tag" option. What
you want is have the hotfix branch use a different "prev tag" (default
`versio-prev`) than your main branch. Here's what to do:

1. Create a new branch as normal for a hotfix: this will be at a
   branch-point, where the branch diverges from the main release trunk.
   E.g. `git switch -c hotfix-1234 v1.0.0` (`git checkout -b hotfix-1234
   v1.0.0` for older versions of git)
2. Tag the branch-point with a unique "prev tag"; something based on the
   branch name would be ideal. E.g. `git tag versio-prev-hotfix-1234`.
   If there are specific project versions you want that branch to start
   from, you can help the process by annotating the tag: `git tag -f -a
   -m '{"versions":{"1":"0.1.2","2":"5.2.1"}}' versio-prev-hotfix-1234`.
   Otherwise, Versio will try to figure it out.
3. Change the `prev-tag` option in the `.versio.yaml` file **in the new
   branch** to point to your new "prev tag":
   ```
   options:
     prev_tag: "versio-prev-hotfix-1234"
   ```
4. Commit / push your change. `git commit -am 'build: update versio for
   branch' ; git push -u origin hotfix-1234`
5. Now the hotfix branch will use `versio-prev-hotfix-1234` instead of
   `versio-prev` as its "prev tag". But because you didn't change the
   `.versio.yaml` file on the main branch, main will still use
   `versio-prev`.
6. You can `versio release` as normal on both the main branch and the
   hotfix branch independently. The first time you run it on the hotfix
   branch, it will re-calculate the version number based on your
   annotation, and/or whatever tags exist on or before the branch-point.

**Warning**: Using this strategy won't guard against re-using version
numbers: it's possible that you could inadvertently release e.g. v1.0.3
on both the main branch and the hotfix branch: in that case, the tag
will move to whichever is released last, which is probably not what you
want. Be certain that you aren't clobbering your version numbers when
you release. `versio release --dry-run` can be useful.

## CI/CD

### GitHub Action Matrixes

If you are using a monorepo, you may want to perform the same build step
on all your (for example) Node.js projects. You can build GitHub dynamic
matrixes using the `versio info` command, and then use those matrixes to
execute multiple projects in your repo. For example, if you wanted to
run 'npm test' in every project in your monorepo with the `npm` label:

```
jobs:
  project-matrixes:
    runs-on: ubuntu-latest
    outputs:
      npm-matrix: "${{ steps.find-npm-matrix.outputs.matrix }}"
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      - name: Get versio
        uses: chaaz/versio-actions/install@v1.3
      - name: Find npm matrix
        id: find-npm-matrix
        run: echo matrix={\"include\":$(versio -l none info -l npm -R -N)} >> $GITHUB_OUTPUT
  npm-tests:
    needs: project-matrixes
    runs-on: ubuntu-latest
    strategy:
      matrix: "${{ fromJson(needs.project-matrixes.outputs.npm-matrix) }}"
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      - name: Run local tests
        run: npm test
        working-directory: "${{ matrix.root }}"
```

### Authorization

In most CI/CD environments, you may not have a credentials agent
available to negotiate credentials to your git repo and/or github APIs.
Instead, your should set the `GITHUB_USER` and `GITHUB_TOKEN`
environment variables. For example, GitHub Actions provides these values
to you in various places:

```
env:
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  GITHUB_USER: ${{ github.actor }}
```

## CI Pre-merge

You can use Versio to check that a branch is ready to be merged to your
deployment branch. Your CI pipeline can run `versio check` to ensure
that the `.versio.yaml` file is properly configured, and can `versio
plan` to log the version changes which will be applied once merged.

### GitHub Actions

Use the example snippet to build a workflow for pull requests that can
verify that Versio is configured correctly for all projects, and which
will print out all changes in the PR, and their possible effect on the
project(s) version numbers.

Note the use of `checkout@v3`, and the following `git fetch --unshallow`
command, which is necessary to fill in the git history before `versio`
is asked to analyze it. Also, we've provided a
`versio-actions/install@v1.3` command which installs the `versio`
command into the job. (Currently, the `versio-actions/install` action
only works for linux-based runners.)

```
---
name: pr
on:
  - pull_request
env:
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  GITHUB_USER: ${{ github.actor }}

jobs:
  versio-checks:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      - name: Get versio
        uses: chaaz/versio-actions/install@v1.3
      - name: Fetch history
        run: git fetch --unshallow
      - name: Check projects
        run: versio check
      - name: Print changes
        run: versio plan
```

## CI Release

As part of your CI/CD pipeline, you can create an action to execute
`versio release`, which will update the version numbers, generate
changelogs, and commit and push all changes. You can set this action to
run automatically when a branch has been merged to a release branch, or
at any other time you want your software to be released.

### About Timing

It's important to note that nothing can be pushed to the release branch
during the short time that `versio release` is running, or else it will
fail. There are a number of ways you can deal with this: from locking
the branch while Versio is running; to creating a pre-release branch to
separate merges from the release process; to simply ignoring the problem
and manually re-running the CI action if it gets stuck; and more. The
strategy you use is dependent on the specifics of your organization and
CI/CD process.

### GitHub Actions

A GitHub Actions job that releases your projects might look something
like this:

```
jobs:
  versio-release:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      - name: Get versio
        uses: chaaz/versio-actions/install@v1.3
      - name: Fetch history
        run: git fetch --unshallow
      - name: Generate release
        run: versio release
```