Calculate Go module's libyear!
Use pre-built binaries from the latest release or install with Go:
go install github.com/nieomylnieja/go-libyear/cmd/go-libyear@latest
It can also be built directly from this repository:
git clone https://github.com/nieomylnieja/go-libyear.git
cd go-libyear
make build
./bin/go-libyear ./go.mod
Docker images hosted on GitHub Container Registry are also provided:
docker pull ghcr.io/nieomylnieja/go-libyear:latest
docker run --rm ghcr.io/nieomylnieja/go-libyear -p github.com/nieomylnieja/go-libyear
go-libyear
can be used both as a CLI and Go library.
The CLI usage is also documented in usage.txt
and accessed through go-libyear --help
.
Basic usage:
$ go-libyear /path/to/go.mod
package version date latest latest_date libyear
github.com/nieomylnieja/go-libyear 2023-11-06 2.41
github.com/pkg/errors v0.8.1 2019-01-03 v0.9.1 2020-01-14 1.03
github.com/urfave/cli/v2 v2.20.0 2022-10-14 v2.25.7 2023-06-14 0.67
golang.org/x/mod v0.12.0 2023-06-21 v0.14.0 2023-10-25 0.35
golang.org/x/sync v0.3.0 2023-06-01 v0.5.0 2023-10-11 0.36
What exactly is libyear? Quoting and paraphrasing libyear.com:
Libyear is a simple measure of software dependency freshness.
It is a single number telling you how up-to-date your dependencies are.
Example: pkg/errors v0.8.1 (June 2019) is 1 libyear behind v0.9.0 (June 2020).
Libyear is the default metric calculated by the program.
Example:
Current | Current release | Latest | Latest release | Libyear |
---|---|---|---|---|
v1.45.1 | 2022-10-11 | v2.0.5 | 2023-10-11 | 1 |
v1.46.0 | 2022-12-04 | v2.0.5 | 2023-10-11 | 0.85 |
v2.0.0 | 2023-10-01 | v2.0.5 | 2022-10-11 | 0.03 |
Dependencies with short release cycles are penalized by this measurement, as the version sequence distance is relatively high compared to other dependencies.
Example:
Versions |
---|
v1.45.1 |
v1.45.2 |
v1.46.0 |
v2.0.0 |
v2.0.1 |
Current | Latest | Delta |
---|---|---|
v1.45.1 | v2.0.5 | 5 |
Version delta is a tuple (x,y,z) where:
- x is major version
- y is minor version
- z is patch version
Only highest-order version number is taken into consideration.
Example:
Current | Latest | Delta |
---|---|---|
v1.45.1 | v2.0.5 | (1,0,0) |
v1.45.1 | v1.47.5 | (0,2,0) |
v1.45.1 | v.45.5 | (0,0,4) |
Flag | Explanation |
---|---|
--releases |
Count number of releases between current and latest. |
--versions |
Calculate version number delta between current and latest. |
--indirect |
Include indirect dependencies in the results. |
--skip-fresh |
Skip up-to-date dependencies from the results. |
--find-latest-major |
Use next, greater than or equal to v2 version as the latest. |
Source | Flag | Example |
---|---|---|
File path | default | ~/my-project/go.mod |
URL | --url |
https://raw.githubusercontent.com/nieomylnieja/go-libyear/main/go.mod |
Module path | --pkg |
github.com/nieomylnieja/go-libyear@latest |
Format | Flag |
---|---|
Table | default |
JSON | --json |
CSV | --csv |
In order to calculate the metrics in a given point in time,
use --age-limit
flag.
Example:
go-libyear --age-limit 2022-10-01T12:00:00Z ./go.mod
The latest version for each package will be appointed as the latest version of the package before or at the provided timestamp.
The flag works any other flag. If using a script to extract a history
of the calculated metrics, it is recommended to use --cache
flag as well.
go-libyear
ships with a built-in caching mechanism.
It is disabled by default but can be enabled and adjusted with the following
flags:
Flag | Explanation |
---|---|
--cache |
Enable caching. |
--cache-file-path |
Use the specified file for caching. |
--vcs-cache-dir |
Use custom cache path for VCS modules. |
By default go-libyear
will fetch the latest version for the current major
version adhering to the following rules:
- If the current major version is equal to 0.x.x and there's version 1.x.x available, set the latest to 1.x.x.
- If the current major is equal to or greater than 1.x.x, set the latest to 1.x.x.
If you wish to always set the next major version as the latest, you can use
the --find-latest-major
(short -M
) flag.
This flag enforces the following rules:
-
If the current major is equal to or greater than x.x.x, set the latest to the latest (by semver) available version.
-
If the latest major version is greater than the current major and the current version has been published after the first version of the latest major, the libyear is calculated as a difference between the first version of the latest major and latest major version.
Example:
Current version is 1.21.9 (2024-02-01), latest is 2.0.5 (2024-01-19);
1.21.9 was a security fix, it still means we're some time behind v2;
2.0.0 was released on 2024-01-02, this means we're 17 days (2024-01-19 - 2024-01-02) behind the latest v2, despite the fact that we've updated to the latest security patch for v1.
If you wish to not compensate for such cases and leave libyear as is
(it won't be ever negative, we round it to 0 if negative), use the
--no-libyear-compensation
flag.
The modules reference states that:
If the module is released at major version 2 or higher, the module path must end with a major version suffix like /v2.
This is however not always the case, some older projects, usually pre-module, might not adhere to that. The aforementioned flag also works with such scenarios.
Currently the default mode of execution only supports git VCS and GitHub source.
To access all private modules use --go-list
flag.
It will instruct the program to utilize go list
command instead of GOPROXY API.
If --go-list
flag is provided, go-libyear
will used go list
command to
fetch information about modules.
Specifically it runs go list -m -mod=readonly
.
If the program is executed in a project containing a go.mod
which go.sum
file is out of sync,
it will drop the following error:
updates to go.sum needed, disabled by -mod=readonly
Due to that it is advised to stick with default modules information provider.
CLI application is tested
with bats framework.
The tests are defined in test
folder.
Only core calculations are covered by unit tests, main paths are tested through
CLI tests.
Inspired directly by SE Radio episode 587. Further reading through libyear.com and mimicking libyear-bundler capabilities.
All the concepts and theory is based on or directly quoted from Measuring Dependency Freshness in Software Systems.