Documentation
¶
Overview ¶
Package gitops compares files kept in Git with what the platform holds, for `diff` and `apply --dry-run`, and moves whole projects between the two.
Index ¶
- Variables
- func ApplyProject(ctx context.Context, c *platform.Client, o ApplyOptions) error
- func Changes(diff string) int
- func Comparable(local, remote any) any
- func Diff(file string, local, remote *jsyaml.Map, always ...string) (string, error)
- func DiffFiles(ctx context.Context, c *platform.Client, k Kind, paths []string, ...) error
- func DiffProject(ctx context.Context, c *platform.Client, dir string) error
- func DryRun(ctx context.Context, c *platform.Client, k Kind, paths []string, ...) error
- func Export(ctx context.Context, c *platform.Client, o ExportOptions) error
- type ApplyOptions
- type ExportOptions
- type Kind
- type Result
- type State
Constants ¶
This section is empty.
Variables ¶
var Environment = Kind{ Name: "environment", ReadOnly: environment.ReadOnly, Identity: "id", Remote: func(ctx context.Context, c *platform.Client, local *jsyaml.Map) (string, *jsyaml.Map, error) { if id := str(local, "id"); id != "" { return byID(func(ctx context.Context, c *platform.Client, id openapi_types.UUID) (*http.Response, error) { return c.GetEnvironment(ctx, id) })(ctx, c, local) } name := str(local, "name") if name == "" { return "", nil, nil } var list struct { Environments []struct { ID string `json:"id"` Name string `json:"name"` } `json:"environments"` } resp, err := c.GetEnvironments(ctx, &api.GetEnvironmentsParams{Search: &name}) if _, err := platform.Decode(resp, err, &list); err != nil { return "", nil, err } for _, e := range list.Environments { if e.Name == name { u, _ := uuid(e.ID) remote, err := fetch(c.GetEnvironment(ctx, u)) return e.ID, remote, err } } return "", nil, nil }, }
var ErrDifferent = errors.New("files differ from the platform")
ErrDifferent ends `diff` with exit status 2 when files and platform disagree, so a pipeline can tell drift (2) from a failure (1).
var Experiment = Kind{ Name: "experiment", ReadOnly: []string{"version", "created", "createdBy", "edited", "editedBy"}, Identity: "key", Remote: func(ctx context.Context, c *platform.Client, local *jsyaml.Map) (string, *jsyaml.Map, error) { key := str(local, "key") if key == "" { externalID := str(local, "externalId") if externalID == "" { return "", nil, nil } var list struct { Experiments []struct { Key string `json:"key"` } `json:"experiments"` } ids := []string{externalID} resp, err := c.GetExperiments(ctx, &api.GetExperimentsParams{ExternalId: &ids}) if _, err := platform.Decode(resp, err, &list); err != nil { return "", nil, err } if len(list.Experiments) == 0 { return "", nil, nil } key = list.Experiments[0].Key } remote, err := fetch(c.GetExperiment(ctx, key)) return key, remote, err }, }
var Hub = Kind{ Name: "hub", ReadOnly: hub.ReadOnly, Identity: "id", Remote: byID(func(ctx context.Context, c *platform.Client, id openapi_types.UUID) (*http.Response, error) { return c.GetHubById(ctx, id) }), }
var Integrations = map[string]Kind{ integration.Webhook.Name: integrationKind(integration.Webhook, "webhook integration", allTargetAttributes), integration.Slack.Name: integrationKind(integration.Slack, "Slack integration", nil), integration.Preflight.Name: integrationKind(integration.Preflight, "preflight webhook", allTargetAttributes), integration.PreflightAction.Name: integrationKind(integration.PreflightAction, "preflight action integration", nil), }
Integrations are the kinds of integration by their command's name.
var PropertyDefinition = Kind{ Name: "property definition", ReadOnly: property.ReadOnly, Identity: "key", Remote: func(ctx context.Context, c *platform.Client, local *jsyaml.Map) (string, *jsyaml.Map, error) { key := str(local, "key") if key == "" { return "", nil, nil } remote, err := fetch(c.GetPropertyDefinition(ctx, key)) return key, remote, err }, }
var Schedule = Kind{ Name: "experiment schedule", ReadOnly: []string{"editedBy", "lastUpdated", "nextExecution"}, Defaults: map[string]any{"allowParallel": true}, Identity: "id", Remote: func(ctx context.Context, c *platform.Client, local *jsyaml.Map) (string, *jsyaml.Map, error) { id := str(local, "id") if id == "" { return "", nil, nil } remote, err := fetch(c.GetSchedules(ctx, id)) return id, remote, err }, }
var Service = Kind{ Name: "service", ReadOnly: []string{"version", "created", "createdBy", "edited", "editedBy"}, Defaults: map[string]any{"logoId": "service", "logoColor": "blue"}, Identity: "id", Remote: func(ctx context.Context, c *platform.Client, local *jsyaml.Map) (string, *jsyaml.Map, error) { id := str(local, "id") u, ok := uuid(id) if !ok { return "", nil, nil } remote, err := fetch(c.GetService(ctx, u)) return id, remote, err }, }
var ServiceProfile = Kind{ Name: "service profile", ReadOnly: []string{"version", "created", "createdBy", "edited", "editedBy", "defaultProfile"}, Defaults: map[string]any{"origin": "CUSTOM"}, Identity: "id", Remote: func(ctx context.Context, c *platform.Client, local *jsyaml.Map) (string, *jsyaml.Map, error) { id := str(local, "id") if u, ok := uuid(id); ok { remote, err := fetch(c.GetProfile(ctx, u)) return id, remote, err } name := str(local, "name") if name == "" { return "", nil, nil } type profile struct { ID string `json:"id"` Name string `json:"name"` } profiles, err := platform.AllPages[profile](func(page, size int32) (*http.Response, error) { return c.GetProfiles(ctx, &api.GetProfilesParams{Name: &name, Page: api.PageRequestAO{Page: &page, Size: &size}}) }) if err != nil { return "", nil, err } for _, p := range profiles { if p.Name == name { u, _ := uuid(p.ID) remote, err := fetch(c.GetProfile(ctx, u)) return p.ID, remote, err } } return "", nil, nil }, }
var Team = Kind{ Name: "team", ReadOnly: append(append([]string{"id"}, team.ReadOnly...), prefixed("members.", team.MemberReadOnly)...), Defaults: map[string]any{"allowedActions": []any{"wait", "service-validation"}, "managedBy": "MANUAL"}, Identity: "key", Remote: func(ctx context.Context, c *platform.Client, local *jsyaml.Map) (string, *jsyaml.Map, error) { key := str(local, "key") if key == "" { return "", nil, nil } remote, err := fetch(c.GetTeam(ctx, key)) return key, remote, err }, }
Team is matched by its key, as the platform upserts it. The id differs from one platform to the next, so it is neither exported nor compared: a team kept in Git matches its namesake anywhere.
Functions ¶
func ApplyProject ¶
ApplyProject applies every kind in a project, in the order of projectKinds.
func Comparable ¶
Comparable projects the platform's version of a document onto the file's: every field the file sets, and only those fields the file leaves out that hold something. The platform fills in defaults (false, empty lists and maps) that a file written by hand omits; reporting those would bury every real difference.
func Diff ¶
Diff is a unified diff from the platform's version to the file's, empty when they agree. Both sides are rendered as YAML the way `get` writes it. Fields in always are reported whenever the platform holds them and the file does not.
func DiffFiles ¶
func DiffFiles(ctx context.Context, c *platform.Client, k Kind, paths []string, recursive bool) error
DiffFiles prints how each file differs from the platform: a unified diff for changes, a line for files that would create something new.
func DiffProject ¶
DiffProject diffs every kind in a project, and reports drift once all were compared.
Types ¶
type ApplyOptions ¶
type ExportOptions ¶
type Kind ¶
type Kind struct {
// Name is what messages call it, "experiment" or "service profile".
Name string
// ReadOnly fields are reported by the platform but not part of the file. In
// "members.name", the field is dropped from each member.
ReadOnly []string
// Defaults are the values the platform gives fields a file leaves out, or leaves as
// an empty list or map. Holding exactly that, such a field is not a difference;
// holding anything else, applying the file would reset it, which is.
Defaults map[string]any
// Secrets are fields holding credentials, as integration.Kind names them. A mask in
// a file stands for whatever the platform holds, and no value is ever printed.
Secrets []string
// Identity is the field that names it on the platform. A file matched otherwise, by
// an externalId or a name, has none yet, which is not a difference.
Identity string
// Remote finds the platform's version of a file: its id and content, or nil when
// applying the file would create something new.
Remote func(ctx context.Context, c *platform.Client, local *jsyaml.Map) (string, *jsyaml.Map, error)
}
Kind is a type of file kept in Git and how to find its counterpart on the platform.