Skip to content

Commit

Permalink
Fix missing fields in show command (#315)
Browse files Browse the repository at this point in the history
* show empty strings on selected fields

* add maybe.Optional[T] && maybe.Bool

* add Stringer to maybe.Bool

* update all references to *bool with maybe.Bool

* add test for BoolDecoder function

* add test on JSON marshaller/unmarshaller

* set maybe.Bool type to bool in jsonschema

* add a unit test for generating maybe.Bool json schema

* try running ajv tests on github action

* make schema test running under windows

* use nodejs 18
  • Loading branch information
creativeprojects authored Feb 12, 2024
1 parent 15004f9 commit 9eba431
Show file tree
Hide file tree
Showing 23 changed files with 405 additions and 77 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ jobs:
check-latest: true
cache: true

- name: Set up Node.js LTS for running JSON schema tests (using ajv)
uses: actions/setup-node@v4
with:
node-version: 18

- name: Build
run: make build
env:
Expand Down
6 changes: 2 additions & 4 deletions battery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@ import (

var errTest = errors.New("test error")

func TestNotRunningOnBattery(t *testing.T) {
battery, charge, err := IsRunningOnBattery()
func TestNoErrorIsRunningOnBattery(t *testing.T) {
_, _, err := IsRunningOnBattery()
assert.NoError(t, err)
assert.False(t, battery)
assert.Zero(t, charge)
}

func TestIsFatalError(t *testing.T) {
Expand Down
2 changes: 2 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/creativeprojects/clog"
"github.com/creativeprojects/resticprofile/constants"
"github.com/creativeprojects/resticprofile/filesearch"
"github.com/creativeprojects/resticprofile/util/maybe"
"github.com/creativeprojects/resticprofile/util/templates"
"github.com/mitchellh/mapstructure"
"github.com/spf13/viper"
Expand Down Expand Up @@ -42,6 +43,7 @@ type Config struct {
var (
configOption = viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
mapstructure.StringToTimeDurationHookFunc(),
maybe.BoolDecoder(),
confidentialValueDecoder(),
))

Expand Down
26 changes: 11 additions & 15 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"testing"
"time"

"github.com/creativeprojects/resticprofile/util/maybe"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -198,14 +199,9 @@ profile:
}

func TestBoolPointer(t *testing.T) {
boolPointer := func(value bool) *bool {
output := &value
return output
}

fixtures := []struct {
testTemplate
continueOnError *bool
continueOnError maybe.Bool
}{
{
testTemplate: testTemplate{
Expand All @@ -217,7 +213,7 @@ version = 2
profiles = []
`,
},
continueOnError: nil,
continueOnError: maybe.Bool{},
},
{
testTemplate: testTemplate{
Expand All @@ -229,7 +225,7 @@ groups:
profiles: []
`,
},
continueOnError: nil,
continueOnError: maybe.Bool{},
},
{
testTemplate: testTemplate{
Expand All @@ -245,7 +241,7 @@ groups:
}
`,
},
continueOnError: nil,
continueOnError: maybe.Bool{},
},
{
testTemplate: testTemplate{
Expand All @@ -258,7 +254,7 @@ profiles = []
continue-on-error = true
`,
},
continueOnError: boolPointer(true),
continueOnError: maybe.True(),
},
{
testTemplate: testTemplate{
Expand All @@ -271,7 +267,7 @@ groups:
continue-on-error: true
`,
},
continueOnError: boolPointer(true),
continueOnError: maybe.True(),
},
{
testTemplate: testTemplate{
Expand All @@ -288,7 +284,7 @@ groups:
}
`,
},
continueOnError: boolPointer(true),
continueOnError: maybe.True(),
},
{
testTemplate: testTemplate{
Expand All @@ -301,7 +297,7 @@ profiles = []
continue-on-error = false
`,
},
continueOnError: boolPointer(false),
continueOnError: maybe.False(),
},
{
testTemplate: testTemplate{
Expand All @@ -314,7 +310,7 @@ groups:
continue-on-error: false
`,
},
continueOnError: boolPointer(false),
continueOnError: maybe.False(),
},
{
testTemplate: testTemplate{
Expand All @@ -331,7 +327,7 @@ groups:
}
`,
},
continueOnError: boolPointer(false),
continueOnError: maybe.False(),
},
}

Expand Down
5 changes: 4 additions & 1 deletion config/config_v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"reflect"

"github.com/creativeprojects/resticprofile/constants"
"github.com/creativeprojects/resticprofile/util/maybe"
"github.com/mitchellh/mapstructure"
"github.com/spf13/viper"
)
Expand All @@ -28,11 +29,13 @@ import (
var (
configOptionV1 = viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
mapstructure.StringToTimeDurationHookFunc(),
maybe.BoolDecoder(),
confidentialValueDecoder(),
))

configOptionV1HCL = viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
mapstructure.StringToTimeDurationHookFunc(),
maybe.BoolDecoder(),
confidentialValueDecoder(),
sliceOfMapsToMapHookFunc(),
))
Expand Down Expand Up @@ -70,7 +73,7 @@ func (c *Config) loadGroupsV1() (err error) {
c.groups[groupName] = Group{
Description: "",
Profiles: group,
ContinueOnError: nil,
ContinueOnError: maybe.Bool{},
}
}
}
Expand Down
12 changes: 10 additions & 2 deletions config/display.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@ import (
"io"
"strings"
"text/tabwriter"

"github.com/fatih/color"
)

const (
indent = " " // 4 spaces
)

var (
ansiBold = color.New(color.Bold).SprintFunc()
)

// Display is a temporary struct to display a config object to the console
type Display struct {
topLevel string
Expand All @@ -30,6 +36,7 @@ func (d *Display) addEntry(stack []string, key string, values []string) {
entry := Entry{
section: strings.Join(stack, "."), // in theory we should only have zero or one level, but don't fail if we get more
key: key,
keyOnly: false,
values: values,
}
d.entries = append(d.entries, entry)
Expand All @@ -41,9 +48,10 @@ func (d *Display) addKeyOnlyEntry(stack []string, key string) {
}

func (d *Display) Flush() {
tabWriter := tabwriter.NewWriter(d.writer, 0, 2, 2, ' ', 0)
const minWidth, tabWidth, padding = 0, 2, 2
tabWriter := tabwriter.NewWriter(d.writer, minWidth, tabWidth, padding, ' ', 0)
// title
fmt.Fprintf(tabWriter, "%s:\n", d.topLevel)
fmt.Fprintf(tabWriter, "%s:\n", ansiBold(d.topLevel))
section := ""
prefix := indent
for _, entry := range d.entries {
Expand Down
10 changes: 3 additions & 7 deletions config/flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,8 @@ import (
)

var (
emptyStringArray []string
)

func init() {
emptyStringArray = make([]string, 0)
}
)

var allowedEmptyValueArgs = []string{
constants.ParameterKeepTag, // allows --keep-tag="" - means keep all with any assigned tag
Expand Down Expand Up @@ -68,8 +64,8 @@ func addArgsFromStruct(args *shell.Args, section any) {
}
}

func argAliasesFromStruct(section any) (aliases map[string]string) {
aliases = make(map[string]string)
func argAliasesFromStruct(section any) map[string]string {
aliases := make(map[string]string)
if t := util.ElementType(reflect.TypeOf(section)); t.Kind() == reflect.Struct {
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
Expand Down
8 changes: 5 additions & 3 deletions config/group.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package config

import "github.com/creativeprojects/resticprofile/util/maybe"

// Group of profiles
type Group struct {
Description string `mapstructure:"description" description:"Describe the group"`
Profiles []string `mapstructure:"profiles" description:"Names of the profiles belonging to this group"`
ContinueOnError *bool `mapstructure:"continue-on-error" default:"auto" description:"Continue with the next profile on a failure, overrides \"global.group-continue-on-error\""`
Description string `mapstructure:"description" description:"Describe the group"`
Profiles []string `mapstructure:"profiles" description:"Names of the profiles belonging to this group"`
ContinueOnError maybe.Bool `mapstructure:"continue-on-error" default:"auto" description:"Continue with the next profile on a failure, overrides \"global.group-continue-on-error\""`
}
12 changes: 12 additions & 0 deletions config/info_customizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/creativeprojects/resticprofile/constants"
"github.com/creativeprojects/resticprofile/restic"
"github.com/creativeprojects/resticprofile/util"
"github.com/creativeprojects/resticprofile/util/maybe"
)

// resticDescriptionReplacements removes or replaces misleading documentation fragments from restic man pages
Expand Down Expand Up @@ -123,6 +124,17 @@ func init() {
}
})

// Profile: special handling for maybe.Bool
maybeBoolType := reflect.TypeOf(maybe.Bool{})
registerPropertyInfoCustomizer(func(sectionName, propertyName string, property accessibleProperty) {
if field := property.field(); field != nil {
if util.ElementType(field.Type).AssignableTo(maybeBoolType) {
basic := property.basic().resetTypeInfo()
basic.mayBool = true
}
}
})

// Profile: deprecated sections (squash with deprecated, e.g. schedule in retention)
registerPropertyInfoCustomizer(func(sectionName, propertyName string, property accessibleProperty) {
if field := property.sectionField(nil); field != nil {
Expand Down
34 changes: 33 additions & 1 deletion config/info_customizer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ package config

import (
"fmt"
"github.com/stretchr/testify/require"
"reflect"
"strings"
"testing"

"github.com/stretchr/testify/require"

"github.com/creativeprojects/resticprofile/constants"
"github.com/creativeprojects/resticprofile/restic"
"github.com/creativeprojects/resticprofile/util/collect"
"github.com/creativeprojects/resticprofile/util/maybe"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -171,6 +173,36 @@ func TestConfidentialProperty(t *testing.T) {
}
}

func TestMaybeBoolProperty(t *testing.T) {
var testType = struct {
Simple maybe.Bool `mapstructure:"simple"`
}{}

set := propertySetFromType(reflect.TypeOf(testType))

assert.ElementsMatch(t, []string{"simple"}, set.Properties())
for _, name := range set.Properties() {
t.Run(name+"/before", func(t *testing.T) {
info := set.PropertyInfo(name)
require.True(t, info.CanBePropertySet())
assert.Equal(t, "Bool", info.PropertySet().TypeName())
assert.False(t, info.CanBeBool())
assert.False(t, info.IsMultiType())
})
}

customizeProperties("any", set.properties)

for _, name := range set.Properties() {
t.Run(name, func(t *testing.T) {
info := set.PropertyInfo(name)
assert.True(t, info.CanBeBool())
assert.False(t, info.CanBePropertySet())
assert.False(t, info.IsMultiType())
})
}
}

func TestDeprecatedSection(t *testing.T) {
var testType = struct {
ScheduleBaseSection `mapstructure:",squash" deprecated:"true"`
Expand Down
6 changes: 4 additions & 2 deletions config/jsonschema/schema_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build !ajv_test

package jsonschema

import (
Expand Down Expand Up @@ -67,7 +69,7 @@ func npmRunner(t *testing.T) npmRunnerFunc {
var npm npmRunnerFunc

func initNpmEnv(t *testing.T) {
if !testing.Short() && npm == nil {
if npm == nil {
npm = npmRunner(&testing.T{})
if npm(t, "list", "ajv") != nil {
t.Log("Installing AJV JSONSchema validator")
Expand Down Expand Up @@ -131,7 +133,7 @@ func TestJsonSchemaValidation(t *testing.T) {
require.NoError(t, v.ReadInConfig())

v.SetConfigType("json")
filename = path.Join(t.TempDir(), fmt.Sprintf(path.Base(filename)+".json"))
filename = filepath.Join(t.TempDir(), fmt.Sprintf(filepath.Base(filename)+".json"))
require.NoError(t, v.WriteConfigAs(filename))
return filename
}
Expand Down
Loading

0 comments on commit 9eba431

Please sign in to comment.