summaryrefslogtreecommitdiffstats
path: root/modules/git/pushoptions
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--modules/git/pushoptions/pushoptions.go113
-rw-r--r--modules/git/pushoptions/pushoptions_test.go125
2 files changed, 238 insertions, 0 deletions
diff --git a/modules/git/pushoptions/pushoptions.go b/modules/git/pushoptions/pushoptions.go
new file mode 100644
index 0000000..9709a8b
--- /dev/null
+++ b/modules/git/pushoptions/pushoptions.go
@@ -0,0 +1,113 @@
+// Copyright twenty-panda <twenty-panda@posteo.com>
+// SPDX-License-Identifier: MIT
+
+package pushoptions
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+type Key string
+
+const (
+ RepoPrivate = Key("repo.private")
+ RepoTemplate = Key("repo.template")
+ AgitTopic = Key("topic")
+ AgitForcePush = Key("force-push")
+ AgitTitle = Key("title")
+ AgitDescription = Key("description")
+
+ envPrefix = "GIT_PUSH_OPTION"
+ EnvCount = envPrefix + "_COUNT"
+ EnvFormat = envPrefix + "_%d"
+)
+
+type Interface interface {
+ ReadEnv() Interface
+ Parse(string) bool
+ Map() map[string]string
+
+ ChangeRepoSettings() bool
+
+ Empty() bool
+
+ GetBool(key Key, def bool) bool
+ GetString(key Key) (val string, ok bool)
+}
+
+type gitPushOptions map[string]string
+
+func New() Interface {
+ pushOptions := gitPushOptions(make(map[string]string))
+ return &pushOptions
+}
+
+func NewFromMap(o *map[string]string) Interface {
+ return (*gitPushOptions)(o)
+}
+
+func (o *gitPushOptions) ReadEnv() Interface {
+ if pushCount, err := strconv.Atoi(os.Getenv(EnvCount)); err == nil {
+ for idx := 0; idx < pushCount; idx++ {
+ _ = o.Parse(os.Getenv(fmt.Sprintf(EnvFormat, idx)))
+ }
+ }
+ return o
+}
+
+func (o *gitPushOptions) Parse(data string) bool {
+ key, value, found := strings.Cut(data, "=")
+ if !found {
+ value = "true"
+ }
+ switch Key(key) {
+ case RepoPrivate:
+ case RepoTemplate:
+ case AgitTopic:
+ case AgitForcePush:
+ case AgitTitle:
+ case AgitDescription:
+ default:
+ return false
+ }
+ (*o)[key] = value
+ return true
+}
+
+func (o gitPushOptions) Map() map[string]string {
+ return o
+}
+
+func (o gitPushOptions) ChangeRepoSettings() bool {
+ if o.Empty() {
+ return false
+ }
+ for _, key := range []Key{RepoPrivate, RepoTemplate} {
+ _, ok := o[string(key)]
+ if ok {
+ return true
+ }
+ }
+ return false
+}
+
+func (o gitPushOptions) Empty() bool {
+ return len(o) == 0
+}
+
+func (o gitPushOptions) GetBool(key Key, def bool) bool {
+ if val, ok := o[string(key)]; ok {
+ if b, err := strconv.ParseBool(val); err == nil {
+ return b
+ }
+ }
+ return def
+}
+
+func (o gitPushOptions) GetString(key Key) (string, bool) {
+ val, ok := o[string(key)]
+ return val, ok
+}
diff --git a/modules/git/pushoptions/pushoptions_test.go b/modules/git/pushoptions/pushoptions_test.go
new file mode 100644
index 0000000..49bf2d2
--- /dev/null
+++ b/modules/git/pushoptions/pushoptions_test.go
@@ -0,0 +1,125 @@
+// Copyright twenty-panda <twenty-panda@posteo.com>
+// SPDX-License-Identifier: MIT
+
+package pushoptions
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestEmpty(t *testing.T) {
+ options := New()
+ assert.True(t, options.Empty())
+ options.Parse(fmt.Sprintf("%v", RepoPrivate))
+ assert.False(t, options.Empty())
+}
+
+func TestToAndFromMap(t *testing.T) {
+ options := New()
+ options.Parse(fmt.Sprintf("%v", RepoPrivate))
+ actual := options.Map()
+ expected := map[string]string{string(RepoPrivate): "true"}
+ assert.EqualValues(t, expected, actual)
+ assert.EqualValues(t, expected, NewFromMap(&actual).Map())
+}
+
+func TestChangeRepositorySettings(t *testing.T) {
+ options := New()
+ assert.False(t, options.ChangeRepoSettings())
+ assert.True(t, options.Parse(fmt.Sprintf("%v=description", AgitDescription)))
+ assert.False(t, options.ChangeRepoSettings())
+
+ options.Parse(fmt.Sprintf("%v", RepoPrivate))
+ assert.True(t, options.ChangeRepoSettings())
+
+ options = New()
+ options.Parse(fmt.Sprintf("%v", RepoTemplate))
+ assert.True(t, options.ChangeRepoSettings())
+}
+
+func TestParse(t *testing.T) {
+ t.Run("no key", func(t *testing.T) {
+ options := New()
+
+ val, ok := options.GetString(RepoPrivate)
+ assert.False(t, ok)
+ assert.Equal(t, "", val)
+
+ assert.True(t, options.GetBool(RepoPrivate, true))
+ assert.False(t, options.GetBool(RepoPrivate, false))
+ })
+
+ t.Run("key=value", func(t *testing.T) {
+ options := New()
+
+ topic := "TOPIC"
+ assert.True(t, options.Parse(fmt.Sprintf("%v=%s", AgitTopic, topic)))
+ val, ok := options.GetString(AgitTopic)
+ assert.True(t, ok)
+ assert.Equal(t, topic, val)
+ })
+
+ t.Run("key=true", func(t *testing.T) {
+ options := New()
+
+ assert.True(t, options.Parse(fmt.Sprintf("%v=true", RepoPrivate)))
+ assert.True(t, options.GetBool(RepoPrivate, false))
+ assert.True(t, options.Parse(fmt.Sprintf("%v=TRUE", RepoTemplate)))
+ assert.True(t, options.GetBool(RepoTemplate, false))
+ })
+
+ t.Run("key=false", func(t *testing.T) {
+ options := New()
+
+ assert.True(t, options.Parse(fmt.Sprintf("%v=false", RepoPrivate)))
+ assert.False(t, options.GetBool(RepoPrivate, true))
+ })
+
+ t.Run("key", func(t *testing.T) {
+ options := New()
+
+ assert.True(t, options.Parse(fmt.Sprintf("%v", RepoPrivate)))
+ assert.True(t, options.GetBool(RepoPrivate, false))
+ })
+
+ t.Run("unknown keys are ignored", func(t *testing.T) {
+ options := New()
+
+ assert.True(t, options.Empty())
+ assert.False(t, options.Parse("unknown=value"))
+ assert.True(t, options.Empty())
+ })
+}
+
+func TestReadEnv(t *testing.T) {
+ t.Setenv(envPrefix+"_0", fmt.Sprintf("%v=true", AgitForcePush))
+ t.Setenv(envPrefix+"_1", fmt.Sprintf("%v", RepoPrivate))
+ t.Setenv(envPrefix+"_2", fmt.Sprintf("%v=equal=in string", AgitTitle))
+ t.Setenv(envPrefix+"_3", "not=valid")
+ t.Setenv(envPrefix+"_4", fmt.Sprintf("%v=description", AgitDescription))
+ t.Setenv(EnvCount, "5")
+
+ options := New().ReadEnv()
+
+ assert.True(t, options.GetBool(AgitForcePush, false))
+ assert.True(t, options.GetBool(RepoPrivate, false))
+ assert.False(t, options.GetBool(RepoTemplate, false))
+
+ {
+ val, ok := options.GetString(AgitTitle)
+ assert.True(t, ok)
+ assert.Equal(t, "equal=in string", val)
+ }
+ {
+ val, ok := options.GetString(AgitDescription)
+ assert.True(t, ok)
+ assert.Equal(t, "description", val)
+ }
+ {
+ _, ok := options.GetString(AgitTopic)
+ assert.False(t, ok)
+ }
+}