diff --git a/browser/flagr-ui/src/components/Flags.vue b/browser/flagr-ui/src/components/Flags.vue
index 8d7a77da..08f4d7d6 100644
--- a/browser/flagr-ui/src/components/Flags.vue
+++ b/browser/flagr-ui/src/components/Flags.vue
@@ -11,19 +11,26 @@
-
+
-
+
-
+ @command="onCommandDropdown"
+ @click.prevent="createFlag"
+ >
Create New Flag
-
+
+ Create Simple Boolean Flag
+
+
@@ -34,54 +41,41 @@
placeholder="Search a flag"
prefix-icon="el-icon-search"
v-model="searchTerm"
- v-focus>
-
+ v-focus
+ >
-
-
-
-
-
-
+ style="width: 100%"
+ >
+
+
+
-
+ width="200"
+ >
+ width="100"
+ >
{{scope.row.enabled ? 'on' : 'off'}}
+ disable-transitions
+ >{{ scope.row.enabled ? "on" : "off" }}
@@ -92,87 +86,87 @@
diff --git a/docs/api_docs/bundle.yaml b/docs/api_docs/bundle.yaml
index d58ae2bd..ae19bcb1 100644
--- a/docs/api_docs/bundle.yaml
+++ b/docs/api_docs/bundle.yaml
@@ -863,6 +863,9 @@ definitions:
key:
description: unique key representation of the flag
type: string
+ template:
+ description: template for flag creation
+ type: string
putFlagRequest:
type: object
properties:
diff --git a/go.sum b/go.sum
index b04432cf..d97fb690 100644
--- a/go.sum
+++ b/go.sum
@@ -21,6 +21,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/asaskevich/govalidator v0.0.0-20180315120708-ccb8e960c48f h1:y2hSFdXeA1y5z5f0vfNO0Dg5qVY036qzlz3Pds0B92o=
github.com/asaskevich/govalidator v0.0.0-20180315120708-ccb8e960c48f/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7 h1:irR1cO6eek3n5uquIVaRAsQmZnlsfPuHNz31cXo4eyk=
github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7/go.mod h1:LWMyo4iOLWXHGdBki7NIht1kHru/0wM179h+d3g8ATM=
github.com/avast/retry-go v2.2.0+incompatible h1:m+w7mVLWa/oKqX2xYqiEKQQkeGH8DDEXB/XnjS54Wyw=
github.com/avast/retry-go v2.2.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
@@ -28,11 +29,13 @@ github.com/aws/aws-sdk-go v1.15.32 h1:tb099RWtGbsXqOWDNKISRyufkdRWOYlXhE4XN0Jm3B
github.com/aws/aws-sdk-go v1.15.32/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/brandur/simplebox v0.0.0-20150921201729-84e9865bb03a h1:EMG9wk3iGM7WBAohiKenvpfyh1L5jv3snIMj3ffAMY8=
github.com/brandur/simplebox v0.0.0-20150921201729-84e9865bb03a/go.mod h1:8hDWkKEpFQwZcugC69PxsoNQMh+0/A3FzLCppp/yJZM=
github.com/bsm/ratelimit v2.0.0+incompatible h1:cV5yEqApIEkLumVjN65y/PlVrzJfCfz+b7BUQrNvCxA=
github.com/bsm/ratelimit v2.0.0+incompatible/go.mod h1:CKXgBlwczX35ERUvw2g6Nl+CT0QNd5m+xh3fpzjgbzo=
github.com/caarlos0/env v3.3.0+incompatible h1:jCfY0ilpzC2FFViyZyDKCxKybDESTwaR+ebh8zm6AOE=
github.com/caarlos0/env v3.3.0+incompatible/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y=
+github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 h1:6/yVvBsKeAw05IUj4AzvrxaCnDjN4nUqKjW9+w5wixg=
github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY=
@@ -47,12 +50,15 @@ github.com/denisenkom/go-mssqldb v0.0.0-20190418034912-35416408c946/go.mod h1:zA
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/eapache/go-resiliency v1.1.0 h1:1NtRmCAqadE2FN4ZcN6g90TP3uk8cg9rn9eNK2197aU=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
+github.com/evalphobia/logrus_sentry v0.4.6 h1:825MLGu+SW5H8hMXGeBI7TwX7vgJLd9hz0Eth1Mnp3o=
github.com/evalphobia/logrus_sentry v0.4.6/go.mod h1:pKcp+vriitUqu9KiWj/VRFbRfFNUwz95/UkgG8a6MNc=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@@ -85,11 +91,13 @@ github.com/go-openapi/swag v0.0.0-20180908172849-dd0dad036e67 h1:HSEYUsQFq79SfgU
github.com/go-openapi/swag v0.0.0-20180908172849-dd0dad036e67/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
github.com/go-openapi/validate v0.0.0-20180825180342-e0648ff40507 h1:WSEFLFs9bAbxJqnRnZYSYgkQtNjtCjq+/2ai5yR7/QA=
github.com/go-openapi/validate v0.0.0-20180825180342-e0648ff40507/go.mod h1:ve8xoSHgqBUifiKgaVbxLmOE0ckvH0oXfsJcnm6SIz0=
+github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gohttp/pprof v0.0.0-20141119085724-c9d246cbb3ba h1:OckY4Dk1WhEEEz4zYYMsXG5f6necMtGAyAs19vcpRXk=
github.com/gohttp/pprof v0.0.0-20141119085724-c9d246cbb3ba/go.mod h1:V97TX7IXWIioKfmy0IKnnBzsC1jRXP2VicslN9O8IIQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -98,6 +106,7 @@ github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
@@ -123,6 +132,7 @@ github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGAR
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/gorm v0.0.0-20180909231100-123d4f50ef8a h1:Z+fo5W6ecb0uvnWoEtzYoQKB8e9NFHT/19aB9ihFsLM=
github.com/jinzhu/gorm v0.0.0-20180909231100-123d4f50ef8a/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=
+github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a h1:eeaG9XMUvRBYXJi4pg1ZKM7nxc5AfXfojeLLW7O5J3k=
github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.0.0 h1:6WV8LvwPpDhKjo5U9O6b4+xdG/jTXNPwlDme/MTo8Ns=
github.com/jinzhu/now v1.0.0/go.mod h1:oHTiXerJ20+SfYcrdlBO7rzZRJWGwSTQ0iUY2jI6Gfc=
@@ -148,9 +158,11 @@ github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/meatballhat/negroni-logrus v0.0.0-20170801195057-31067281800f h1:V6GHkMOIsnpGDasS1iYiNxEYTY8TmyjQXEF8PqYkKQ8=
github.com/meatballhat/negroni-logrus v0.0.0-20170801195057-31067281800f/go.mod h1:Ylx55XGW4gjY7McWT0pgqU0aQquIOChDnYkOVbSuF/c=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
@@ -207,13 +219,16 @@ github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:s
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
+github.com/urfave/negroni v0.3.0 h1:PaXOb61mWeZJxc1Ji2xJjpVg9QfPo0rrB+lHyBxGNSU=
github.com/urfave/negroni v0.3.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
+github.com/yadvendar/negroni-newrelic-go-agent v0.0.0-20160803090806-3dc58758cb67 h1:BpDBAgffGUtOwUnYuFVOnl9PuDXW0X7bVw7NX/UdA4w=
github.com/yadvendar/negroni-newrelic-go-agent v0.0.0-20160803090806-3dc58758cb67/go.mod h1:eRmB4tpcIoEUfMNyiXTbnZtzfODhBhZB3BIWGDD+vLs=
github.com/zhouzhuojie/conditions v0.0.0-20190705160302-784df330cb87 h1:5pQTfWe/n9OvmwOamjhkePoT3dtJv0If1CXl3zkhSZg=
github.com/zhouzhuojie/conditions v0.0.0-20190705160302-784df330cb87/go.mod h1:Izhy98HD3MkfwGPz+p9ZV2JuqrpbHjaQbUq9iZHh+ZY=
diff --git a/pkg/handler/crud.go b/pkg/handler/crud.go
index ff330fd2..727e79e7 100644
--- a/pkg/handler/crud.go
+++ b/pkg/handler/crud.go
@@ -114,37 +114,6 @@ func (c *crud) FindFlags(params flag.FindFlagsParams) middleware.Responder {
return resp
}
-func (c *crud) CreateFlag(params flag.CreateFlagParams) middleware.Responder {
- f := &entity.Flag{}
- if params.Body != nil {
- f.Description = util.SafeString(params.Body.Description)
- f.CreatedBy = getSubjectFromRequest(params.HTTPRequest)
-
- key, err := entity.CreateFlagKey(params.Body.Key)
- if err != nil {
- return flag.NewCreateFlagDefault(400).WithPayload(
- ErrorMessage("cannot create flag. %s", err))
- }
- f.Key = key
- }
- err := getDB().Create(f).Error
- if err != nil {
- return flag.NewCreateFlagDefault(500).WithPayload(
- ErrorMessage("cannot create flag. %s", err))
- }
-
- resp := flag.NewCreateFlagOK()
- payload, err := e2rMapFlag(f)
- if err != nil {
- return flag.NewCreateFlagDefault(500).WithPayload(
- ErrorMessage("cannot map flag. %s", err))
- }
- resp.SetPayload(payload)
-
- entity.SaveFlagSnapshot(getDB(), f.ID, getSubjectFromRequest(params.HTTPRequest))
- return resp
-}
-
func (c *crud) GetFlag(params flag.GetFlagParams) middleware.Responder {
f := &entity.Flag{}
result := entity.PreloadSegmentsVariants(getDB()).First(f, params.FlagID)
diff --git a/pkg/handler/crud_flag_creation.go b/pkg/handler/crud_flag_creation.go
new file mode 100644
index 00000000..2f802e02
--- /dev/null
+++ b/pkg/handler/crud_flag_creation.go
@@ -0,0 +1,101 @@
+package handler
+
+import (
+ "github.com/checkr/flagr/pkg/entity"
+ "github.com/checkr/flagr/pkg/util"
+ "github.com/checkr/flagr/swagger_gen/restapi/operations/flag"
+ "github.com/go-openapi/runtime/middleware"
+ "github.com/jinzhu/gorm"
+)
+
+func (c *crud) CreateFlag(params flag.CreateFlagParams) middleware.Responder {
+ f := &entity.Flag{}
+ if params.Body != nil {
+ f.Description = util.SafeString(params.Body.Description)
+ f.CreatedBy = getSubjectFromRequest(params.HTTPRequest)
+
+ key, err := entity.CreateFlagKey(params.Body.Key)
+ if err != nil {
+ return flag.NewCreateFlagDefault(400).WithPayload(
+ ErrorMessage("cannot create flag. %s", err))
+ }
+ f.Key = key
+ }
+
+ tx := getDB().Begin()
+
+ if err := tx.Create(f).Error; err != nil {
+ tx.Rollback()
+ return flag.NewCreateFlagDefault(500).WithPayload(
+ ErrorMessage("cannot create flag. %s", err))
+ }
+
+ if params.Body.Template == "simple_boolean_flag" {
+ if err := LoadSimpleBooleanFlagTemplate(f, tx); err != nil {
+ tx.Rollback()
+ return flag.NewCreateFlagDefault(500).WithPayload(
+ ErrorMessage("cannot create flag. %s", err))
+ }
+ } else if params.Body.Template != "" {
+ return flag.NewCreateFlagDefault(400).WithPayload(
+ ErrorMessage("unknown value for template: %s", params.Body.Template))
+ }
+
+ err := tx.Commit().Error
+ if err != nil {
+ tx.Rollback()
+ return flag.NewCreateFlagDefault(500).WithPayload(ErrorMessage("%s", err))
+ }
+
+ resp := flag.NewCreateFlagOK()
+ payload, err := e2rMapFlag(f)
+ if err != nil {
+ return flag.NewCreateFlagDefault(500).WithPayload(
+ ErrorMessage("cannot map flag. %s", err))
+ }
+ resp.SetPayload(payload)
+
+ entity.SaveFlagSnapshot(getDB(), f.ID, getSubjectFromRequest(params.HTTPRequest))
+
+ return resp
+}
+
+// LoadSimpleBooleanFlagTemplate loads the simple boolean flag template into
+// a new flag. It creates a single segment, variant ('on'), and distribution.
+func LoadSimpleBooleanFlagTemplate(flag *entity.Flag, tx *gorm.DB) error {
+ // Create our default segment
+ s := &entity.Segment{}
+ s.FlagID = flag.ID
+ s.RolloutPercent = uint(100)
+ s.Rank = entity.SegmentDefaultRank
+
+ if err := tx.Create(s).Error; err != nil {
+ return err
+ }
+
+ // .. and our default Variant
+ v := &entity.Variant{}
+ v.FlagID = flag.ID
+ v.Key = "on"
+
+ if err := tx.Create(v).Error; err != nil {
+ return err
+ }
+
+ // .. and our default Distribution
+ d := &entity.Distribution{}
+ d.SegmentID = s.ID
+ d.VariantID = v.ID
+ d.VariantKey = v.Key
+ d.Percent = uint(100)
+
+ if err := tx.Create(d).Error; err != nil {
+ return err
+ }
+
+ s.Distributions = append(s.Distributions, *d)
+ flag.Variants = append(flag.Variants, *v)
+ flag.Segments = append(flag.Segments, *s)
+
+ return nil
+}
diff --git a/pkg/handler/crud_flag_creation_test.go b/pkg/handler/crud_flag_creation_test.go
new file mode 100644
index 00000000..67b97bd0
--- /dev/null
+++ b/pkg/handler/crud_flag_creation_test.go
@@ -0,0 +1,123 @@
+package handler
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/checkr/flagr/pkg/entity"
+ "github.com/checkr/flagr/pkg/util"
+ "github.com/checkr/flagr/swagger_gen/models"
+ "github.com/checkr/flagr/swagger_gen/restapi/operations/flag"
+ "github.com/go-openapi/runtime/middleware"
+ "github.com/prashantv/gostub"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestCrudCreateFlag(t *testing.T) {
+ var res middleware.Responder
+ db := entity.NewTestDB()
+ c := &crud{}
+
+ defer db.Close()
+ defer gostub.StubFunc(&getDB, db).Reset()
+
+ t.Run("it should be able to create one flag", func(t *testing.T) {
+ res = c.CreateFlag(flag.CreateFlagParams{
+ Body: &models.CreateFlagRequest{
+ Description: util.StringPtr("funny flag"),
+ Key: "some_random_flag_key",
+ },
+ })
+ assert.NotZero(t, res.(*flag.CreateFlagOK).Payload.ID)
+ assert.Equal(t, "some_random_flag_key", res.(*flag.CreateFlagOK).Payload.Key)
+
+ flagID := uint(res.(*flag.CreateFlagOK).Payload.ID)
+ segment := entity.Segment{FlagID: flagID}
+ db.First(&segment)
+ assert.Zero(t, segment.ID)
+ })
+
+ t.Run("it should be able to create simple_boolean_flag template", func(t *testing.T) {
+ res = c.CreateFlag(flag.CreateFlagParams{
+ Body: &models.CreateFlagRequest{
+ Description: util.StringPtr("simple flag"),
+ Key: "simple_boolean_flag_key",
+ Template: "simple_boolean_flag",
+ },
+ })
+ res := res.(*flag.CreateFlagOK)
+ assert.NotZero(t, res.Payload.ID)
+ assert.Equal(t, "simple_boolean_flag_key", res.Payload.Key)
+ assert.Equal(t, len(res.Payload.Variants), 1)
+ assert.Equal(t, len(res.Payload.Segments), 1)
+ assert.Equal(t, len(res.Payload.Segments[0].Distributions), 1)
+ flagID := uint(res.Payload.ID)
+ segment := entity.Segment{FlagID: flagID}
+ db.First(&segment)
+ assert.NotZero(t, segment.ID)
+ assert.Equal(t, segment.Rank, entity.SegmentDefaultRank)
+
+ variant := entity.Variant{FlagID: flagID}
+ db.First(&variant)
+ assert.NotZero(t, variant.ID)
+ assert.Equal(t, variant.Key, "on")
+
+ distribution := entity.Distribution{VariantID: variant.ID}
+ db.First(&distribution)
+ assert.NotZero(t, distribution.ID)
+ assert.Equal(t, distribution.Percent, uint(100))
+ assert.Equal(t, distribution.SegmentID, segment.ID)
+ assert.Equal(t, distribution.VariantKey, variant.Key)
+ })
+}
+
+func TestCrudCreateFlagWithFailures(t *testing.T) {
+ var res middleware.Responder
+ db := entity.NewTestDB()
+ c := &crud{}
+
+ defer db.Close()
+ defer gostub.StubFunc(&getDB, db).Reset()
+
+ t.Run("CreateFlag - got e2r MapFlag error", func(t *testing.T) {
+ defer gostub.StubFunc(&e2rMapFlag, nil, fmt.Errorf("e2r MapFlag error")).Reset()
+ res = c.CreateFlag(flag.CreateFlagParams{
+ Body: &models.CreateFlagRequest{
+ Description: util.StringPtr("funny flag"),
+ },
+ })
+ assert.NotZero(t, res.(*flag.CreateFlagDefault).Payload)
+ })
+
+ t.Run("CreateFlag - db generic error", func(t *testing.T) {
+ db.Error = fmt.Errorf("db generic error")
+ res = c.CreateFlag(flag.CreateFlagParams{
+ Body: &models.CreateFlagRequest{
+ Description: util.StringPtr("funny flag"),
+ },
+ })
+ assert.NotZero(t, res.(*flag.CreateFlagDefault).Payload)
+ db.Error = nil
+ })
+
+ t.Run("CreateFlag - invalid key error", func(t *testing.T) {
+ res = c.CreateFlag(flag.CreateFlagParams{
+ Body: &models.CreateFlagRequest{
+ Description: util.StringPtr(" flag with a space"),
+ Key: " 1-2-3", // invalid key
+ },
+ })
+ assert.NotZero(t, res.(*flag.CreateFlagDefault).Payload)
+ })
+
+ t.Run("CreateFlag - invalid template error", func(t *testing.T) {
+ res = c.CreateFlag(flag.CreateFlagParams{
+ Body: &models.CreateFlagRequest{
+ Description: util.StringPtr(" flag with a space"),
+ Key: "invalid_template",
+ Template: "invalid_template",
+ },
+ })
+ assert.NotZero(t, res.(*flag.CreateFlagDefault).Payload)
+ })
+}
diff --git a/pkg/handler/crud_test.go b/pkg/handler/crud_test.go
index 9c17dabe..8c7f4368 100644
--- a/pkg/handler/crud_test.go
+++ b/pkg/handler/crud_test.go
@@ -31,15 +31,11 @@ func TestCrudFlags(t *testing.T) {
assert.Len(t, res.(*flag.FindFlagsOK).Payload, 0)
})
- t.Run("it should be able to create one flag", func(t *testing.T) {
- res = c.CreateFlag(flag.CreateFlagParams{
- Body: &models.CreateFlagRequest{
- Description: util.StringPtr("funny flag"),
- Key: "some_random_flag_key",
- },
- })
- assert.NotZero(t, res.(*flag.CreateFlagOK).Payload.ID)
- assert.Equal(t, "some_random_flag_key", res.(*flag.CreateFlagOK).Payload.Key)
+ c.CreateFlag(flag.CreateFlagParams{
+ Body: &models.CreateFlagRequest{
+ Description: util.StringPtr("funny flag"),
+ Key: "flag_key_1",
+ },
})
t.Run("it should be able to find some flags after creation", func(t *testing.T) {
@@ -190,37 +186,6 @@ func TestCrudFlagsWithFailures(t *testing.T) {
db.Error = nil
})
- t.Run("CreateFlag - got e2r MapFlag error", func(t *testing.T) {
- defer gostub.StubFunc(&e2rMapFlag, nil, fmt.Errorf("e2r MapFlag error")).Reset()
- res = c.CreateFlag(flag.CreateFlagParams{
- Body: &models.CreateFlagRequest{
- Description: util.StringPtr("funny flag"),
- },
- })
- assert.NotZero(t, res.(*flag.CreateFlagDefault).Payload)
- })
-
- t.Run("CreateFlag - db generic error", func(t *testing.T) {
- db.Error = fmt.Errorf("db generic error")
- res = c.CreateFlag(flag.CreateFlagParams{
- Body: &models.CreateFlagRequest{
- Description: util.StringPtr("funny flag"),
- },
- })
- assert.NotZero(t, res.(*flag.CreateFlagDefault).Payload)
- db.Error = nil
- })
-
- t.Run("CreateFlag - invalid key error", func(t *testing.T) {
- res = c.CreateFlag(flag.CreateFlagParams{
- Body: &models.CreateFlagRequest{
- Description: util.StringPtr(" flag with a space"),
- Key: " 1-2-3", // invalid key
- },
- })
- assert.NotZero(t, res.(*flag.CreateFlagDefault).Payload)
- })
-
t.Run("PutFlag - try to update a non-existing flag", func(t *testing.T) {
res = c.PutFlag(flag.PutFlagParams{
FlagID: int64(99999),
diff --git a/swagger/index.yaml b/swagger/index.yaml
index cffa2b6d..caf10abc 100644
--- a/swagger/index.yaml
+++ b/swagger/index.yaml
@@ -143,6 +143,9 @@ definitions:
key:
description: unique key representation of the flag
type: string
+ template:
+ description: template for flag creation
+ type: string
putFlagRequest:
type: object
properties:
diff --git a/swagger_gen/models/create_flag_request.go b/swagger_gen/models/create_flag_request.go
index e76c23c5..a444e9aa 100644
--- a/swagger_gen/models/create_flag_request.go
+++ b/swagger_gen/models/create_flag_request.go
@@ -24,6 +24,9 @@ type CreateFlagRequest struct {
// unique key representation of the flag
Key string `json:"key,omitempty"`
+
+ // template for flag creation
+ Template string `json:"template,omitempty"`
}
// Validate validates this create flag request
diff --git a/swagger_gen/restapi/embedded_spec.go b/swagger_gen/restapi/embedded_spec.go
index 3127de7d..78d66df2 100644
--- a/swagger_gen/restapi/embedded_spec.go
+++ b/swagger_gen/restapi/embedded_spec.go
@@ -1227,6 +1227,10 @@ func init() {
"key": {
"description": "unique key representation of the flag",
"type": "string"
+ },
+ "template": {
+ "description": "template for flag creation",
+ "type": "string"
}
}
},
@@ -3000,6 +3004,10 @@ func init() {
"key": {
"description": "unique key representation of the flag",
"type": "string"
+ },
+ "template": {
+ "description": "template for flag creation",
+ "type": "string"
}
}
},