Skip to content

Commit

Permalink
feat: config file schema versioning
Browse files Browse the repository at this point in the history
  • Loading branch information
zaremba-tomasz committed Oct 3, 2023
1 parent 2627252 commit 1d9d69e
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 1 deletion.
4 changes: 4 additions & 0 deletions assets/versions/versions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"cliVersion": "v0.5.0",
"configFileSchemaVersion": "v1"
}
11 changes: 11 additions & 0 deletions src/cli/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/nearform/initium-cli/src/services/k8s"
"github.com/nearform/initium-cli/src/services/project"
"github.com/nearform/initium-cli/src/services/versions"
"github.com/nearform/initium-cli/src/utils/defaults"
"github.com/urfave/cli/v2"
)
Expand Down Expand Up @@ -83,6 +84,16 @@ func (c icli) InitConfigCMD(ctx *cli.Context) error {
config = config + next
}

versionFileContent, err := versions.LoadCliVersionsFileContent(c.Resources)
if err != nil {
return err
}
configFileSchemaVersion, err := versions.LoadCurrentCliConfigFileSchemaVersion(versionFileContent)
if err != nil {
return err
}
config = fmt.Sprintf("%s: %s\n", versions.ConfigFileSchemaVersionFlagName, configFileSchemaVersion) + config

if ctx.Bool(persistFlag) {
f, err := os.OpenFile(filepath.Join(ctx.String(projectDirectoryFlag), defaults.ConfigFile), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
Expand Down
5 changes: 4 additions & 1 deletion src/cli/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@ import (
)

func compareConfig(t *testing.T, appName string, registry string, writer io.Writer) {
configTemplate := fmt.Sprintf(`app-name: %s
currentConfigVersion := "v1"
configTemplate := fmt.Sprintf(`schema-version: %s
app-name: %s
cluster-endpoint: null
container-registry: %s
default-branch: main
dockerfile-name: null
registry-user: null
runtime-version: null
`,
currentConfigVersion,
appName,
registry,
)
Expand Down
64 changes: 64 additions & 0 deletions src/services/versions/versions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package versions

import (
"encoding/json"
"errors"
"gopkg.in/yaml.v2"
"io/fs"
"path"
)

const (
ConfigFileSchemaVersionFlagName = "schema-version"
InitialConfigFileSchemaVersion = "v1"
)

type VersionsFile struct {
CliVersion string `json:"cliVersion"`
ConfigFileSchemaVersion string `json:"configFileSchemaVersion"`
}

func LoadCliVersionsFileContent(resources fs.FS) ([]byte, error) {
bytes, err := fs.ReadFile(resources, path.Join("assets", "versions", "versions.json"))
if err != nil {
return nil, err
}

return bytes, nil
}

func LoadCurrentCliConfigFileSchemaVersion(cliVersionsFileContent []byte) (string, error) {
var versionsFile VersionsFile
err := json.Unmarshal(cliVersionsFileContent, &versionsFile)
if err != nil {
return "", err
}

return versionsFile.ConfigFileSchemaVersion, nil
}

func EnsureConfigFileSchemaVersionMatchesCli(clientConfigFileContent []byte, cliVersionsFileContent []byte) error {
currentCliConfigFileVersion, err := LoadCurrentCliConfigFileSchemaVersion(cliVersionsFileContent)
if err != nil {
return err
}

clientConfigFile := make(map[string]string)
err = yaml.Unmarshal(clientConfigFileContent, &clientConfigFile)
if err != nil {
return err
}

clientConfigFileVersion := ""
if clientConfigFile[ConfigFileSchemaVersionFlagName] == "" && currentCliConfigFileVersion == InitialConfigFileSchemaVersion {
clientConfigFileVersion = InitialConfigFileSchemaVersion
} else {
clientConfigFileVersion = clientConfigFile[ConfigFileSchemaVersionFlagName]
}

if currentCliConfigFileVersion != clientConfigFileVersion {
return errors.New("client config file schema version does not match the one expected by the CLI")
}

return nil
}
98 changes: 98 additions & 0 deletions src/services/versions/versions_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package versions

import (
"encoding/json"
"fmt"
"gopkg.in/yaml.v2"
"gotest.tools/v3/assert"
"testing"
)

type ClientConfigFile struct {
SchemaVersion string `yaml:"schema-version"`
AppName string `yaml:"app-name"`
}

func TestShouldReturnCurrentCliConfigFileSchemaVersion(t *testing.T) {
cliConfigFileSchemaVersion := InitialConfigFileSchemaVersion
bytes, err := getCliVersionsFileContent(cliConfigFileSchemaVersion)
if err != nil {
t.Fatalf(fmt.Sprintf("Error: %s", err))
}

schemaVersion, err := LoadCurrentCliConfigFileSchemaVersion(bytes)
if err != nil {
t.Fatalf(fmt.Sprintf("Error: %s", err))
}

assert.Assert(t, schemaVersion == cliConfigFileSchemaVersion, fmt.Sprintf("Expected: %s, got: %s", cliConfigFileSchemaVersion, schemaVersion))
}

func TestShouldBeBackwardCompatibleWhenClientConfigIsMissingSchemaVersion(t *testing.T) {
cliConfigFileSchemaVersion := InitialConfigFileSchemaVersion
cliVersionsFileContent, err := getCliVersionsFileContent(cliConfigFileSchemaVersion)
if err != nil {
t.Fatalf(fmt.Sprintf("Error: %s", err))
}

clientConfigFileContent, err := getClientConfigFileContent("")
if err != nil {
t.Fatalf(fmt.Sprintf("Error: %s", err))
}

err = EnsureConfigFileSchemaVersionMatchesCli(clientConfigFileContent, cliVersionsFileContent)
assert.NilError(t, err, "Expected error not present, got: %v", err)
}

func TestShouldAcceptTheClientConfigFileWhenSchemaVersionMatches(t *testing.T) {
cliConfigFileSchemaVersion := InitialConfigFileSchemaVersion
cliVersionsFileContent, err := getCliVersionsFileContent(cliConfigFileSchemaVersion)
if err != nil {
t.Fatalf(fmt.Sprintf("Error: %s", err))
}

clientConfigFileContent, err := getClientConfigFileContent(InitialConfigFileSchemaVersion)
if err != nil {
t.Fatalf(fmt.Sprintf("Error: %s", err))
}

err = EnsureConfigFileSchemaVersionMatchesCli(clientConfigFileContent, cliVersionsFileContent)
assert.NilError(t, err, "Expected error not present, got: %v", err)
}

func TestShouldReturnAnErrorWhenThereIsAMismatchBetweenSchemaVersions(t *testing.T) {
cliConfigFileSchemaVersion := "v2"
cliVersionsFileContent, err := getCliVersionsFileContent(cliConfigFileSchemaVersion)
if err != nil {
t.Fatalf(fmt.Sprintf("Error: %s", err))
}

clientConfigFileContent, err := getClientConfigFileContent(InitialConfigFileSchemaVersion)
if err != nil {
t.Fatalf(fmt.Sprintf("Error: %s", err))
}

err = EnsureConfigFileSchemaVersionMatchesCli(clientConfigFileContent, cliVersionsFileContent)
assert.Error(t, err, "client config file schema version does not match the one expected by the CLI")
}

func getCliVersionsFileContent(schemaVersion string) ([]byte, error) {
versionsFile := VersionsFile{
CliVersion: "v0.5.0",
ConfigFileSchemaVersion: schemaVersion,
}
return json.Marshal(versionsFile)
}

func getClientConfigFileContent(schemaVersion string) ([]byte, error) {
if schemaVersion == "" {
return yaml.Marshal(ClientConfigFile{
AppName: "initium-nodejs-demo-app",
})
} else {
return yaml.Marshal(ClientConfigFile{
SchemaVersion: schemaVersion,
AppName: "initium-nodejs-demo-app",
})
}
}

0 comments on commit 1d9d69e

Please sign in to comment.