Skip to content

feat: add recipes#362

Draft
nieomylnieja wants to merge 28 commits into
mainfrom
add-recipes
Draft

feat: add recipes#362
nieomylnieja wants to merge 28 commits into
mainfrom
add-recipes

Conversation

@nieomylnieja

@nieomylnieja nieomylnieja commented Jul 31, 2025

Copy link
Copy Markdown
Collaborator

Motivation

Currently there's a lot of ways floating around for scripting with sloctl, even in the sloctl README.md we have a short "recipes" section.
Wouldn't it be nice to have a curated list of such recipes available in sloctl itself? Or have custom ones! Or share them with others!
I got you, let's define some sloctl recipes 😄

Summary

Example recipe in YAML format:

object-names:
  description: Fetch object names
  args: [get]
  example: |
    # Fetch SLO object names
    sloctl recipe object-names slo
  validators:
    atLeastArgs: [kind]
  jq: .[].metadata.name

Related changes

List related changes from other PRs (if any).

Testing

  • Describe how to check introduced code changes manually. Provide example invocations and applied YAML configs.
  • Take care of test coverage on unit and end-to-end levels.

Release Notes

If this change should be part of the Release Notes,
replace this entire paragraph with 1-3 sentences about the changes.
Otherwise, you MUST remove this section entirely.

Does this PR contain any breaking changes?
If so, add ## Breaking Changes header and list the introduced changes there.

This commit introduces jq filtering capabilities to the `sloctl` tool, enabling users to query and manipulate output data using jq syntax.

Key changes include:
- Integration of the `gojq` library for parsing and evaluating jq expressions.
- Addition of a new `ExpressionRunner` component to handle jq queries and output formatting.
- Updates to the `GetCmd` structure to include jq-related functionality.
- Modifications to the `printObjects` method to support conditional jq evaluation.
- Enhancements to the JSON printer to handle scalar values more effectively.
- Comprehensive unit tests for the jq functionality, covering various scenarios and edge cases.
- A new BATS test to validate jq filtering in the `get project` command.

These changes improve the flexibility and usability of the tool, allowing users to extract specific data from complex outputs.
The `jq` flag in the `ExpressionRunner` has been updated to include an alias `-q` for better usability. This change ensures
users can use either `--jq` or `-q` to specify their query expressions.

Additionally, the test suite has been updated to validate the functionality of both flag variants. The test for the `jq`
filter now iterates over both `--jq` and `-q` aliases, ensuring consistent behavior and output for both options.
The SLO filtering and counting commands have been updated to use `--jq` directly with `sloctl`, simplifying the syntax and improving readability.
This change removes the dependency on external tools like `yq` and streamlines the process for users.
- Updated `EvaluateAndPrint` in `jq.go` to return the evaluated value directly instead of the error object,
  ensuring better handling of halt errors with nil values.
- Modified `jsonScalarToString` in `json.go` to use `-1` precision for float formatting, allowing for more
  accurate representation of floating-point numbers without unnecessary truncation.
- Added new test cases in `printer_test.go` to validate the updated float formatting behavior and ensure
  proper handling of various scalar values, including integers, floats with no decimals, and large decimal floats.
Enhanced the `jsonScalarToString` method in the JSON printer to handle integer inputs.
Previously, the method only supported string and float64 types.
Now, integers are converted to their string representation using `strconv.Itoa`.
This commit removes the direct dependency on the `jq` package from the `GetCmd` structure and integrates its functionality into the `Printer` component. The `Printer` now handles `jq` expression evaluation internally, simplifying the `GetCmd` implementation and reducing redundancy.

Key changes:
- Removed `jq.ExpressionRunner` from `GetCmd` and its initialization.
- Integrated `jq.ExpressionRunner` into the `Printer` component, allowing `Printer` to evaluate and print `jq` expressions directly.
- Updated `Printer` to initialize and manage `jq.ExpressionRunner` internally.
- Refactored `jq` package to return an iterator for evaluated results, enabling better integration with `Printer`.
- Adjusted tests to reflect the new design, removing mock printer tests and adding iterator-based result collection.

This refactor improves modularity and encapsulation, ensuring that `jq` functionality is centralized within the `Printer` component.
This commit introduces several changes to improve code clarity and consistency:

- In `internal/jq/jq.go`, the error handling logic in `EvaluateAndPrint` was updated to yield the correct value (`v`) instead of the error (`err`) in certain cases.
- Adjusted the `collectResults` function in `internal/jq/jq_test.go` to use `iter.Seq2[any, error]` directly, aligning with the updated type usage. Removed the `nolint: prealloc` directive for clarity.
- Modified the `internal/printer/printer_test.go` to ensure the expected output for a `nil` scalar in JSON format is an empty string, improving test accuracy.
- Replaced the `interface{}` type with `any` in the `doRequest` method of `internal/replay.go` for better readability and adherence to Go's modern type conventions.
Refined the description of the jq flag to better clarify its purpose. The new description emphasizes its role in filtering
command results using jq expressions, replacing the previous phrasing that focused on selecting values from the response.
This update introduces a new feature allowing users to define and execute custom recipes in the sloctl CLI. Recipes are user-defined commands that can be configured via a YAML file. The implementation includes:

- A new `recipes` command added to the root CLI, enabling users to run custom recipes.
- Validation rules for recipes, ensuring proper configuration and preventing conflicts (e.g., disallowing simultaneous use of `jq` in both the recipe property and arguments).
- Support for displaying recipe definitions using the `--show-definition` flag.
- Dynamic loading of recipes from a configurable path, defaulting to `sloctl-recipes.yaml` in the Nobl9 SDK configuration directory.
- Enhanced error handling and validation for recipe arguments.

Additionally, the `Execute` function in the root command has been refactored to return errors instead of directly exiting, improving testability and error propagation.
@nieomylnieja nieomylnieja changed the title Add recipes feat: add recipes Jul 31, 2025
@n9-machine-user n9-machine-user added go enhancement New feature or request minor labels Jul 31, 2025
nieomylnieja and others added 6 commits August 1, 2025 16:08
This commit introduces a new feature for managing and executing built-in recipes in the application. It includes the following changes:

1. Added a new YAML file (`builtin_recipes.yaml`) to define built-in recipes with their descriptions, arguments, examples, and validators.
2. Enhanced the `recipes.go` file to support commands for listing, adding, and removing recipes. Recipes are grouped into categories for better organization.
3. Implemented functionality to read and save recipes from a configuration file, with support for both JSON and YAML formats.
4. Introduced helper functions for handling recipe configuration paths and temporary file creation for safe updates.
5. Updated the command structure to include recipe-specific commands dynamically based on the defined recipes.

These changes provide a flexible and extensible framework for managing recipes, enabling users to execute predefined tasks efficiently.
This commit introduces a custom YAML encoder to replace the default encoding logic. The new encoder is implemented in the
`yamlenc` package and provides enhanced control over YAML formatting and serialization. Key changes include:

- Replacing the use of `goccy/go-yaml`'s default `Marshal` and `NewEncoder` methods with a custom encoder.
- Adding a `yamlenc.NewEncoder` function that configures the encoder with specific options, such as sequence indentation
  and literal style for multiline strings.
- Introducing a custom marshaler for `json.Number` to ensure integers are not converted to floats during JSON-to-YAML
  transformations.

The changes affect the `yamlPrinter` implementation in `internal/printer/yaml.go` and the recipe handling logic in
`internal/recipes.go`. The new encoder is also used for temporary file writing in the recipes workflow.
This commit introduces a `RecipesCmd` struct to encapsulate the recipes logic and associated printer. The changes include:

- Adding a `RecipesCmd` struct that holds the recipes and a printer instance.
- Refactoring the `NewRecipesCmd` function to use the `RecipesCmd` struct for managing recipes-related commands.
- Moving the logic for listing, adding, deleting, and running recipes into methods of the `RecipesCmd` struct (`ListRecipes`, `AddRecipe`, `DeleteRecipes`, and `RunRecipe`).
- Updating the `Validators` field in the `Recipe` struct to use the `omitzero` tag for better JSON serialization.

These changes improve the modularity and maintainability of the code by grouping related functionality into a dedicated struct.
- Introduced a new `jsonbuffer` package to encapsulate JSON buffer detection logic, replacing the inline `isJSONBuffer` function.
- Updated `ExpressionRunner` to use value receivers instead of pointers, improving consistency and simplifying usage.
- Enhanced `Printer` with a `WithOutput` method for easier output redirection and refactored format validation using the `slices` package.
- Removed the unused `add` command from the recipes module, simplifying the command structure.
- Added comprehensive unit tests for the `jsonbuffer` package to ensure robust JSON detection.
@nieomylnieja nieomylnieja requested a review from Copilot August 6, 2025 15:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces a recipes feature to sloctl that allows users to define, share, and execute custom command templates. The implementation includes built-in recipes for common operations like fetching object names and filtering SLOs by data source type.

Key changes:

  • Added sloctl recipes command with subcommands for listing, removing, and running recipes
  • Implemented recipe configuration system with YAML/JSON storage support
  • Created reusable YAML encoder utility for consistent formatting
  • Refactored error handling in main execution flow

Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
internal/recipes.go Core recipes functionality with command handling, validation, and execution logic
internal/yamlenc/encoder.go New YAML encoder utility with custom number marshaling for consistent output
internal/jsonbuffer/json.go Utility for detecting JSON vs YAML content in buffers
internal/printer/yaml.go Updated to use new YAML encoder for consistent formatting
internal/root.go Added recipes command to CLI and refactored Execute() error handling
cmd/sloctl/main.go Updated main function to handle Execute() errors properly

Comment thread internal/recipes.go Outdated
Comment thread internal/recipes.go
Comment thread internal/recipes.go
nieomylnieja and others added 9 commits August 8, 2025 17:37
Modified the argument validation logic in the `recipesArgFunc` function to permit additional arguments beyond the required ones.
Previously, the function enforced an exact match between the number of provided and required arguments.
Now, it ensures that the number of provided arguments is at least equal to the number of required arguments.
…ies and redundant logic

Removed the `manifest` and `sdk` dependencies as they were no longer used in the `yamlPrinter` implementation. Simplified the `Print` method by eliminating the type switch logic, which was redundant, and directly using the `yamlenc.Encoder` for encoding the content.
nieomylnieja and others added 4 commits February 18, 2026 12:11
Adds a RunE handler to the 'recipes' command to display a clear error message and usage when an unknown recipe is invoked.

This commit also introduces comprehensive unit tests for the 'recipes' command, covering listing, removing, and argument validation. Additionally, unit tests are added for the internal 'yamlenc' package's encoder to ensure correct YAML serialization, especially for JSON numbers and nested structures.
Extract default recipes config path logic into a dedicated function and use a constant for the environment variable. Update the `recipes` command's long description to clarify config path usage. Improve unit tests for `recipes remove` and config handling by making them more isolated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request go minor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants