Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
SHELL = /bin/sh

VERSION=1.5.0
VERSION=1.6.0
BUILD=`git rev-parse HEAD`

LDFLAGS=-ldflags "-w -s \
Expand Down
60 changes: 60 additions & 0 deletions cmds/sync.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package cmds

import (
"github.com/Betterment/testtrack-cli/schema"
"github.com/Betterment/testtrack-cli/serializers"
"github.com/Betterment/testtrack-cli/servers"
"github.com/Betterment/testtrack-cli/splits"
"github.com/spf13/cobra"
)

var syncDoc = `
Sync the local schema TestTrack assignments with the remote production TestTrack assignments.
`

func init() {
rootCmd.AddCommand(syncCommand)
}

var syncCommand = &cobra.Command{
Use: "sync",
Short: "Sync TestTrack assignments with production",
Long: syncDoc,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
return Sync()
},
}

// Sync synchronizes the local schema TestTrack assignments with the remote production TestTrack assignments.
func Sync() error {
server, err := servers.New()
if err != nil {
return err
}

var splitRegistry serializers.RemoteRegistry
err = server.Get("api/v2/split_registry.json", &splitRegistry)
if err != nil {
return err
}

localSchema, err := schema.Read()
if err != nil {
return err
}

for ind, localSplit := range localSchema.Splits {
remoteSplit, exists := splitRegistry.Splits[localSplit.Name]
if exists {
remoteWeights := splits.Weights(remoteSplit.Weights)
localSchema.Splits[ind].Weights = remoteWeights.ToYAML()
}
}
Copy link
Contributor Author

@SirNeuman SirNeuman Jan 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically we unmarshal both remote JSON and local YAML files. Then we match split names, and whatever split names match we assign the "weights" from the JSON to the YAML file. Then we write and marshal the YAML object back.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there anything that can be reused from (or incorporated into) the existing schema.go module?

Copy link
Contributor Author

@SirNeuman SirNeuman Jan 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah i'm kinda learning this project and go as i go... i've refactored it to use schema write and read methods. Now i'm looking into whether i can use the "server" get method so we don't have to pass in the remote url as an argument, and also hopefully figure out how to clean some of this stuff around unmarshalling/marshalling the weights from json and casting them to serializable yaml values to write back to the file

Copy link
Contributor Author

@SirNeuman SirNeuman Jan 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smudge i think it's at a good place now for another review


if err := schema.Write(localSchema); err != nil {
return err
}

return nil
}
12 changes: 11 additions & 1 deletion serializers/serializers.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,22 @@ type SplitYAML struct {
Owner string `yaml:"owner,omitempty"`
}

// SplitJSON is is the JSON-marshalabe representation of a Split
// SplitJSON is the JSON-marshalabe representation of a Split
type SplitJSON struct {
Name string `json:"name"`
WeightingRegistry map[string]int `json:"weighting_registry"`
}

// RemoteRegistrySplit is the JSON-marshalable representation of a server-provided split configuration
type RemoteRegistrySplit struct {
Weights map[string]int `json:"weights"`
}

// RemoteRegistry is the JSON-marshalable representation of a server-provided split registry
type RemoteRegistry struct {
Splits map[string]RemoteRegistrySplit `json:"splits"`
}

// SplitRetirement is the JSON and YAML-marshalable representation of a SplitRetirement
type SplitRetirement struct {
Split string `json:"split"`
Expand Down