annotation_search_logic.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #!/usr/bin/env python3
  2. # Copyright Materialize, Inc. and contributors. All rights reserved.
  3. #
  4. # Use of this software is governed by the Business Source License
  5. # included in the LICENSE file at the root of this repository.
  6. #
  7. # As of the Change Date specified in that file, in accordance with
  8. # the Business Source License, use of this software will be governed
  9. # by the Apache License, Version 2.0.
  10. from materialize.buildkite_insights.annotation_search.annotation_search_presentation import (
  11. print_annotation_match,
  12. print_before_search_results,
  13. print_summary,
  14. )
  15. from materialize.buildkite_insights.annotation_search.buildkite_search_source import (
  16. ANY_BRANCH_VALUE,
  17. BuildkiteDataSource,
  18. )
  19. from materialize.buildkite_insights.buildkite_api.generic_api import RateLimitExceeded
  20. from materialize.buildkite_insights.data.build_annotation import BuildAnnotation
  21. from materialize.buildkite_insights.data.build_info import Build
  22. from materialize.buildkite_insights.util.search_utility import (
  23. _search_value_to_pattern,
  24. )
  25. def search_build(
  26. build: Build,
  27. search_source: BuildkiteDataSource,
  28. search_value: str,
  29. use_regex: bool,
  30. max_entries_to_print: int,
  31. short_result_presentation: bool,
  32. one_line_match_presentation: bool,
  33. verbose: bool = False,
  34. ) -> int:
  35. assert max_entries_to_print >= 0
  36. if verbose:
  37. print(f"Searching build #{build.number}...")
  38. annotations = search_source.fetch_annotations(build)
  39. matched_annotations = search_annotations(
  40. annotations,
  41. search_value=search_value,
  42. use_regex=use_regex,
  43. )
  44. for i, annotation in enumerate(matched_annotations):
  45. if i >= max_entries_to_print:
  46. break
  47. print_annotation_match(
  48. build,
  49. annotation,
  50. search_value=search_value,
  51. use_regex=use_regex,
  52. short_result_presentation=short_result_presentation,
  53. one_line_match_presentation=one_line_match_presentation,
  54. )
  55. return len(matched_annotations)
  56. def search_annotations(
  57. annotations: list[BuildAnnotation],
  58. search_value: str,
  59. use_regex: bool,
  60. ) -> list[BuildAnnotation]:
  61. matched_annotations = []
  62. search_pattern = _search_value_to_pattern(search_value, use_regex)
  63. for annotation in annotations:
  64. if search_pattern.search(annotation.content) is not None:
  65. matched_annotations.append(
  66. BuildAnnotation(title=annotation.title, content=annotation.content)
  67. )
  68. return matched_annotations
  69. def start_search(
  70. pipeline_slug: str,
  71. branch: str | None,
  72. search_source: BuildkiteDataSource,
  73. max_results: int,
  74. only_one_result_per_build: bool,
  75. pattern: str,
  76. use_regex: bool,
  77. short_result_presentation: bool,
  78. one_line_match_presentation: bool,
  79. verbose: bool,
  80. ) -> None:
  81. assert len(pattern) > 0, "pattern must not be empty"
  82. if branch == ANY_BRANCH_VALUE:
  83. branch = None
  84. builds = search_source.fetch_builds(pipeline=pipeline_slug, branch=branch)
  85. print_before_search_results()
  86. count_matches = 0
  87. for build in builds:
  88. max_entries_to_print = max(0, max_results - count_matches)
  89. if max_entries_to_print == 0:
  90. break
  91. if only_one_result_per_build:
  92. max_entries_to_print = 1
  93. try:
  94. matches_in_build = search_build(
  95. build,
  96. search_source,
  97. pattern,
  98. use_regex=use_regex,
  99. max_entries_to_print=max_entries_to_print,
  100. short_result_presentation=short_result_presentation,
  101. one_line_match_presentation=one_line_match_presentation,
  102. verbose=verbose,
  103. )
  104. except RateLimitExceeded:
  105. print("Aborting due to exceeded rate limit!")
  106. return
  107. if only_one_result_per_build:
  108. matches_in_build = min(1, matches_in_build)
  109. count_matches = count_matches + matches_in_build
  110. print_summary(pipeline_slug, branch, builds, count_matches, max_results)