From 74bf5c544e4a47727785b08af90267219fe701f0 Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Mon, 12 Jun 2023 15:53:01 +0200 Subject: [PATCH] feat(apiops): integrate go-apiops --- CHANGELOG.md | 37 +++++++++ cmd/file.go | 24 ++++++ cmd/file_addplugins.go | 158 +++++++++++++++++++++++++++++++++++++ cmd/file_addtags.go | 89 +++++++++++++++++++++ cmd/file_listtags.go | 90 +++++++++++++++++++++ cmd/file_merge.go | 65 ++++++++++++++++ cmd/file_openapi2kong.go | 89 +++++++++++++++++++++ cmd/file_patch.go | 164 +++++++++++++++++++++++++++++++++++++++ cmd/file_removetags.go | 109 ++++++++++++++++++++++++++ cmd/root.go | 21 ++++- go.mod | 10 +++ go.sum | 49 +++++++++++- 12 files changed, 900 insertions(+), 5 deletions(-) create mode 100644 cmd/file.go create mode 100644 cmd/file_addplugins.go create mode 100644 cmd/file_addtags.go create mode 100644 cmd/file_listtags.go create mode 100644 cmd/file_merge.go create mode 100644 cmd/file_openapi2kong.go create mode 100644 cmd/file_patch.go create mode 100644 cmd/file_removetags.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bfce2a27..771d31dea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Table of Contents +- [v1.24.0](#v1240) - [v1.23.0](#v1230) - [v1.22.1](#v1221) - [v1.22.0](#v1220) @@ -60,6 +61,41 @@ - [v0.2.0](#v020) - [v0.1.0](#v010) +## [v1.24.0] + +> Release date: to-be-set + +### Added + +- Added a new command `file openapi2kong` that will generate a deck file from an OpenAPI + 3.0 spec. This is the replacement for the similar `inso` functionality. + The functionality is imported from the [go-apiops library](https://github.com/Kong/go-apiops). + [#939](https://github.com/Kong/deck/pull/939) +- Added a new command `file merge` that will merge multiple deck files. The files will not be + validated, which allows for working with incomplete or even invalid files in a pipeline. + The functionality is imported from the [go-apiops library](https://github.com/Kong/go-apiops). + [#939](https://github.com/Kong/deck/pull/939) +- Added a new command `file patch` for applying patches on top of a decK file. The patches can be + provided on the commandline, or via patch files. The deck file will not be + validated, which allows for working with incomplete or even invalid files in a pipeline. + The functionality is imported from the [go-apiops library](https://github.com/Kong/go-apiops). + [#939](https://github.com/Kong/deck/pull/939) +- Added a new commands `file add-tags/list-tags/remove-tags` to manage tags in a decK file. The deck file will not be + validated, which allows for working with incomplete or even invalid files in a pipeline. + The functionality is imported from the [go-apiops library](https://github.com/Kong/go-apiops). + [#939](https://github.com/Kong/deck/pull/939) +- Added a new command `file add-plugins` for adding plugins to a decK file. The plugins can be + provided on the commandline, or via config files. The deck file will not be + validated, which allows for working with incomplete or even invalid files in a pipeline. + The functionality is imported from the [go-apiops library](https://github.com/Kong/go-apiops). + [#939](https://github.com/Kong/deck/pull/939) + +### Fixes + + +### Misc + + ## [v1.23.0] > Release date: 2023/07/03 @@ -1264,6 +1300,7 @@ No breaking changes have been introduced in this release. Debut release of decK +[v1.24.0]: https://github.com/kong/deck/compare/v1.23.0...v1.24.0 [v1.23.0]: https://github.com/kong/deck/compare/v1.22.1...v1.23.0 [v1.22.1]: https://github.com/kong/deck/compare/v1.22.0...v1.22.1 [v1.22.0]: https://github.com/kong/deck/compare/v1.21.0...v1.22.0 diff --git a/cmd/file.go b/cmd/file.go new file mode 100644 index 000000000..50232e68c --- /dev/null +++ b/cmd/file.go @@ -0,0 +1,24 @@ +/* +Copyright © 2023 NAME HERE +*/ +package cmd + +import ( + "github.com/spf13/cobra" +) + +// +// +// Define the CLI data for the file sub-command +// +// + +func newAddFileCmd() *cobra.Command { + addFileCmd := &cobra.Command{ + Use: "file [sub-command]...", + Short: "Sub-command to host the decK file manipulation operations", + Long: `Sub-command to host the decK file manipulation operations`, + } + + return addFileCmd +} diff --git a/cmd/file_addplugins.go b/cmd/file_addplugins.go new file mode 100644 index 000000000..3d735c982 --- /dev/null +++ b/cmd/file_addplugins.go @@ -0,0 +1,158 @@ +/* +Copyright © 2023 NAME HERE +*/ +package cmd + +import ( + "fmt" + "log" + "strings" + + "github.com/kong/go-apiops/deckformat" + "github.com/kong/go-apiops/filebasics" + "github.com/kong/go-apiops/jsonbasics" + "github.com/kong/go-apiops/logbasics" + "github.com/kong/go-apiops/plugins" + "github.com/spf13/cobra" +) + +var ( + cmdAddPluginsOverwrite bool + cmdAddPluginsInputFilename string + cmdAddPluginOutputFilename string + cmdAddPluginOutputFormat string + cmdAddPluginsSelectors []string + cmdAddPluginsStrConfigs []string +) + +// Executes the CLI command "add-plugins" +func executeAddPlugins(cmd *cobra.Command, cfgFiles []string) error { + verbosity, _ := cmd.Flags().GetInt("verbose") + logbasics.Initialize(log.LstdFlags, verbosity) + + cmdAddPluginOutputFormat = strings.ToUpper(cmdAddPluginOutputFormat) + + var pluginConfigs []map[string]interface{} + { + for _, strConfig := range cmdAddPluginsStrConfigs { + pluginConfig, err := filebasics.Deserialize([]byte(strConfig)) + if err != nil { + return fmt.Errorf("failed to deserialize plugin config '%s'; %w", strConfig, err) + } + pluginConfigs = append(pluginConfigs, pluginConfig) + } + } + + var pluginFiles []plugins.DeckPluginFile + { + for _, filename := range cfgFiles { + var file plugins.DeckPluginFile + if err := file.ParseFile(filename); err != nil { + return fmt.Errorf("failed to parse plugin file '%s'; %w", filename, err) + } + pluginFiles = append(pluginFiles, file) + } + } + + // do the work: read/add-plugins/write + jsondata, err := filebasics.DeserializeFile(cmdAddPluginsInputFilename) + if err != nil { + return fmt.Errorf("failed to read input file '%s'; %w", cmdAddPluginsInputFilename, err) + } + yamlNode := jsonbasics.ConvertToYamlNode(jsondata) + + // apply CLI flags + plugger := plugins.Plugger{} + plugger.SetYamlData(yamlNode) + err = plugger.SetSelectors(cmdAddPluginsSelectors) + if err != nil { + return fmt.Errorf("failed to set selectors; %w", err) + } + err = plugger.AddPlugins(pluginConfigs, cmdAddPluginsOverwrite) + if err != nil { + return fmt.Errorf("failed to add plugins; %w", err) + } + yamlNode = plugger.GetYamlData() + + // apply plugin-files + for i, pluginFile := range pluginFiles { + err = pluginFile.Apply(yamlNode) + if err != nil { + return fmt.Errorf("failed to apply plugin file '%s'; %w", cfgFiles[i], err) + } + } + jsondata = plugger.GetData() + + trackInfo := deckformat.HistoryNewEntry("add-plugins") + trackInfo["input"] = cmdAddPluginsInputFilename + trackInfo["output"] = cmdAddPluginOutputFilename + trackInfo["overwrite"] = cmdAddPluginsOverwrite + if len(pluginConfigs) > 0 { + trackInfo["configs"] = pluginConfigs + } + if len(cfgFiles) > 0 { + trackInfo["pluginfiles"] = cfgFiles + } + trackInfo["selectors"] = cmdAddPluginsSelectors + deckformat.HistoryAppend(jsondata, trackInfo) + + return filebasics.WriteSerializedFile(cmdAddPluginOutputFilename, jsondata, cmdAddPluginOutputFormat) +} + +// +// +// Define the CLI data for the add-plugins command +// +// + +func newAddPluginsCmd() *cobra.Command { + addPluginsCmd := &cobra.Command{ + Use: "add-plugins [flags] [...plugin-files]", + Short: "Add plugins to objects in a decK file", + Long: `Add plugins to objects in a decK file. + +The plugins are added to all objects that match the selector expressions. If no +selectors are given, they will be added to the top-level 'plugins' array. + +The plugin-files have the following format (JSON or YAML) and are applied in the +order they are given; + + { "_format_version": "1.0", + "add-plugins": [ + { "selectors": [ + "$..services[*]" + ], + "overwrite": false, + "plugins": [ + { "name": "my-plugin", + "config": { + "my-property": "value" + } + } + ], + } + ] + } +`, + RunE: executeAddPlugins, + Args: cobra.MinimumNArgs(0), + } + + addPluginsCmd.Flags().StringVarP(&cmdAddPluginsInputFilename, "state", "s", "-", + "decK file to process. Use - to read from stdin") + addPluginsCmd.Flags().StringArrayVar(&cmdAddPluginsSelectors, "selector", []string{}, + "JSON path expression to select plugin-owning objects to add plugins to,\n"+ + "defaults to the top-level (selector '$'). Repeat for multiple selectors.") + addPluginsCmd.Flags().StringArrayVar(&cmdAddPluginsStrConfigs, "config", []string{}, + "JSON snippet containing the plugin configuration to add. Repeat to add\n"+ + "multiple plugins.") + addPluginsCmd.Flags().BoolVar(&cmdAddPluginsOverwrite, "overwrite", false, + "specifying this flag will overwrite plugins by the same name if they already\n"+ + "exist in an array. The default is to skip existing plugins.") + addPluginsCmd.Flags().StringVarP(&cmdAddPluginOutputFilename, "output-file", "o", "-", + "output file to write. Use - to write to stdout") + addPluginsCmd.Flags().StringVarP(&cmdAddPluginOutputFormat, "format", "", filebasics.OutputFormatYaml, + "output format: "+filebasics.OutputFormatJSON+" or "+filebasics.OutputFormatYaml) + + return addPluginsCmd +} diff --git a/cmd/file_addtags.go b/cmd/file_addtags.go new file mode 100644 index 000000000..7675fa8e5 --- /dev/null +++ b/cmd/file_addtags.go @@ -0,0 +1,89 @@ +/* +Copyright © 2023 NAME HERE +*/ +package cmd + +import ( + "fmt" + "log" + "strings" + + "github.com/kong/go-apiops/deckformat" + "github.com/kong/go-apiops/filebasics" + "github.com/kong/go-apiops/logbasics" + "github.com/kong/go-apiops/tags" + "github.com/spf13/cobra" +) + +var ( + cmdAddTagsInputFilename string + cmdAddTagsOutputFilename string + cmdAddTagsOutputFormat string + cmdAddTagsSelectors []string +) + +// Executes the CLI command "add-tags" +func executeAddTags(cmd *cobra.Command, tagsToAdd []string) error { + verbosity, _ := cmd.Flags().GetInt("verbose") + logbasics.Initialize(log.LstdFlags, verbosity) + + cmdAddTagsOutputFormat = strings.ToUpper(cmdAddTagsOutputFormat) + + // do the work: read/add-tags/write + data, err := filebasics.DeserializeFile(cmdAddTagsInputFilename) + if err != nil { + return fmt.Errorf("failed to read input file '%s'; %w", cmdAddTagsInputFilename, err) + } + + tagger := tags.Tagger{} + tagger.SetData(data) + err = tagger.SetSelectors(cmdAddTagsSelectors) + if err != nil { + return fmt.Errorf("failed to set selectors; %w", err) + } + err = tagger.AddTags(tagsToAdd) + if err != nil { + return fmt.Errorf("failed to add tags; %w", err) + } + data = tagger.GetData() + + trackInfo := deckformat.HistoryNewEntry("add-tags") + trackInfo["input"] = cmdAddTagsInputFilename + trackInfo["output"] = cmdAddTagsOutputFilename + trackInfo["tags"] = tagsToAdd + trackInfo["selectors"] = cmdAddTagsSelectors + deckformat.HistoryAppend(data, trackInfo) + + return filebasics.WriteSerializedFile(cmdAddTagsOutputFilename, data, cmdAddTagsOutputFormat) +} + +// +// +// Define the CLI data for the add-tags command +// +// + +func newAddTagsCmd() *cobra.Command { + addTagsCmd := &cobra.Command{ + Use: "add-tags [flags] tag [...tag]", + Short: "Add tags to objects in a decK file", + Long: `Add tags to objects in a decK file. + +The tags are added to all objects that match the selector expressions. If no +selectors are given, all Kong entities are tagged.`, + RunE: executeAddTags, + Args: cobra.MinimumNArgs(1), + } + + addTagsCmd.Flags().StringVarP(&cmdAddTagsInputFilename, "state", "s", "-", + "decK file to process. Use - to read from stdin") + addTagsCmd.Flags().StringArrayVar(&cmdAddTagsSelectors, "selector", []string{}, + "JSON path expression to select objects to add tags to,\n"+ + "defaults to all Kong entities (repeat for multiple selectors)") + addTagsCmd.Flags().StringVarP(&cmdAddTagsOutputFilename, "output-file", "o", "-", + "output file to write. Use - to write to stdout") + addTagsCmd.Flags().StringVarP(&cmdAddTagsOutputFormat, "format", "", filebasics.OutputFormatYaml, + "output format: "+filebasics.OutputFormatJSON+" or "+filebasics.OutputFormatYaml) + + return addTagsCmd +} diff --git a/cmd/file_listtags.go b/cmd/file_listtags.go new file mode 100644 index 000000000..d680ca8dc --- /dev/null +++ b/cmd/file_listtags.go @@ -0,0 +1,90 @@ +/* +Copyright © 2023 NAME HERE +*/ +package cmd + +import ( + "fmt" + "log" + "strings" + + "github.com/kong/go-apiops/filebasics" + "github.com/kong/go-apiops/logbasics" + "github.com/kong/go-apiops/tags" + "github.com/spf13/cobra" +) + +const PlainOutputFormat = "PLAIN" + +var ( + cmdListTagsInputFilename string + cmdListTagsOutputFilename string + cmdListTagsOutputFormat string + cmdListTagsSelectors []string +) + +// Executes the CLI command "list-tags" +func executeListTags(cmd *cobra.Command, _ []string) error { + verbosity, _ := cmd.Flags().GetInt("verbose") + logbasics.Initialize(log.LstdFlags, verbosity) + + cmdListTagsOutputFormat = strings.ToUpper(cmdListTagsOutputFormat) + + // do the work: read/list-tags/write + data, err := filebasics.DeserializeFile(cmdListTagsInputFilename) + if err != nil { + return fmt.Errorf("failed to read input file '%s'; %w", cmdListTagsInputFilename, err) + } + + tagger := tags.Tagger{} + tagger.SetData(data) + err = tagger.SetSelectors(cmdListTagsSelectors) + if err != nil { + return fmt.Errorf("failed to set selectors; %w", err) + } + list, err := tagger.ListTags() + if err != nil { + return fmt.Errorf("failed to list tags; %w", err) + } + + if cmdListTagsOutputFormat == PlainOutputFormat { + // return as a plain text format, unix style; line separated + result := []byte(strings.Join(list, "\n")) + return filebasics.WriteFile(cmdListTagsOutputFilename, result) + } + // return as yaml/json, create an object containing only a tags-array + result := make(map[string]interface{}) + result["tags"] = list + return filebasics.WriteSerializedFile(cmdListTagsOutputFilename, result, cmdListTagsOutputFormat) +} + +// +// +// Define the CLI data for the list-tags command +// +// + +func newListTagsCmd() *cobra.Command { + ListTagsCmd := &cobra.Command{ + Use: "list-tags [flags]", + Short: "List current tags from objects in a decK file", + Long: `List current tags from objects in a decK file. + +The tags will be collected from all objects that match the selector expressions. If no +selectors are given, all Kong entities will be scanned.`, + RunE: executeListTags, + Args: cobra.NoArgs, + } + + ListTagsCmd.Flags().StringVarP(&cmdListTagsInputFilename, "state", "s", "-", + "decK file to process. Use - to read from stdin") + ListTagsCmd.Flags().StringArrayVar(&cmdListTagsSelectors, "selector", []string{}, + "JSON path expression to select objects to scan for tags,\n"+ + "defaults to all Kong entities (repeat for multiple selectors)") + ListTagsCmd.Flags().StringVarP(&cmdListTagsOutputFilename, "output-file", "o", "-", + "output file to write. Use - to write to stdout") + ListTagsCmd.Flags().StringVarP(&cmdListTagsOutputFormat, "format", "", PlainOutputFormat, + "output format: "+filebasics.OutputFormatJSON+", "+filebasics.OutputFormatYaml+", or "+PlainOutputFormat) + + return ListTagsCmd +} diff --git a/cmd/file_merge.go b/cmd/file_merge.go new file mode 100644 index 000000000..ae53c6c31 --- /dev/null +++ b/cmd/file_merge.go @@ -0,0 +1,65 @@ +package cmd + +import ( + "log" + + "github.com/kong/go-apiops/deckformat" + "github.com/kong/go-apiops/filebasics" + "github.com/kong/go-apiops/logbasics" + "github.com/kong/go-apiops/merge" + "github.com/spf13/cobra" +) + +var ( + cmdMergeOutputFilename string + cmdMergeOutputFormat string +) + +// Executes the CLI command "merge" +func executeMerge(cmd *cobra.Command, args []string) error { + verbosity, _ := cmd.Flags().GetInt("verbose") + logbasics.Initialize(log.LstdFlags, verbosity) + + // do the work: read/merge + merged, info, err := merge.Files(args) + if err != nil { + return err + } + + historyEntry := deckformat.HistoryNewEntry("merge") + historyEntry["output"] = cmdMergeOutputFilename + historyEntry["files"] = info + deckformat.HistoryClear(merged) + deckformat.HistoryAppend(merged, historyEntry) + + return filebasics.WriteSerializedFile(cmdMergeOutputFilename, merged, cmdMergeOutputFormat) +} + +// +// +// Define the CLI data for the merge command +// +// + +func newMergeCmd() *cobra.Command { + mergeCmd := &cobra.Command{ + Use: "merge [flags] filename [...filename]", + Short: "Merge multiple decK files into one", + Long: `Merge multiple decK files into one. + +The files can be either json or yaml format. Will merge all top-level arrays by simply +concatenating them. Any other keys will be copied. The files will be processed in the order +provided. No checks on content will be done, eg. duplicates, nor any validations. + +If the input files are not compatible an error will be returned. Compatibility is +determined by the '_transform' and '_format_version' fields.`, + RunE: executeMerge, + Args: cobra.MinimumNArgs(1), + } + + mergeCmd.Flags().StringVarP(&cmdMergeOutputFilename, "output-file", "o", "-", + "output file to write. Use - to write to stdout") + mergeCmd.Flags().StringVarP(&cmdMergeOutputFormat, "format", "", "yaml", "output format: yaml or json") + + return mergeCmd +} diff --git a/cmd/file_openapi2kong.go b/cmd/file_openapi2kong.go new file mode 100644 index 000000000..abec59751 --- /dev/null +++ b/cmd/file_openapi2kong.go @@ -0,0 +1,89 @@ +package cmd + +import ( + "fmt" + "log" + "strings" + + "github.com/kong/go-apiops/deckformat" + "github.com/kong/go-apiops/filebasics" + "github.com/kong/go-apiops/logbasics" + "github.com/kong/go-apiops/openapi2kong" + "github.com/spf13/cobra" +) + +var ( + cmdO2KinputFilename string + cmdO2KoutputFilename string + cmdO2KdocName string + cmdO2KoutputFormat string + cmdO2KentityTags []string +) + +// Executes the CLI command "openapi2kong" +func executeOpenapi2Kong(cmd *cobra.Command, _ []string) error { + verbosity, _ := cmd.Flags().GetInt("verbose") + logbasics.Initialize(log.LstdFlags, verbosity) + + if len(cmdO2KentityTags) == 0 { + cmdO2KentityTags = nil + } + + cmdO2KoutputFormat = strings.ToUpper(cmdO2KoutputFormat) + + options := openapi2kong.O2kOptions{ + Tags: cmdO2KentityTags, + DocName: cmdO2KdocName, + } + + trackInfo := deckformat.HistoryNewEntry("openapi2kong") + trackInfo["input"] = cmdO2KinputFilename + trackInfo["output"] = cmdO2KoutputFilename + trackInfo["uuid-base"] = cmdO2KdocName + + // do the work: read/convert/write + content, err := filebasics.ReadFile(cmdO2KinputFilename) + if err != nil { + return err + } + result, err := openapi2kong.Convert(content, options) + if err != nil { + return fmt.Errorf("failed converting OpenAPI spec '%s'; %w", cmdO2KinputFilename, err) + } + deckformat.HistoryAppend(result, trackInfo) + return filebasics.WriteSerializedFile(cmdO2KoutputFilename, result, cmdO2KoutputFormat) +} + +// +// +// Define the CLI data for the openapi2kong command +// +// + +func newOpenapi2KongCmd() *cobra.Command { + openapi2kongCmd := &cobra.Command{ + Use: "openapi2kong", + Short: "Convert OpenAPI files to Kong's decK format", + Long: `Convert OpenAPI files to Kong's decK format. + +The example file has extensive annotations explaining the conversion +process, as well as all supported custom annotations (x-kong-... directives). +See: https://github.com/Kong/go-apiops/blob/main/docs/learnservice_oas.yaml`, + RunE: executeOpenapi2Kong, + Args: cobra.NoArgs, + } + + openapi2kongCmd.Flags().StringVarP(&cmdO2KinputFilename, "spec", "s", "-", + "OpenAPI spec file to process. Use - to read from stdin") + openapi2kongCmd.Flags().StringVarP(&cmdO2KoutputFilename, "output-file", "o", "-", + "output file to write. Use - to write to stdout") + openapi2kongCmd.Flags().StringP("format", "", "yaml", "output format: yaml or json") + openapi2kongCmd.Flags().StringVarP(&cmdO2KdocName, "uuid-base", "", "", + "the unique base-string for uuid-v5 generation of entity id's (if omitted\n"+ + "will use the root-level \"x-kong-name\" directive, or fall back to 'info.title')") + openapi2kongCmd.Flags().StringSliceVar(&cmdO2KentityTags, "select-tag", nil, + "select tags to apply to all entities (if omitted will use the \"x-kong-tags\"\n"+ + "directive from the file)") + + return openapi2kongCmd +} diff --git a/cmd/file_patch.go b/cmd/file_patch.go new file mode 100644 index 000000000..e32f58380 --- /dev/null +++ b/cmd/file_patch.go @@ -0,0 +1,164 @@ +package cmd + +import ( + "fmt" + "log" + "strings" + + "github.com/kong/go-apiops/deckformat" + "github.com/kong/go-apiops/filebasics" + "github.com/kong/go-apiops/jsonbasics" + "github.com/kong/go-apiops/logbasics" + "github.com/kong/go-apiops/patch" + "github.com/spf13/cobra" +) + +var ( + cmdPatchInputFilename string + cmdPatchOutputFilename string + cmdPatchOutputFormat string + cmdPatchValues []string + cmdPatchSelectors []string +) + +// Executes the CLI command "patch" +func executePatch(cmd *cobra.Command, args []string) error { + verbosity, _ := cmd.Flags().GetInt("verbose") + logbasics.Initialize(log.LstdFlags, verbosity) + + cmdPatchOutputFormat = strings.ToUpper(cmdPatchOutputFormat) + + var valuesPatch patch.DeckPatch + { + var err error + valuesPatch.SelectorSources = cmdPatchSelectors + valuesPatch.Values, valuesPatch.Remove, err = patch.ValidateValuesFlags(cmdPatchValues) + if err != nil { + return fmt.Errorf("failed parsing '--value' entry; %w", err) + } + } + + patchFiles := make([]patch.DeckPatchFile, 0) + { + for _, filename := range args { + var patchfile patch.DeckPatchFile + err := patchfile.ParseFile(filename) + if err != nil { + return fmt.Errorf("failed to parse '%s': %w", filename, err) + } + patchFiles = append(patchFiles, patchfile) + } + } + + trackInfo := deckformat.HistoryNewEntry("patch") + trackInfo["input"] = cmdPatchInputFilename + trackInfo["output"] = cmdPatchOutputFilename + if len(valuesPatch.Values) != 0 || len(valuesPatch.Remove) != 0 { + trackInfo["selector"] = valuesPatch.SelectorSources + } + if len(valuesPatch.Values) != 0 { + trackInfo["values"] = valuesPatch.Values + } + if len(valuesPatch.Remove) != 0 { + trackInfo["remove"] = valuesPatch.Remove + } + if len(args) != 0 { + trackInfo["patchfiles"] = args + } + + // do the work; read/patch/write + data, err := filebasics.DeserializeFile(cmdPatchInputFilename) + if err != nil { + return fmt.Errorf("failed to read input file '%s'; %w", cmdPatchInputFilename, err) + } + deckformat.HistoryAppend(data, trackInfo) // add before patching, so patch can operate on it + + yamlNode := jsonbasics.ConvertToYamlNode(data) + + if (len(valuesPatch.Values) + len(valuesPatch.Remove)) > 0 { + // apply selector + value flags + logbasics.Debug("applying value-flags") + err = valuesPatch.ApplyToNodes(yamlNode) + if err != nil { + return fmt.Errorf("failed to apply command-line values; %w", err) + } + } + + if len(args) > 0 { + // apply patch files + for i, patchFile := range patchFiles { + logbasics.Debug("applying patch-file", "file", i) + err := patchFile.Apply(yamlNode) + if err != nil { + return fmt.Errorf("failed to apply patch-file '%s'; %w", args[i], err) + } + } + } + + data = jsonbasics.ConvertToJSONobject(yamlNode) + + return filebasics.WriteSerializedFile(cmdPatchOutputFilename, data, cmdPatchOutputFormat) +} + +// +// +// Define the CLI data for the patch command +// +// + +func newPatchCmd() *cobra.Command { + patchCmd := &cobra.Command{ + Use: "patch [flags] [...patch-files]", + Short: "Apply patches on top of a decK file", + Long: `Apply patches on top of a decK file. + +The input file will be read, the patches will be applied, and if successful, written +to the output file. The patches can be specified by a '--selector' and one or more +'--value' tags, or via patch-files. + +When using '--selector' and '--values', the items will be selected by the 'selector' which is +a JSONpath query. From the array of nodes found, only the objects will be updated. +The 'values' will be applied on each of the JSONobjects returned by the 'selector'. + +The value part must be a valid JSON snippet, so make sure to use single/double quotes +appropriately. If the value is empty, the field will be removed from the object. +Examples: + --selector="$..services[*]" --value="read_timeout:10000" + --selector="$..services[*]" --value='_comment:"comment injected by patching"' + --selector="$..services[*]" --value='_ignore:["ignore1","ignore2"]' + --selector="$..services[*]" --value='_ignore:' --value='_comment:' + +The patch-files have the following format (JSON or Yaml) and can contain multiple +patches that will be applied in order; + + { "_format_version": "1.0", + "patches": [ + { "selectors": [ + "$..services[*]" + ], + "values": { + "read_timeout": 10000, + "_comment": "comment injected by patching" + }, + "remove": [ "_ignore" ] + } + ] + } +`, + RunE: executePatch, + } + + patchCmd.Flags().StringVarP(&cmdPatchInputFilename, "state", "s", "-", + "decK file to process. Use - to read from stdin") + patchCmd.Flags().StringVarP(&cmdPatchOutputFilename, "output-file", "o", "-", + "output file to write. Use - to write to stdout") + patchCmd.Flags().StringVarP(&cmdPatchOutputFormat, "format", "", "yaml", + "output format: yaml or json") + patchCmd.Flags().StringArrayVarP(&cmdPatchSelectors, "selector", "", []string{}, + "json-pointer identifying element to patch (can be specified more than once)") + patchCmd.Flags().StringArrayVarP(&cmdPatchValues, "value", "", []string{}, + "a value to set in the selected entry in format (can be specified more than once)") + patchCmd.MarkFlagsRequiredTogether("selector", "value") + + return patchCmd +} diff --git a/cmd/file_removetags.go b/cmd/file_removetags.go new file mode 100644 index 000000000..f65f7de64 --- /dev/null +++ b/cmd/file_removetags.go @@ -0,0 +1,109 @@ +/* +Copyright © 2023 NAME HERE +*/ +package cmd + +import ( + "fmt" + "log" + "strings" + + "github.com/kong/go-apiops/deckformat" + "github.com/kong/go-apiops/filebasics" + "github.com/kong/go-apiops/logbasics" + "github.com/kong/go-apiops/tags" + "github.com/spf13/cobra" +) + +var ( + cmdRemoveTagsKeepEmptyArrays bool + cmdRemoveTagsKeepOnlyTags bool + cmdRemoveTagsInputFilename string + cmdRemoveTagsOutputFilename string + cmdRemoveTagsOutputFormat string + cmdRemoveTagsSelectors []string +) + +// Executes the CLI command "remove-tags" +func executeRemoveTags(cmd *cobra.Command, tagsToRemove []string) error { + verbosity, _ := cmd.Flags().GetInt("verbose") + logbasics.Initialize(log.LstdFlags, verbosity) + + cmdRemoveTagsOutputFormat = strings.ToUpper(cmdRemoveTagsOutputFormat) + + if !cmdRemoveTagsKeepOnlyTags && len(tagsToRemove) == 0 { + return fmt.Errorf("no tags to remove") + } + + // do the work: read/remove-tags/write + data, err := filebasics.DeserializeFile(cmdRemoveTagsInputFilename) + if err != nil { + return fmt.Errorf("failed to read input file '%s'; %w", cmdRemoveTagsInputFilename, err) + } + + tagger := tags.Tagger{} + tagger.SetData(data) + err = tagger.SetSelectors(cmdRemoveTagsSelectors) + if err != nil { + return fmt.Errorf("failed to set selectors; %w", err) + } + if cmdRemoveTagsKeepOnlyTags { + err = tagger.RemoveUnknownTags(tagsToRemove, !cmdRemoveTagsKeepEmptyArrays) + } else { + err = tagger.RemoveTags(tagsToRemove, !cmdRemoveTagsKeepEmptyArrays) + } + if err != nil { + return fmt.Errorf("failed to remove tags; %w", err) + } + data = tagger.GetData() + + trackInfo := deckformat.HistoryNewEntry("remove-tags") + trackInfo["input"] = cmdRemoveTagsInputFilename + trackInfo["output"] = cmdRemoveTagsOutputFilename + trackInfo["tags"] = tagsToRemove + trackInfo["keep-empty-array"] = cmdRemoveTagsKeepEmptyArrays + trackInfo["selectors"] = cmdRemoveTagsSelectors + deckformat.HistoryAppend(data, trackInfo) + + return filebasics.WriteSerializedFile(cmdRemoveTagsOutputFilename, data, cmdRemoveTagsOutputFormat) +} + +// +// +// Define the CLI data for the remove-tags command +// +// + +func newRemoveTagsCmd() *cobra.Command { + removeTagsCmd := &cobra.Command{ + Use: "remove-tags [flags] tag [...tag]", + Short: "Remove tags from objects in a decK file", + Long: `Remove tags from objects in a decK file. + +The listed tags are removed from all objects that match the selector expressions. +If no selectors are given, all Kong entities will be selected.`, + RunE: executeRemoveTags, + Example: " # clear tags 'tag1' and 'tag2' from all services in file 'kong.yml'\n" + + " cat kong.yml | go-apiops remove-tags --selector='services[*]' tag1 tag2\n" + + "\n" + + " # clear all tags except 'tag1' and 'tag2' from the file 'kong.yml'\n" + + " cat kong.yml | go-apiops remove-tags --keep-only tag1 tag2", + } + + removeTagsCmd.Flags().BoolVar(&cmdRemoveTagsKeepEmptyArrays, "keep-empty-array", false, + "keep empty tag-arrays in output") + removeTagsCmd.Flags().BoolVar(&cmdRemoveTagsKeepOnlyTags, "keep-only", false, + "setting this flag will remove all tags except the ones listed\n"+ + "(if none are listed, all tags will be removed)") + removeTagsCmd.Flags().StringVarP(&cmdRemoveTagsInputFilename, "state", "s", "-", + "decK file to process. Use - to read from stdin") + removeTagsCmd.Flags().StringArrayVar(&cmdRemoveTagsSelectors, "selector", []string{}, + "JSON path expression to select objects to remove tags from,\n"+ + "defaults to all Kong entities (repeat for multiple selectors)") + removeTagsCmd.Flags().StringVarP(&cmdRemoveTagsOutputFilename, "output-file", "o", "-", + "output file to write. Use - to write to stdout") + removeTagsCmd.Flags().StringVarP(&cmdRemoveTagsOutputFormat, "format", "", filebasics.OutputFormatYaml, + "output format: "+filebasics.OutputFormatJSON+" or "+filebasics.OutputFormatYaml) + + return removeTagsCmd +} diff --git a/cmd/root.go b/cmd/root.go index a14748744..2e19fd2da 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -11,6 +11,7 @@ import ( "github.com/fatih/color" "github.com/kong/deck/utils" + "github.com/kong/go-apiops/deckformat" homedir "github.com/mitchellh/go-homedir" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -102,8 +103,7 @@ It can be used to export, import, or sync entities to Kong.`, rootCmd.PersistentFlags().Int("verbose", 0, "Enable verbose logging levels\n"+ - "Setting this value to 2 outputs all HTTP requests/responses\n"+ - "between decK and Kong.") + "Sets the verbosity level of log output (higher is more verbose).") viper.BindPFlag("verbose", rootCmd.PersistentFlags().Lookup("verbose")) @@ -214,6 +214,18 @@ It can be used to export, import, or sync entities to Kong.`, rootCmd.AddCommand(newConvertCmd()) rootCmd.AddCommand(newCompletionCmd()) rootCmd.AddCommand(newKonnectCmd()) + // commands from go-apiops library: + fileCmd := newAddFileCmd() + { + rootCmd.AddCommand(fileCmd) + fileCmd.AddCommand(newAddPluginsCmd()) + fileCmd.AddCommand(newAddTagsCmd()) + fileCmd.AddCommand(newListTagsCmd()) + fileCmd.AddCommand(newRemoveTagsCmd()) + fileCmd.AddCommand(newMergeCmd()) + fileCmd.AddCommand(newPatchCmd()) + fileCmd.AddCommand(newOpenapi2KongCmd()) + } return rootCmd } @@ -380,3 +392,8 @@ func extendHeaders(headers []string) []string { headers = append(headers, userAgentHeader) return headers } + +func init() { + // set version and commit hash to report in the go-apiops library + deckformat.ToolVersionSet("decK", VERSION, COMMIT) +} diff --git a/go.mod b/go.mod index 9cbc1e044..285a6596c 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.4 github.com/hexops/gotextdiff v1.0.3 github.com/imdario/mergo v0.3.16 + github.com/kong/go-apiops v0.1.17 github.com/kong/go-kong v0.44.0 github.com/mitchellh/go-homedir v1.1.0 github.com/shirou/gopsutil/v3 v3.23.6 @@ -35,9 +36,12 @@ require ( github.com/Kong/go-diff v1.2.2 // indirect github.com/adrg/strutil v0.2.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960 // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/getkin/kin-openapi v0.108.0 // indirect github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.1 // indirect @@ -50,6 +54,7 @@ require ( github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/invopop/yaml v0.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kong/semver/v4 v4.0.1 // indirect @@ -61,9 +66,13 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/mozillazg/go-slugify v0.2.0 // indirect + github.com/mozillazg/go-unidecode v0.2.0 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/satori/go.uuid v1.2.0 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect @@ -74,6 +83,7 @@ require ( github.com/tidwall/pretty v1.2.0 // indirect github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/tklauser/numcpus v0.6.0 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect diff --git a/go.sum b/go.sum index 8cbab3c6d..585292c44 100644 --- a/go.sum +++ b/go.sum @@ -66,6 +66,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960 h1:aRd8M7HJVZOqn/vhOzrGcQH0lNAMkqMn+pXUYkatmcA= +github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58= github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -77,21 +79,29 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/getkin/kin-openapi v0.108.0 h1:EYf0GtsKa4hQNIlplGS+Au7NEfGQ1F7MoHD2kcVevPQ= +github.com/getkin/kin-openapi v0.108.0/go.mod h1:QtwUNt0PAAgIIBEvFWYfB7dfngxtAaqCX1zYHMZDeK8= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-task/slim-sprig v2.20.0+incompatible h1:4Xh3bDzO29j4TWNOI+24ubc0vbVFMg2PMnXKxK54/CA= @@ -167,6 +177,7 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= @@ -188,6 +199,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -195,6 +208,8 @@ github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/invopop/yaml v0.1.0 h1:YW3WGUoJEXYfzWBjn00zIlrw7brGVD0fUKRYDPAPhrc= +github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -202,6 +217,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kong/go-apiops v0.1.17 h1:ChR7tW1sXSM0RNLFiPwvytksgO0rsoiMi/ipkXutj0A= +github.com/kong/go-apiops v0.1.17/go.mod h1:3P9DBGLcU6Gp4wo8z4xohcg8PMutBAknc54pLZoQtDs= github.com/kong/go-kong v0.44.0 h1:1x3w/TYdJjIZ6c1j9HiYP8755c923XN2O6j3kEaUkTA= github.com/kong/go-kong v0.44.0/go.mod h1:41Sot1N/n8UHBp+gE/6nOw3vuzoHbhMSyU/zOS7VzPE= github.com/kong/semver/v4 v4.0.1 h1:DIcNR8W3gfx0KabFBADPalxxsp+q/5COwIFkkhrFQ2Y= @@ -219,6 +236,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -235,9 +254,18 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/onsi/ginkgo v1.1.1-0.20150303023352-38caab951a9f h1:znMoXRti03ZIy/gaW5cl3EO2A5zqzHBKA6uMnrAQDE0= -github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk= -github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/mozillazg/go-slugify v0.2.0 h1:SIhqDlnJWZH8OdiTmQgeXR28AOnypmAXPeOTcG7b9lk= +github.com/mozillazg/go-slugify v0.2.0/go.mod h1:z7dPH74PZf2ZPFkyxx+zjPD8CNzRJNa1CGacv0gg8Ns= +github.com/mozillazg/go-unidecode v0.2.0 h1:vFGEzAH9KSwyWmXCOblazEWDh7fOkpmy/Z4ArmamSUc= +github.com/mozillazg/go-unidecode v0.2.0/go.mod h1:zB48+/Z5toiRolOZy9ksLryJ976VIwmDmpQ2quyt1aA= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.2 h1:uqH7bpe+ERSiDa34FDOF7RikN6RzXgduUF8yarlZp94= +github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -250,6 +278,10 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil/v3 v3.23.6 h1:5y46WPI9QBKBbK7EEccUPNXpJpNrvPuTD0O2zHEHT08= github.com/shirou/gopsutil/v3 v3.23.6/go.mod h1:j7QX50DrXYggrpN30W0Mo+I4/8U2UUIQrnrhqUeWrAU= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= @@ -298,6 +330,8 @@ github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+Kd github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= +github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= +github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -365,6 +399,7 @@ golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -420,6 +455,7 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -628,15 +664,22 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=