Skip to content

Conversation

@hetangmodi-crest
Copy link
Contributor

@hetangmodi-crest hetangmodi-crest commented Jan 20, 2025

Issue number:
ADDON-76780

PR Type

What kind of change does this PR introduce?

  • Feature
  • Bug Fix
  • Refactoring (no functional or API changes)
  • Documentation Update
  • Maintenance (dependency updates, CI, etc.)

Summary

Added support for custom search command

Changes

customSearchCommand tag has been added to the global configuration, allowing users to generate their custom search commands using ucc-gen build. Users only need to define the logic for their command and update the customSearchCommand in globalConfig.

User experience

Users can now generate custom search commands using the ucc-gen build command. To do so, they need to define the command logic and update the globalConfig accordingly.

Checklist

If an item doesn't apply to your changes, leave it unchecked.

@hetangmodi-crest hetangmodi-crest added the enhancement New feature or request label Jan 20, 2025
@hetangmodi-crest hetangmodi-crest self-assigned this Jan 20, 2025
@hetangmodi-crest hetangmodi-crest marked this pull request as ready for review January 23, 2025 11:58
@hetangmodi-crest hetangmodi-crest requested review from a team as code owners January 23, 2025 11:58
@kkedziak-splunk
Copy link
Contributor

Let me review this extensive pull request that adds support for custom search commands.

Suggested pull request title: feat: add custom search command support

The pull request demonstrates high quality and introduces significant enhancements to the add-on UCC framework. Here's what I appreciate about it:

  1. Well-structured implementation of custom search command support with proper templates and validation
  2. Comprehensive test coverage with unit and smoke tests
  3. Documentation updates explaining the new feature and its configuration
  4. UI improvements including:
    • New CheckboxTree component
    • Better form control styling and accessibility
    • Updated dependencies and build system

Here are a few specific suggestions for improvement:

  1. For better mutation test coverage, consider adding more edge cases to test error handling in the custom search command generation
  2. The documentation could benefit from more code examples showing common custom search command use cases
  3. Consider adding validation to ensure command names follow Splunk's naming conventions

The changes appear suitable for merging once any testing feedback has been addressed. The commits are cleanly organized and the changes ready for review.

The best feature of this PR is its comprehensive approach - not just implementing the core functionality but also adding proper tests, documentation and sample code.

Great job on the PR organization and quality of implementation. Feel free to merge once CI passes and any testing feedback has been addressed.

This comment was added by our PR Review Assistant Bot. Please kindly acknowledge that
while we're doing our best to keep these comments up to very high standards, they may occasionally be
incorrect. Suggestions offered by the Bot are only intended as points for consideration and no statements
by this bot alone can be considered grounds for merging of any pull request. Remember to seek a review
from a human co-worker.

To reply to the review and engage Review Bot in further conversation, start your comment with the words Review bot:

@kkedziak-splunk
Copy link
Contributor

Just tested the PR review bot

, require=False
{%- endif -%}

{%- if arg.validate -%}
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a very complicated IF. Maybe it should be done outside of the template?

It could be passed as a string.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is a nested if-else ladder, but yes the conditions are seem long due to the Jinja2 template.
Doing it outside in the Python scripts would work, but I don't think it would be a patch, as the templates should be providing the skeleton and the values then fill in the muscles and organs.

Comment on lines 520 to 524
if (command["requireSeachAssistant"] is False) and (
command.get("description")
or command.get("usage")
or command.get("syntax")
):
Copy link
Member

Choose a reason for hiding this comment

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

Can you please check is it possible to have this logic in the schema.json? Or would it be too complicated for the JSON schema to handle?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it is possible to implement the above logic in JSON schema the reason I think we shouldn't go with schema.json approach is because,

  • JSON Schema validators typically reject invalid data, rather than logging a warning, and in this case I don't think we should stop the build process.
  • JSON Schema library does not support custom error messages directly. It is better to validate and raise warning through above logic.

" is not been defined in globalConfig. Defined them as requireSeachAssistant is set to True. "
)
sys.exit(1)
if command["version"] == 1:
Copy link
Member

Choose a reason for hiding this comment

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

Should we not support version 1? We mention in this PR that it is deprecated.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Though version 1 is deprecated, we should support it as add-ons like ServiceNow and BMC Remedy uses version 1 for their custom search commands, hence I kept it.

Copy link
Member

Choose a reason for hiding this comment

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

Let's remove it from UCC, I'll create a Jira for the team to move to the version 2.

Copy link
Member

Choose a reason for hiding this comment

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

Btw, I checked both those add-ons and I can't find version in commands.conf. Is there another way to figure out which version do they use?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The determination of version is can be seen based on this description.

Okay, I'll remove the support of version 1 from this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed the support of version 1.

for command in kwargs["custom_search_commands"]:
self.command_names.append(command["commandName"])

def generate_conf(self) -> Union[Dict[str, str], None]:
Copy link
Member

Choose a reason for hiding this comment

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

What happens if there is a commands.conf file already in the package folder?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If the commands.conf is present in the package folder, it would overwrite the one we generated, as it is done for the other conf files (except app.conf). Do we want to merge the generated and source content of the conf files?

Comment on lines +40 to +44
src_pkg_bin = os.path.realpath(os.path.join(self._input_dir, "bin"))
sys.path.insert(0, src_pkg_bin)
if hasattr(import_module(command["fileName"]), "map"):
import_map = True
sys.path.pop(0)
Copy link
Member

Choose a reason for hiding this comment

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

Can you please explain what are we trying to achieve here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For reporting type of custom search command, map method is optional, hence we check whether the developer has implemented this map method or not.


{% if import_map %}
@Configuration()
def map(self, events):
Copy link
Contributor

Choose a reason for hiding this comment

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

Can't we always add this method, without this check with importing the command? Would it have any drawbacks?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

map is an optional method which is used for streaming preop, if there is no need of pre-operation then we can remove this method.
(reference)

@kkedziak-splunk kkedziak-splunk self-requested a review March 4, 2025 13:15
Copy link
Contributor

@kkedziak-splunk kkedziak-splunk left a comment

Choose a reason for hiding this comment

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

I copied the minimal definition from the docs to splunk-example-ta, created an empty mycommandlogic.py file and built it. I got the following exception:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/kkedziak/PycharmProjects/addonfactory-ucc-generator/splunk_add_on_ucc_framework/main.py", line 244, in main
    build.generate(
  File "/Users/kkedziak/PycharmProjects/addonfactory-ucc-generator/splunk_add_on_ucc_framework/commands/build.py", line 519, in generate
    if (command["requireSeachAssistant"] is False) and (
KeyError: 'requireSeachAssistant'

)
sys.exit(1)

if (command["requireSeachAssistant"] is False) and (
Copy link
Contributor

@kkedziak-splunk kkedziak-splunk Mar 4, 2025

Choose a reason for hiding this comment

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

Suggested change
if (command["requireSeachAssistant"] is False) and (
if (command["requiredSearchAssistant"] is False) and (

and typos in other occurences of this phrase (compared with docs)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for pointing it out, I have made the respective changes in all files.

@artemrys
Copy link
Member

artemrys commented Mar 5, 2025

Let's wait with merging this one, I'd like to discuss @kkedziak-splunk's document first and find consensus in the team.

files_to_delete.append(sep.join([output_path, ta_name, "bin", "template_rest_handler_script.py"]))
files_to_delete.append(sep.join([output_path, ta_name, "bin", "file_does_not_exist.py"]))
files_to_delete.append(sep.join([output_path, ta_name, "default", "nav", "views", "file_copied_from_source_code.xml"]))
files_to_delete.append(sep.join([output_path, ta_name, "bin", "__pycache__", "sum_without_map.cpython-37.pyc"]))
Copy link
Contributor

@sgoral-splunk sgoral-splunk Mar 5, 2025

Choose a reason for hiding this comment

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

I don't think we should keep this (or TA devs). Maybe we should clean this up?
EDIT: my mistake. Ignore this comment.

@github-actions
Copy link

Code Coverage ⚠️

Type PR Develop Change Status
Line Coverage 86.84% 86.90% 0.05% 🔴 Decreased
Branch Coverage 79.83% 80.12% 0.29% 🔴 Decreased

Comment on lines +35 to +48
{%- if (arg.validate.type == "Integer" or arg.validate.type == "Float") -%}
{%- if (arg.validate.minimum and arg.validate.maximum) -%}
, validate=validators.{{ arg.validate.type }}(minimum={{ arg.validate.minimum }}, maximum={{ arg.validate.maximum }})
{%- elif (arg.validate.minimum and not arg.validate.maximum) -%}
, validate=validators.{{ arg.validate.type }}(minimum={{ arg.validate.minimum }})
{%- elif (not arg.validate.minimum and arg.validate.maximum) -%}
, validate=validators.{{ arg.validate.type }}(maximum={{ arg.validate.maximum }})
{%- else -%}
, validate=validators.{{ arg.validate.type }}()
{%- endif -%}
{%- else -%}
, validate=validators.{{ arg.validate.type }}()
{%- endif -%}
{%- endif -%}
Copy link
Contributor

Choose a reason for hiding this comment

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

Are we going to move this logic out of the template? I think we agreed to do that in a meeting two weeks ago, but maybe something has changed

@github-actions github-actions bot locked and limited conversation to collaborators May 7, 2025
@hetangmodi-crest
Copy link
Contributor Author

Closing the PR as it has been broken down into new PRs.

@hetangmodi-crest hetangmodi-crest deleted the feat/custom-search-command branch May 7, 2025 10:02
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

enhancement New feature or request size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants