Skip to content
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
2 changes: 1 addition & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ builds:
- env:
- CGO_ENABLED=0
ldflags:
- -X github.com/commitdev/zero/cmd.appVersion={{.Version}} -X github.com/commitdev/zero/cmd.appBuild={{.ShortCommit}}
- -X github.com/commitdev/zero/version.AppVersion={{.Version}} -X github.com/commitdev/zero/version.AppBuild={{.ShortCommit}}
archives:
- replacements:
darwin: Darwin
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
VERSION = 0.0.1
BUILD ?=$(shell git rev-parse --short HEAD)
PKG ?=github.com/commitdev/zero
BUILD_ARGS=-v -trimpath -ldflags=all="-X ${PKG}/cmd.appVersion=${VERSION} -X ${PKG}/cmd.appBuild=${BUILD}"
BUILD_ARGS=-v -trimpath -ldflags=all="-X ${PKG}/version.AppVersion=${VERSION} -X ${PKG}/version.AppBuild=${BUILD}"
Copy link
Contributor

Choose a reason for hiding this comment

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

For real releases this actually gets set by .goreleaser.yml, not the Makefile.


deps:
go mod download
Expand Down
10 changes: 3 additions & 7 deletions cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@ package cmd
import (
"fmt"

"github.com/commitdev/zero/version"
"github.com/spf13/cobra"
)

var (
appVersion = "SNAPSHOT"
appBuild = "SNAPSHOT"
)

func init() {
rootCmd.AddCommand(versionCmd)
}
Expand All @@ -19,7 +15,7 @@ var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version number of zero",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("version: %v\n", appVersion)
fmt.Printf("build: %v\n", appBuild)
fmt.Printf("version: %v\n", version.AppVersion)
fmt.Printf("build: %v\n", version.AppBuild)
},
}
19 changes: 11 additions & 8 deletions docs/module-definition.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
This file is the definition of a Zero module. It contains a list of all the required parameters to be able to prompt a user for choices during `zero init`, information about how to template the contents of the module during `zero create`, and the information needed for the module to run (`zero apply`).
It also declares the module's dependencies to determine the order of execution in relation to other modules.

| Parameters | type | Description |
|---------------|-----------------|--------------------------------------------------|
| `name` | string | Name of module |
| `description` | string | Description of the module |
| `template` | template | default settings for templating out the module |
| `author` | string | Author of the module |
| `icon` | string | Path to logo image |
| `parameters` | list(Parameter) | Parameters to prompt users |
| Parameters | type | Description |
|---------------|--------------------|--------------------------------------------------|
| `name` | string | Name of module |
| `description` | string | Description of the module |
| `template` | template | default settings for templating out the module |
| `author` | string | Author of the module |
| `icon` | string | Path to logo image |
| `parameters` | list(Parameter) | Parameters to prompt users |
| `zeroVersion` | string([go-semver])| Zero versions its compatible with |


### Template
Expand Down Expand Up @@ -77,3 +78,5 @@ For example if a user decide to not use circleCI, condition can be used to skip
| `type` | enum(string) | Currently supports [`regex`] |
| `value` | string | Regular expression string |
| `errorMessage` | string | Error message when validation fails |

[go-semver]: https://github.com/hashicorp/go-version/blob/master/README.md
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/google/go-cmp v0.3.1
github.com/google/uuid v1.1.1
github.com/hashicorp/go-getter v1.4.2-0.20200106182914-9813cbd4eb02
github.com/hashicorp/go-version v1.2.1
github.com/hashicorp/terraform v0.12.26
github.com/iancoleman/strcase v0.1.2
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PF
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
Expand Down
65 changes: 64 additions & 1 deletion internal/config/moduleconfig/module_config.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package moduleconfig

import (
"errors"
"fmt"
"io/ioutil"
"log"
"reflect"
"strings"

goVerson "github.com/hashicorp/go-version"
yaml "gopkg.in/yaml.v2"

"github.com/commitdev/zero/internal/config/projectconfig"
"github.com/commitdev/zero/internal/constants"
"github.com/commitdev/zero/pkg/util/flog"
"github.com/commitdev/zero/version"
"github.com/iancoleman/strcase"
)

Expand All @@ -20,11 +24,39 @@ type ModuleConfig struct {
Author string
DependsOn []string `yaml:"dependsOn,omitempty"`
TemplateConfig `yaml:"template"`
RequiredCredentials []string `yaml:"requiredCredentials"`
RequiredCredentials []string `yaml:"requiredCredentials"`
ZeroVersion VersionConstraints `yaml:"zeroVersion,omitempty"`
Parameters []Parameter
Conditions []Condition `yaml:"conditions,omitempty"`
}

func checkVersionAgainstConstrains(vc VersionConstraints, versionString string) bool {
v, err := goVerson.NewVersion(versionString)
if err != nil {
return false
}

return vc.Check(v)
}

// ValidateZeroVersion receives a module config, and returns whether the running zero's binary
// is compatible with the module
func ValidateZeroVersion(mc ModuleConfig) bool {
if mc.ZeroVersion.String() == "" {
return true
}

zeroVersion := version.AppVersion
flog.Debugf("Checking Zero version (%s) against %s", zeroVersion, mc.ZeroVersion)

// Unreleased versions or test runs, defaults to SNAPSHOT when not declared
if zeroVersion == "SNAPSHOT" {
return true
}

return checkVersionAgainstConstrains(mc.ZeroVersion, zeroVersion)
}

type Parameter struct {
Field string
Label string `yaml:"label,omitempty"`
Expand Down Expand Up @@ -60,6 +92,10 @@ type TemplateConfig struct {
OutputDir string `yaml:"outputDir"`
}

type VersionConstraints struct {
goVerson.Constraints
}

// A "nice" wrapper around findMissing()
func (cfg ModuleConfig) collectMissing() []string {
var missing []string
Expand Down Expand Up @@ -107,6 +143,13 @@ func LoadModuleConfig(filePath string) (ModuleConfig, error) {
log.Fatal("")
}

if !ValidateZeroVersion(config) {
constraint := config.ZeroVersion.Constraints.String()
errTpl := `Module(%s) requires Zero to be version %s. Your current Zero version is: %s
Please update your Zero version to %s.
Please check %s for available releases.`
return config, errors.New(fmt.Sprintf(errTpl, config.Name, constraint, version.AppVersion, constraint, constants.ZeroReleaseURL))
}
return config, nil
}

Expand Down Expand Up @@ -214,3 +257,23 @@ func SummarizeConditions(module ModuleConfig) []projectconfig.Condition {
}
return moduleConditions
}

// UnmarshalYAML Parses a version constraint string into go-version constraint during yaml parsing
func (semVer *VersionConstraints) UnmarshalYAML(unmarshal func(interface{}) error) error {
var versionString string
err := unmarshal(&versionString)
if err != nil {
return err
}
if versionString != "" {
constraints, constErr := goVerson.NewConstraint(versionString)
// If an invalid constraint is declared in a module
// instead of erroring out we just print a warning message
if constErr != nil {
flog.Warnf("Zero version constraint invalid format: %s", constErr)
}

*semVer = VersionConstraints{constraints}
}
return nil
}
1 change: 1 addition & 0 deletions internal/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ const (
MaxPnameLength = 16
RegexValidation = "regex"
FunctionValidation = "function"
ZeroReleaseURL = "https://github.com/commitdev/zero/releases"
)
71 changes: 71 additions & 0 deletions internal/module/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package module_test

import (
"errors"
"fmt"
"testing"

"github.com/commitdev/zero/internal/config/moduleconfig"
"github.com/stretchr/testify/assert"

"github.com/commitdev/zero/internal/module"
"github.com/commitdev/zero/version"
)

func TestGetSourceDir(t *testing.T) {
Expand All @@ -33,6 +35,7 @@ func TestParseModuleConfig(t *testing.T) {

t.Run("Loading module from source", func(t *testing.T) {
mod, _ = module.ParseModuleConfig(testModuleSource)
moduleconfig.ValidateZeroVersion(mod)

assert.Equal(t, "CI templates", mod.Name)
})
Expand Down Expand Up @@ -86,6 +89,74 @@ func TestParseModuleConfig(t *testing.T) {
assert.Equal(t, []string{"<%", "%>"}, mod.TemplateConfig.Delimiters)
})

t.Run("Parsing zero version constraints", func(t *testing.T) {
moduleConstraints := mod.ZeroVersion.Constraints.String()
assert.Equal(t, ">= 3.0.0, < 4.0.0", moduleConstraints)
})

t.Run("Should Fail against old zero version", func(t *testing.T) {
moduleConstraints := mod.ZeroVersion.Constraints.String()

// Mocking zero's version, testing against ">= 3.0.0, <= 4.0.0"
originalVersion := version.AppVersion
version.AppVersion = "2.0.0"
defer func() { version.AppVersion = originalVersion }()
// end of mock

isValid := moduleconfig.ValidateZeroVersion(mod)
assert.Equal(t, false, isValid, fmt.Sprintf("Version should satisfy %s", moduleConstraints))
})

t.Run("Should Fail against too new zero version", func(t *testing.T) {
moduleConstraints := mod.ZeroVersion.Constraints.String()

// Mocking zero's version, testing against ">= 3.0.0, <= 4.0.0"
originalVersion := version.AppVersion
version.AppVersion = "4.0.0"
defer func() { version.AppVersion = originalVersion }()
// end of mock

isValid := moduleconfig.ValidateZeroVersion(mod)
assert.Equal(t, false, isValid, fmt.Sprintf("Version should satisfy %s", moduleConstraints))
})

t.Run("Should validate against valid versions", func(t *testing.T) {
moduleConstraints := mod.ZeroVersion.Constraints.String()

// Mocking zero's version, testing against ">= 3.0.0, <= 4.0.0"
const newZeroVersion = "3.0.5"
originalVersion := version.AppVersion
version.AppVersion = newZeroVersion
defer func() { version.AppVersion = originalVersion }()
// end of mock

isValid := moduleconfig.ValidateZeroVersion(mod)
assert.Equal(t, true, isValid, fmt.Sprintf("Version should satisfy %s", moduleConstraints))
})

t.Run("default to SNAPSHOT version passes tests", func(t *testing.T) {
assert.Equal(t, "SNAPSHOT", version.AppVersion)
isValid := moduleconfig.ValidateZeroVersion(mod)
assert.Equal(t, true, isValid, "default test run should pass version constraint")
})

}

func TestModuleWithNoVersionConstraint(t *testing.T) {
testModuleSource := "../../tests/test_data/modules/no-version-constraint"
var mod moduleconfig.ModuleConfig
var err error

t.Run("Parsing Module with no version constraint", func(t *testing.T) {
mod, err = module.ParseModuleConfig(testModuleSource)
assert.Equal(t, "", mod.ZeroVersion.String())
assert.Nil(t, err)
})

t.Run("Should pass Validation if constraint not specified", func(t *testing.T) {
isValid := moduleconfig.ValidateZeroVersion(mod)
assert.Equal(t, true, isValid, "Module with no constraint should pass version validation")
})
}

func findParameter(params []moduleconfig.Parameter, field string) (moduleconfig.Parameter, error) {
Expand Down
1 change: 1 addition & 0 deletions tests/test_data/modules/ci/zero-module.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ description: "CI description"
author: "CI author"
icon: ""
thumbnail: ""
zeroVersion: ">= 3.0.0, < 4.0.0"

requiredCredentials:
- aws
Expand Down
19 changes: 19 additions & 0 deletions tests/test_data/modules/no-version-constraint/zero-module.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: "Test module"
description: "a module for testing, with no zero version requirement"
author: "Test module author"
icon: ""
thumbnail: ""

template:
delimiters:
- "<%"
- "%>"
inputDir: templates
outputDir: test-module-output

requiredCredentials:
- aws
- circleci
- github

parameters:
7 changes: 7 additions & 0 deletions version/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package version

// These values are overridden by makefile during build
var (
AppVersion = "SNAPSHOT"
AppBuild = "SNAPSHOT"
)