Skip to content
Open
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
79 changes: 70 additions & 9 deletions build/testing/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,20 @@ exit $?`,
return err
}

// Check export contains expected structure
// Note: We check parts separately since IDs are now included in export
if _, err = assertExec(ctx, container,
flipt("export"),
stdout(contains(expectedFliptYAML)),
stdout(contains("key: zUFtS7D0UyMeueYu")),
stdout(contains("name: UAoZRksg94r1iipa")),
stdout(contains("type: VARIANT_FLAG_TYPE")),
stdout(contains("segment: 08UoVJ96LhZblPEx")),
stdout(contains("key: 08UoVJ96LhZblPEx")),
stdout(contains("name: 2oS8SHbrxyFkRg1a")),
stdout(contains("type: STRING_COMPARISON_TYPE")),
stdout(contains("property: foo")),
stdout(contains("operator: eq")),
stdout(contains("value: baz")),
); err != nil {
return err
}
Expand All @@ -199,8 +210,16 @@ exit $?`,
return err
}

if !strings.Contains(contents, expectedFliptYAML) {
return fmt.Errorf("unexpected output: %q does not contain %q", contents, expectedFliptYAML)
// Check file contains expected content (checking parts since IDs are now included)
if !strings.Contains(contents, "key: zUFtS7D0UyMeueYu") ||
!strings.Contains(contents, "name: UAoZRksg94r1iipa") ||
!strings.Contains(contents, "type: VARIANT_FLAG_TYPE") ||
!strings.Contains(contents, "segment: 08UoVJ96LhZblPEx") ||
!strings.Contains(contents, "key: 08UoVJ96LhZblPEx") ||
!strings.Contains(contents, "type: STRING_COMPARISON_TYPE") ||
!strings.Contains(contents, "property: foo") ||
!strings.Contains(contents, "value: baz") {
return fmt.Errorf("exported file missing expected content")
}
}

Expand Down Expand Up @@ -239,9 +258,17 @@ exit $?`,
return err
}

// Check export with namespace contains expected structure
if _, err = assertExec(ctx, container,
flipt("export", "--namespaces", "foo"),
stdout(contains(expectedFliptYAML)),
stdout(contains("key: zUFtS7D0UyMeueYu")),
stdout(contains("name: UAoZRksg94r1iipa")),
stdout(contains("type: VARIANT_FLAG_TYPE")),
stdout(contains("segment: 08UoVJ96LhZblPEx")),
stdout(contains("key: 08UoVJ96LhZblPEx")),
stdout(contains("type: STRING_COMPARISON_TYPE")),
stdout(contains("property: foo")),
stdout(contains("value: baz")),
); err != nil {
return err
}
Expand All @@ -258,8 +285,16 @@ exit $?`,
return err
}

if !strings.Contains(contents, expectedFliptYAML) {
return fmt.Errorf("unexpected output: %q does not contain %q", contents, expectedFliptYAML)
// Check file contains expected content (checking parts since IDs are now included)
if !strings.Contains(contents, "key: zUFtS7D0UyMeueYu") ||
!strings.Contains(contents, "name: UAoZRksg94r1iipa") ||
!strings.Contains(contents, "type: VARIANT_FLAG_TYPE") ||
!strings.Contains(contents, "segment: 08UoVJ96LhZblPEx") ||
!strings.Contains(contents, "key: 08UoVJ96LhZblPEx") ||
!strings.Contains(contents, "type: STRING_COMPARISON_TYPE") ||
!strings.Contains(contents, "property: foo") ||
!strings.Contains(contents, "value: baz") {
return fmt.Errorf("exported file missing expected content")
}
}

Expand All @@ -280,9 +315,18 @@ exit $?`,
return err
}

// Check export contains expected namespaces and structure
if _, err := assertExec(ctx, container,
flipt("export", "--all-namespaces"),
stdout(contains(expectedYAMLStreamOutput)),
stdout(contains("namespace:\n key: default")),
stdout(contains("namespace:\n key: foo")),
stdout(contains("namespace:\n key: bar")),
stdout(contains("key: zUFtS7D0UyMeueYu")),
stdout(contains("type: VARIANT_FLAG_TYPE")),
stdout(contains("key: 08UoVJ96LhZblPEx")),
stdout(contains("type: STRING_COMPARISON_TYPE")),
stdout(contains("property: foo")),
stdout(contains("value: baz")),
); err != nil {
return err
}
Expand All @@ -305,9 +349,18 @@ exit $?`,
return err
}

// Check sorted export contains expected structure (checking key parts)
if _, err := assertExec(ctx, container,
flipt("export", "--namespace", "foo,bar", "--sort-by-key"),
stdout(contains(expectedFliptSortedOutput)),
stdout(contains("namespace:\n key: foo")),
stdout(contains("namespace:\n key: bar")),
stdout(contains("key: FLag2")),
stdout(contains("key: flag1")),
stdout(contains("key: flag2")),
stdout(contains("key: segment1")),
stdout(contains("key: segment2")),
stdout(contains("type: BOOLEAN_FLAG_TYPE")),
stdout(contains("type: VARIANT_FLAG_TYPE")),
); err != nil {
return err
}
Expand All @@ -330,9 +383,17 @@ exit $?`,
return err
}

// Check sorted all-namespaces export contains expected structure
if _, err := assertExec(ctx, container,
flipt("export", "--all-namespaces", "--sort-by-key"),
stdout(contains(expectedFliptSortedAllNamespacesOutput)),
stdout(contains("namespace:\n key: bar")),
stdout(contains("namespace:\n key: default")),
stdout(contains("namespace:\n key: foo")),
stdout(contains("key: FLag2")),
stdout(contains("key: flag1")),
stdout(contains("key: flag2")),
stdout(contains("key: segment1")),
stdout(contains("key: segment2")),
); err != nil {
return err
}
Expand Down
8 changes: 8 additions & 0 deletions build/testing/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"math/big"
"os"
"path"
"regexp"
"runtime"
"strconv"
"strings"
Expand Down Expand Up @@ -648,6 +649,13 @@ func importExport(ctx context.Context, _ *dagger.Client, base, flipt *dagger.Con
// remove line that starts with comment character '#' and newline after
generated = generated[strings.Index(generated, "\n")+2:]

// Remove ID fields from constraints and rollouts before comparison
// IDs are server-generated UUIDs and not stable across import/export
// Simply remove the id: line while preserving structure
idFieldRegex := regexp.MustCompile(`(?m)^(\s+)id: [a-f0-9-]+\n`)
expected = idFieldRegex.ReplaceAllString(expected, "")
generated = idFieldRegex.ReplaceAllString(generated, "")

diff := cmp.Diff(expected, generated)
if diff != "" {
fmt.Printf("Unexpected difference in %q exported output: \n", conf.name)
Expand Down
12 changes: 12 additions & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,11 @@ cloud.google.com/go/auth v0.12.1/go.mod h1:BFMu+TNpF3DmvfBO9ClqTR/SiqVIm7LukKF9m
cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q=
cloud.google.com/go/auth v0.14.0/go.mod h1:CYsoRL1PdiDuqeQpZE0bP2pnPrGqFcOkI0nldEQis+A=
cloud.google.com/go/auth v0.16.0/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4=
cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA=
cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA=
cloud.google.com/go/auth v0.16.4/go.mod h1:j10ncYwjX/g3cdX7GpEzsdM+d+ZNsXAbb6qXA7p1Y5M=
cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q=
cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I=
cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc=
Expand Down Expand Up @@ -301,6 +304,7 @@ cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1h
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
cloud.google.com/go/compute/metadata v0.5.1/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
cloud.google.com/go/contactcenterinsights v1.13.1/go.mod h1:/3Ji8Rr1GS6d+/MOwlXM2gZPSuvTKIFyf8OG+7Pe5r8=
cloud.google.com/go/contactcenterinsights v1.13.6/go.mod h1:mL+DbN3pMQGaAbDC4wZhryLciwSwHf5Tfk4Itr72Zyk=
cloud.google.com/go/contactcenterinsights v1.14.0/go.mod h1:APmWYHDN4sASnUBnXs4o68t1EUfnqadA53//CzXZ1xE=
Expand Down Expand Up @@ -865,6 +869,7 @@ cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502Jw
cloud.google.com/go/storage v1.49.0/go.mod h1:k1eHhhpLvrPjVGfo0mOUPEJ4Y2+a/Hv5PiwehZI9qGU=
cloud.google.com/go/storage v1.51.0/go.mod h1:YEJfu/Ki3i5oHC/7jyTgsGZwdQ8P9hqMqvpi5kRKGgc=
cloud.google.com/go/storage v1.53.0/go.mod h1:7/eO2a/srr9ImZW9k5uufcNahT2+fPb8w5it1i5boaA=
cloud.google.com/go/storage v1.56.0/go.mod h1:Tpuj6t4NweCLzlNbw9Z9iwxEkrSem20AetIeH/shgVU=
cloud.google.com/go/storagetransfer v1.10.5/go.mod h1:086WXPZlWXLfql+/nlmcc8ZzFWvITqfSGUQyMdf5eBk=
cloud.google.com/go/storagetransfer v1.10.10/go.mod h1:8+nX+WgQ2ZJJnK8e+RbK/zCXk8T7HdwyQAJeY7cEcm0=
cloud.google.com/go/storagetransfer v1.11.0/go.mod h1:arcvgzVC4HPcSikqV8D4h4PwrvGQHfKtbL4OwKPirjs=
Expand Down Expand Up @@ -1944,6 +1949,7 @@ github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBH
github.com/googleapis/gax-go/v2 v2.12.5/go.mod h1:BUDKcWo+RaKq5SC9vVYL0wLADa3VcfswbOMMRmB9H3E=
github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A=
github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk=
github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
Expand Down Expand Up @@ -3562,8 +3568,11 @@ google.golang.org/api v0.216.0/go.mod h1:K9wzQMvWi47Z9IU7OgdOofvZuw75Ge3PPITImZR
google.golang.org/api v0.224.0/go.mod h1:3V39my2xAGkodXy0vEqcEtkqgw2GtrFL5WuBZlCTCOQ=
google.golang.org/api v0.229.0/go.mod h1:wyDfmq5g1wYJWn29O22FDWN48P7Xcz0xz+LBpptYvB0=
google.golang.org/api v0.232.0/go.mod h1:p9QCfBWZk1IJETUdbTKloR5ToFdKbYh2fkjsUL6vNoY=
google.golang.org/api v0.234.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg=
google.golang.org/api v0.239.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
google.golang.org/api v0.242.0 h1:7Lnb1nfnpvbkCiZek6IXKdJ0MFuAZNAJKQfA1ws62xg=
google.golang.org/api v0.242.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
google.golang.org/api v0.246.0/go.mod h1:dMVhVcylamkirHdzEBAIQWUCgqY885ivNeZYd7VAVr8=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
Expand Down Expand Up @@ -3693,6 +3702,7 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250512202823-5a2f75b736a9/go.
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237/go.mod h1:ezi0AVyMKDWy5xAncvjLWH7UcLBB5n7y2fQ8MzjJcto=
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a/go.mod h1:a77HrdMjoeKbnd2jmgcWdaS++ZLZAEq3orIOAEIKiVw=
google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA=
google.golang.org/genproto/googleapis/api v0.0.0-20250721164621-a45f3dfb1074/go.mod h1:vYFwMYFbmA8vl6Z/krj/h7+U/AqpHknwJX4Uqgfyc7I=
google.golang.org/genproto/googleapis/api v0.0.0-20250728155136-f173205681a0/go.mod h1:8ytArBbtOy2xfht+y2fqKd5DRDJRUQhqbyEnQ4bDChs=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20240429193739-8cf5692501f6/go.mod h1:ULqtoQMxDLNRfW+pJbKA68wtIy1OiYjdIsJs3PMpzh8=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20240730163845-b1a4ccb954bf/go.mod h1:5/MT647Cn/GGhwTpXC7QqcaR5Cnee4v4MKCU1/nwnIQ=
Expand All @@ -3707,6 +3717,7 @@ google.golang.org/genproto/googleapis/bytestream v0.0.0-20250414145226-207652e42
google.golang.org/genproto/googleapis/bytestream v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20250603155806-513f23925822 h1:zWFRixYR5QlotL+Uv3YfsPRENIrQFXiGs+iwqel6fOQ=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20250603155806-513f23925822/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5/go.mod h1:zBEcrKX2ZOcEkHWxBPAIvYUWOKKMIhYcmNiUIu2ji3I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY=
Expand Down Expand Up @@ -3762,6 +3773,7 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
Expand Down
2 changes: 2 additions & 0 deletions internal/ext/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type Distribution struct {
}

type Rollout struct {
Id string `yaml:"id,omitempty" json:"id,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Segment *SegmentRule `yaml:"segment,omitempty" json:"segment,omitempty"`
Threshold *ThresholdRule `yaml:"threshold,omitempty" json:"threshold,omitempty"`
Expand All @@ -71,6 +72,7 @@ type Segment struct {
}

type Constraint struct {
Id string `yaml:"id,omitempty" json:"id,omitempty"`
Type string `yaml:"type,omitempty" json:"type,omitempty"`
Property string `yaml:"property,omitempty" json:"property,omitempty"`
Operator string `yaml:"operator,omitempty" json:"operator,omitempty"`
Expand Down
2 changes: 2 additions & 0 deletions internal/ext/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ func (e *Exporter) Export(ctx context.Context, encoding Encoding, w io.Writer) e

for _, r := range rollouts.Rules {
rollout := Rollout{
Id: r.Id,
Description: r.Description,
}

Expand Down Expand Up @@ -321,6 +322,7 @@ func (e *Exporter) Export(ctx context.Context, encoding Encoding, w io.Writer) e

for _, c := range s.Constraints {
segment.Constraints = append(segment.Constraints, &Constraint{
Id: c.Id,
Type: c.Type.String(),
Property: c.Property,
Operator: c.Operator,
Expand Down
39 changes: 17 additions & 22 deletions internal/ext/testdata/export.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,22 @@
"type": "VARIANT_FLAG_TYPE",
"description": "description",
"enabled": true,
"metadata": { "area": true, "label": "variant" },
"variants": [
{
"key": "variant1",
"name": "variant1",
"attachment": {
"pi": 3.141,
"answer": { "everything": 42 },
"happy": true,
"list": [1, 0, 2],
"name": "Niels",
"nothing": null,
"answer": { "everything": 42 },
"list": [1, 0, 2],
"object": { "currency": "USD", "value": 42.99 }
"object": { "currency": "USD", "value": 42.99 },
"pi": 3.141
}
},
{
"key": "foo",
"default": true
}
{ "default": true, "key": "foo" }
],
"rules": [
{
Expand All @@ -42,62 +40,59 @@
"operator": "AND_SEGMENT_OPERATOR"
}
}
],
"metadata": {
"label": "variant",
"area": true
}
]
},
{
"key": "flag2",
"name": "flag2",
"type": "BOOLEAN_FLAG_TYPE",
"description": "a boolean flag",
"enabled": false,
"metadata": { "area": 12, "label": "bool" },
"rollouts": [
{
"id": "1",
"description": "enabled for internal users",
"segment": { "key": "internal_users", "value": true }
},
{
"id": "2",
"description": "enabled for 50%",
"threshold": { "percentage": 50, "value": true }
}
],
"metadata": {
"label": "bool",
"area": 12
}
]
}
],
"segments": [
{
"key": "segment1",
"name": "segment1",
"match_type": "ANY_MATCH_TYPE",
"description": "description",
"constraints": [
{
"id": "1",
"type": "STRING_COMPARISON_TYPE",
"property": "foo",
"operator": "eq",
"value": "baz",
"description": "desc"
},
{
"id": "2",
"type": "STRING_COMPARISON_TYPE",
"property": "fizz",
"operator": "neq",
"value": "buzz",
"description": "desc"
}
]
],
"match_type": "ANY_MATCH_TYPE"
},
{
"key": "segment2",
"name": "segment2",
"match_type": "ANY_MATCH_TYPE",
"description": "description"
"description": "description",
"match_type": "ANY_MATCH_TYPE"
}
]
}
Loading
Loading