Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add documentation #4

Merged
merged 1 commit into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,176 @@
<div align="center">

# comver

</div>

<div align="center">

[![Go](https://github.com/typisttech/comver/actions/workflows/go.yml/badge.svg)](https://github.com/typisttech/comver/actions/workflows/go.yml)
[![Go Report Card](https://goreportcard.com/badge/github.com/typisttech/comver)](https://goreportcard.com/report/github.com/typisttech/comver)
[![GitHub Release](https://img.shields.io/github/v/release/typisttech/comver?style=flat-square&)](https://github.com/typisttech/comver/releases/latest)
[![Go Reference](https://pkg.go.dev/badge/github.com/typisttech/comver.svg)](https://pkg.go.dev/github.com/typisttech/comver)
[![license](https://img.shields.io/github/license/typisttech/comver.svg?style=flat-square)](https://github.com/typisttech/comver/blob/master/LICENSE)
[![X Follow @TangRufus](https://img.shields.io/badge/Follow-%40TangRufus-black?style=flat-square&logo=x&logoColor=white)](https://x.com/tangrufus)
[![Hire Typist Tech](https://img.shields.io/badge/Hire-Typist%20Tech-ff69b4.svg?style=flat-square)](https://typist.tech/contact/)

</div>

<p align="center">
<strong>Package <code>comver</code> provides the ability to work with <a href="https://github.com/composer/semver/">composer supported versions</a> in Go.</strong>
<br />
<br />
Built with ♥ by <a href="https://typist.tech/">Typist Tech</a>
</p>

---

## Usage

> [!NOTE]
> See full API documentation at [pkg.go.dev](https://pkg.go.dev/github.com/typisttech/comver).

### `Version`

[`NewVersion`](https://pkg.go.dev/github.com/typisttech/comver#NewVersion) parses a given version string, attempts to coerce a version string into a [`Version`](https://pkg.go.dev/github.com/typisttech/comver#Version) object or return an error if unable to parse the version string.

If there is a leading **v** or a version listed without all parts (e.g. **v1.2.p5+foo**) it will attempt to coerce it into a valid composer version (e.g. **1.2.0.0-patch5**). In both cases a [`Version`](https://pkg.go.dev/github.com/typisttech/comver#Version) object is returned that can be sorted, compared, and used in constraints.


> [!WARNING]
> Due to implementation complexity, it only supports a subset of [composer versioning](https://github.com/composer/semver/).
>
> Refer to the [`version_test.go`](version_test.go) for examples.


```go
ss := []string{
"1.2.3",
"v1.2.p5+foo",
"v1.2.3.4.p5+foo",
"2010-01-02",
"2010-01-02.5",
"not a version",
"1.0.0-meh",
"20100102.0.3.4",
"1.0.0-alpha.beta",
}

for _, s := range ss {
v, err := comver.NewVersion(s)
if err != nil {
fmt.Println(s, " => ", err)
continue
}
fmt.Println(s, " => ", v)
}

// Output:
// 1.2.3 => 1.2.3.0
// v1.2.p5+foo => 1.2.0.0-patch5
// v1.2.3.4.p5+foo => 1.2.3.4-patch5
// 2010-01-02 => 2010.1.2.0
// 2010-01-02.5 => 2010.1.2.5
// not a version => error parsing version string "not a version"
// 1.0.0-meh => error parsing version string "1.0.0-meh"
// 20100102.0.3.4 => error parsing version string "20100102.0.3.4"
// 1.0.0-alpha.beta => error parsing version string "1.0.0-alpha.beta"
```

### `constraint`

```go
v1, _ := comver.NewVersion("1")
v2, _ := comver.NewVersion("2")
v3, _ := comver.NewVersion("3")
v4, _ := comver.NewVersion("4")

cs := []any{
comver.NewGreaterThanConstraint(v1),
comver.NewGreaterThanOrEqualToConstraint(v2),
comver.NewLessThanOrEqualToConstraint(v3),
comver.NewLessThanConstraint(v4),
}

for _, c := range cs {
fmt.Println(c)
}

// Output:
// >1
// >=2
// <=3
// <4
```

### `interval`

`interval` represents the intersection (logical AND) of two constraints.

```go
v1, _ := comver.NewVersion("1")
v2, _ := comver.NewVersion("2")
v3, _ := comver.NewVersion("3")

g1l3, _ := comver.NewInterval(
comver.NewGreaterThanConstraint(v1),
comver.NewLessThanConstraint(v3),
)

if g1l3.Check(v2) {
fmt.Println(v2.Short(), "satisfies", g1l3)
}

if !g1l3.Check(v3) {
fmt.Println(v2.Short(), "doesn't satisfy", g1l3)
}

// Output:
// 2 satisfies >1 <3
// 2 doesn't satisfy >1 <3
```

### `Intervals`

[`Intervals`](https://pkg.go.dev/github.com/typisttech/comver#Intervals) represent the union (logical OR) of multiple intervals.

```go
v1, _ := comver.NewVersion("1")
v2, _ := comver.NewVersion("2")
v3, _ := comver.NewVersion("3")
v4, _ := comver.NewVersion("4")

g1l3, _ := comver.NewInterval(
comver.NewGreaterThanConstraint(v1),
comver.NewLessThanConstraint(v3),
)

ge2le4, _ := comver.NewInterval(
comver.NewGreaterThanOrEqualToConstraint(v2),
comver.NewLessThanOrEqualToConstraint(v4),
)

is := comver.Intervals{g1l3, ge2le4}
fmt.Println(is)

is = comver.Compact(is)
fmt.Println(is)

// Output:
// >1 <3 || >=2 <=4
// >1 <=4
```

## Credits

[`comver`](https://github.com/typisttech/comver) is a [Typist Tech](https://typist.tech) project and maintained by [Tang Rufus](https://x.com/TangRufus), freelance developer for [hire](https://typist.tech/contact/).

Full list of contributors can be found [here](https://github.com/typisttech/comver/graphs/contributors).

## Copyright and License

This project is a [free software](https://www.gnu.org/philosophy/free-sw.en.html) distributed under the terms of the MIT license. For the full license, see [LICENSE](./LICENSE).

## Contribute

Feedbacks / bug reports / pull requests are welcome.
2 changes: 1 addition & 1 deletion constraint.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (c *constraint) upperbounded() bool {
return c.op == lessThanOrEqualTo || c.op == lessThan
}

// Check tests if a [Version] satisfies the constraints.
// Check reports whether a [Version] satisfies the constraint.
func (c *constraint) Check(v Version) bool {
if c == nil {
// this should never happen
Expand Down
6 changes: 6 additions & 0 deletions doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*
Package comver provides the ability to work with [composer supported versions] in Go.

[composer supported versions]: https://github.com/composer/semver/
*/
package comver
115 changes: 115 additions & 0 deletions doc_examle_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package comver_test

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tangrufus This files could be renamed to doc_example_test.go (note the p)

Copy link
Member Author

@tangrufus tangrufus Nov 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I need ☕

Please don't use this package yet. I am not satisfied with the API yet.
API changes are coming in #12

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in #12

Thanks!


import (
"fmt"

"github.com/typisttech/comver"
)

func Example_version() {
ss := []string{
"1.2.3",
"v1.2.p5+foo",
"v1.2.3.4.p5+foo",
"2010-01-02",
"2010-01-02.5",
"not a version",
"1.0.0-meh",
"20100102.0.3.4",
"1.0.0-alpha.beta",
}

for _, s := range ss {
v, err := comver.NewVersion(s)
if err != nil {
fmt.Println(s, " => ", err)
continue
}
fmt.Println(s, " => ", v)
}

// Output:
// 1.2.3 => 1.2.3.0
// v1.2.p5+foo => 1.2.0.0-patch5
// v1.2.3.4.p5+foo => 1.2.3.4-patch5
// 2010-01-02 => 2010.1.2.0
// 2010-01-02.5 => 2010.1.2.5
// not a version => error parsing version string "not a version"
// 1.0.0-meh => error parsing version string "1.0.0-meh"
// 20100102.0.3.4 => error parsing version string "20100102.0.3.4"
// 1.0.0-alpha.beta => error parsing version string "1.0.0-alpha.beta"
}

func Example_constraint() {
v1, _ := comver.NewVersion("1")
v2, _ := comver.NewVersion("2")
v3, _ := comver.NewVersion("3")
v4, _ := comver.NewVersion("4")

cs := []any{
comver.NewGreaterThanConstraint(v1),
comver.NewGreaterThanOrEqualToConstraint(v2),
comver.NewLessThanOrEqualToConstraint(v3),
comver.NewLessThanConstraint(v4),
}

for _, c := range cs {
fmt.Println(c)
}

// Output:
// >1
// >=2
// <=3
// <4
}

func Example_interval() {
v1, _ := comver.NewVersion("1")
v2, _ := comver.NewVersion("2")
v3, _ := comver.NewVersion("3")

g1l3, _ := comver.NewInterval(
comver.NewGreaterThanConstraint(v1),
comver.NewLessThanConstraint(v3),
)

if g1l3.Check(v2) {
fmt.Println(v2.Short(), "satisfies", g1l3)
}

if !g1l3.Check(v3) {
fmt.Println(v2.Short(), "doesn't satisfy", g1l3)
}

// Output:
// 2 satisfies >1 <3
// 2 doesn't satisfy >1 <3
}

func Example_intervals() {
v1, _ := comver.NewVersion("1")
v2, _ := comver.NewVersion("2")
v3, _ := comver.NewVersion("3")
v4, _ := comver.NewVersion("4")

g1l3, _ := comver.NewInterval(
comver.NewGreaterThanConstraint(v1),
comver.NewLessThanConstraint(v3),
)

ge2le4, _ := comver.NewInterval(
comver.NewGreaterThanOrEqualToConstraint(v2),
comver.NewLessThanOrEqualToConstraint(v4),
)

is := comver.Intervals{g1l3, ge2le4}
fmt.Println(is)

is = comver.Compact(is)
fmt.Println(is)

// Output:
// >1 <3 || >=2 <=4
// >1 <=4
}
4 changes: 2 additions & 2 deletions interval.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package comver

// interval represents the intersection of two constraints.
// interval represents the intersection (logical AND) of two constraints.
type interval [2]*constraint

const (
Expand Down Expand Up @@ -44,7 +44,7 @@ func NewInterval(c1, c2 *constraint) (interval, error) { //nolint:cyclop
}
}

// Check tests if a [Version] lies within the interval.
// Check reports whether a [Version] satisfies the interval.
func (i interval) Check(v Version) bool {
for _, c := range i {
if c != nil && !c.Check(v) {
Expand Down
15 changes: 13 additions & 2 deletions version.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,18 @@ type Version struct {
original string `exhaustruct:"optional"`
}

// NewVersion parses a given version string and returns an instance of [Version] or
// an error if unable to parse the version.
// NewVersion parses a given version string, attempts to coerce a version string into
// a [Version] object or return an error if unable to parse the version string.
//
// If there is a leading v or a version listed without all parts (e.g. v1.2.p5+foo) it will
// attempt to coerce it into a valid composer version (e.g. 1.2.0.0-patch5). In both cases
// a [Version] object is returned that can be sorted, compared, and used in constraints.
//
// Due to implementation complexity, it only supports a subset of [composer versioning].
// Refer to the [version_test.go] for examples.
//
// [composer versioning]: https://github.com/composer/semver/
// [version_test.go]: https://github.com/typisttech/comver/blob/main/version_test.go
func NewVersion(v string) (Version, error) { //nolint:cyclop,funlen
original := v

Expand Down Expand Up @@ -152,6 +162,7 @@ func (v Version) String() string {
return s
}

// Short returns the shortest string representation of the version.
func (v Version) Short() string {
s := fmt.Sprintf("%d.%d.%d.%d", v.major, v.minor, v.patch, v.tweak)

Expand Down
Loading