Skip to content

Commit dabf54f

Browse files
committed
Version constraints configuration
terraform-docs version constraints is almost identical to the syntax used by Terraform. A version constraint is a string literal containing one or more condition, which are separated by commas. ```yaml version: ">= 0.13.0, < 1.0.0" ``` Each condition consists of an operator and a version number. A version number is a series of numbers separated by dots (e.g. `0.13.0`). Note that version number should not have leading `v` in it. Valid operators are as follow: - `=` (or no operator): allows for exact version number. - `!=`: exclude an exact version number. - `>`, `>=`, `<`, and `<=`: comparisons against a specific version. - `~>`: only the rightmost version component to increment. Signed-off-by: Khosrow Moossavi <khos2ow@gmail.com>
1 parent b8b0edc commit dabf54f

File tree

8 files changed

+155
-1
lines changed

8 files changed

+155
-1
lines changed

docs/user-guide/configuration.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ Below is a complete list of options that you can use with `terraform-docs`, with
4343
corresponding default values (if applicable).
4444

4545
```yaml
46+
version: ""
47+
4648
formatter: <FORMATTER_NAME>
4749

4850
header-from: main.tf
@@ -92,6 +94,29 @@ settings:
9294
**Note:** As of `v0.13.0`, `sections.hide-all` and `settings.show-all` are deprecated
9395
and removed in favor of explicit use of `settings.hide` and `settings.show`.
9496

97+
## Version
98+
99+
Since `v0.13.0`
100+
101+
terraform-docs version constraints is almost identical to the syntax used by
102+
Terraform. A version constraint is a string literal containing one or more condition,
103+
which are separated by commas.
104+
105+
```yaml
106+
version: ">= 0.13.0, < 1.0.0"
107+
```
108+
109+
Each condition consists of an operator and a version number. A version number is
110+
a series of numbers separated by dots (e.g. `0.13.0`). Note that version number
111+
should not have leading `v` in it.
112+
113+
Valid operators are as follow:
114+
115+
- `=` (or no operator): allows for exact version number.
116+
- `!=`: exclude an exact version number.
117+
- `>`, `>=`, `<`, and `<=`: comparisons against a specific version.
118+
- `~>`: only the rightmost version component to increment.
119+
95120
## Formatters
96121

97122
The following options are supported out of the box by terraform-docs and can be

examples/.terraform-docs.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1+
# # terraform-docs version constraints for execution
2+
# # more information: https://terraform-docs.io/user-guide/configuration/#version
3+
# version: ">= 0.10, < 0.12"
4+
15
formatter: markdown table
6+
27
header-from: doc.txt
38
footer-from: footer.md
49

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.16
55
require (
66
github.com/BurntSushi/toml v0.3.1
77
github.com/hashicorp/go-plugin v1.4.0
8+
github.com/hashicorp/go-version v1.3.0
89
github.com/iancoleman/orderedmap v0.2.0
910
github.com/imdario/mergo v0.3.11
1011
github.com/mitchellh/go-homedir v1.1.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
104104
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
105105
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
106106
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
107+
github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04x7iNw=
108+
github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
107109
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
108110
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
109111
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=

internal/cli/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ type Config struct {
326326
BaseDir string `yaml:"-"`
327327
File string `yaml:"-"`
328328
Formatter string `yaml:"formatter"`
329+
Version string `yaml:"version"`
329330
HeaderFrom string `yaml:"header-from"`
330331
FooterFrom string `yaml:"footer-from"`
331332
Sections sections `yaml:"sections"`
@@ -341,6 +342,7 @@ func DefaultConfig() *Config {
341342
BaseDir: "",
342343
File: "",
343344
Formatter: "",
345+
Version: "",
344346
HeaderFrom: "main.tf",
345347
FooterFrom: "",
346348
Sections: defaultSections(),

internal/cli/run.go

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ import (
1616
"os"
1717
"path/filepath"
1818

19+
goversion "github.com/hashicorp/go-version"
1920
"github.com/spf13/cobra"
2021
"github.com/spf13/pflag"
2122

2223
pluginsdk "github.com/terraform-docs/plugin-sdk/plugin"
2324
"github.com/terraform-docs/terraform-docs/internal/format"
2425
"github.com/terraform-docs/terraform-docs/internal/plugin"
2526
"github.com/terraform-docs/terraform-docs/internal/terraform"
27+
"github.com/terraform-docs/terraform-docs/internal/version"
2628
)
2729

2830
// list of flagset items which are explicitly changed from CLI
@@ -31,7 +33,11 @@ var changedfs = make(map[string]bool)
3133
// PreRunEFunc returns actual 'cobra.Command#PreRunE' function for 'formatter'
3234
// commands. This functions reads and normalizes flags and arguments passed
3335
// through CLI execution.
34-
func PreRunEFunc(config *Config) func(*cobra.Command, []string) error {
36+
func PreRunEFunc(config *Config) func(*cobra.Command, []string) error { //nolint:gocyclo
37+
// NOTE(khos2ow): this function is over our cyclomatic complexity goal.
38+
// Be wary when adding branches, and look for functionality that could
39+
// be reasonably moved into an injected dependency.
40+
3541
return func(cmd *cobra.Command, args []string) error {
3642
formatter := cmd.Annotations["command"]
3743

@@ -71,6 +77,10 @@ func PreRunEFunc(config *Config) func(*cobra.Command, []string) error {
7177
return err
7278
}
7379

80+
if err := checkConstraint(config.Version, version.Short()); err != nil {
81+
return err
82+
}
83+
7484
// explicitly setting formatter to Config for non-root commands this
7585
// will effectively override formattter properties from config file
7686
// if 1) config file exists and 2) formatter is set and 3) explicitly
@@ -135,6 +145,24 @@ func RunEFunc(config *Config) func(*cobra.Command, []string) error {
135145
}
136146
}
137147

148+
func checkConstraint(versionRange string, currentVersion string) error {
149+
if versionRange == "" {
150+
return nil
151+
}
152+
153+
semver, err := goversion.NewSemver(currentVersion)
154+
if err != nil {
155+
return err
156+
}
157+
158+
constraint, err := goversion.NewConstraint(versionRange)
159+
if err != nil || !constraint.Check(semver) {
160+
return fmt.Errorf("current version: %s, constraints: '%s'", semver, constraint)
161+
}
162+
163+
return nil
164+
}
165+
138166
// writeContent to a Writer. This can either be os.Stdout or specific
139167
// file (e.g. README.md) if '--output-file' is provided.
140168
func writeContent(config *Config, content string) error {

internal/cli/run_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package cli
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestVersionConstraint(t *testing.T) {
10+
type tuple struct {
11+
constraint string
12+
version string
13+
}
14+
tests := map[string]struct {
15+
versions []tuple
16+
wantErr bool
17+
}{
18+
"NoRange": {
19+
versions: []tuple{
20+
{"", "1.2.3"},
21+
},
22+
wantErr: false,
23+
},
24+
"ValidConstraint": {
25+
versions: []tuple{
26+
{">= 1.0, < 1.2", "1.1.5"},
27+
{"= 1.0", "1.0.0"},
28+
{"1.0", "1.0.0"},
29+
{">= 1.0", "1.2.3"},
30+
{"~> 1.0", "1.1"},
31+
{"~> 1.0", "1.2.3"},
32+
{"~> 1.0.0", "1.0.7"},
33+
{"~> 1.0.7", "1.0.7"},
34+
{"~> 1.0.7", "1.0.8"},
35+
{"~> 2.1.0-a", "2.1.0-beta"},
36+
{">= 2.1.0-a", "2.1.0-beta"},
37+
{">= 2.1.0-a", "2.1.1"},
38+
{">= 2.1.0-a", "2.1.0"},
39+
{"<= 2.1.0-a", "2.0.0"},
40+
},
41+
wantErr: false,
42+
},
43+
"MalformedCurrent": {
44+
versions: []tuple{
45+
{"> 1.0", "1.2.x"},
46+
},
47+
wantErr: true,
48+
},
49+
"InvalidConstraint": {
50+
versions: []tuple{
51+
{"< 1.0, < 1.2", "1.1.5"},
52+
{"> 1.1, <= 1.2", "1.2.3"},
53+
{"> 1.2, <= 1.1", "1.2.3"},
54+
{"= 1.0", "1.1.5"},
55+
{"~> 1.0", "2.0"},
56+
{"~> 1.0.0", "1.2.3"},
57+
{"~> 1.0.0", "1.1.0"},
58+
{"~> 1.0.7", "1.0.4"},
59+
{"~> 2.0", "2.1.0-beta"},
60+
{"~> 2.1.0-a", "2.2.0"},
61+
{"~> 2.1.0-a", "2.1.0"},
62+
{"~> 2.1.0-a", "2.2.0-alpha"},
63+
{"> 2.0", "2.1.0-beta"},
64+
{">= 2.1.0-a", "2.1.1-beta"},
65+
{">= 2.0.0", "2.1.0-beta"},
66+
{">= 2.1.0-a", "2.1.1-beta"},
67+
},
68+
wantErr: true,
69+
},
70+
}
71+
for name, tt := range tests {
72+
t.Run(name, func(t *testing.T) {
73+
assert := assert.New(t)
74+
75+
for _, v := range tt.versions {
76+
err := checkConstraint(v.constraint, v.version)
77+
78+
if tt.wantErr {
79+
assert.NotNil(err)
80+
} else {
81+
assert.Nil(err)
82+
}
83+
}
84+
})
85+
}
86+
}

internal/version/version.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ func init() {
4343
}
4444
}
4545

46+
// Short return the version of the binary
47+
func Short() string {
48+
return version
49+
}
50+
4651
// Full return the full version of the binary including commit hash and build date
4752
func Full() string {
4853
if !strings.HasSuffix(version, commitHash) {

0 commit comments

Comments
 (0)