gitlab-triage 1.49.0 → 1.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6412e63a12ac53c09a1eb643cd3b5aa49e08e4691544b3356212e8ddec460d56
4
- data.tar.gz: 2c655d476bc397a889f103763a31525116b1b647bfa382ddd9e7418cfe3e7c42
3
+ metadata.gz: '066092d8567b3b76494b99f0c244c565d1c9b65938082e741fe955742c89e88e'
4
+ data.tar.gz: 3fc1d9bf0c94a47b6d6a39002014bb60fe52ac93624cb50f6a06cc2f73d11528
5
5
  SHA512:
6
- metadata.gz: df41feed9393573cf512348b2fb8f5be16474f58ca2af16ab1190543f7cf910b97b5a5c48798927b54ca5e25c72522f2e3609dc0c9d3d46a384259372160be85
7
- data.tar.gz: 23f44c55003c443b5535dc9be1100cf55510f4fd105fc145685cb3446a1cff8b67540db0c784340fe1cd90c999a2c08330cc9b6722c1131760b2a39fd08a7194
6
+ metadata.gz: cd1f5e1088ec9cbe4e21ed6c968ce47489be3d83c95fffd07fd8e59a8eb92240ed44172f09f34390901dd43241a70320e859b5350b1afd20007550736d4bad75
7
+ data.tar.gz: ef7c028266e48926aba06c4fc908798eb7b9b60d3a16cfe7fe05a6134e5756374419961f52baf6c41e12a38f61b5a9c66f11c7e771b725d640619bc13db9bf04
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gitlab-triage (1.49.0)
4
+ gitlab-triage (1.50.0)
5
5
  activesupport (>= 5.1)
6
6
  globalid (~> 1.0, >= 1.0.1)
7
7
  graphql (< 2.1.0)
data/README.md CHANGED
@@ -1467,6 +1467,10 @@ Usage: gitlab-triage [options]
1467
1467
  -H, --host-url [string] A valid host url
1468
1468
  -r, --require [string] Require a file before performing
1469
1469
  -d, --debug Print debug information
1470
+ --cache-dir [string] Directory containing pre-fetched API responses.
1471
+ Files must follow the naming convention: <source>_<id>_<resource>.json
1472
+ (e.g. groups_9970_members.json).
1473
+ Can also be set via the GITLAB_TRIAGE_CACHE_DIR environment variable.
1470
1474
  -h, --help Print help message
1471
1475
  -v, --version Print version
1472
1476
  --init Initialize the project with a policy file
@@ -1592,6 +1596,44 @@ resource_rules:
1592
1596
  #{'/label ~P3' unless has_priority_label?}
1593
1597
  ```
1594
1598
 
1599
+ ### API Response Caching (`--cache-dir`)
1600
+
1601
+ In large CI pipelines with many concurrent triage jobs, each job independently fetches the same paginated API responses (e.g., group members). This results in many redundant API calls.
1602
+
1603
+ The `--cache-dir` option (or `CACHE_DIR` environment variable) allows you to pre-fetch responses once and share them across all jobs via CI artifacts.
1604
+
1605
+ #### File naming convention
1606
+
1607
+ Cache files must be named `<source_type>_<source_id>_<resource>.json`, for example:
1608
+
1609
+ - `groups_9970_members.json` — members of group 9970 (numeric ID)
1610
+ - `projects_278964_members.json` — members of project 278964 (numeric ID)
1611
+ - `groups_gitlab-org_gitlab_members.json` — members of `gitlab-org/gitlab` (path slashes replaced with `_`)
1612
+
1613
+ The gem checks for a matching cache file before making each `query_api_cached` call. If a file exists, its contents are returned directly. If not, the gem falls back to the normal API call transparently.
1614
+
1615
+ #### Usage in CI
1616
+
1617
+ Pre-fetch in a `pre-hygiene` stage and share as an artifact:
1618
+
1619
+ ```yaml
1620
+ # pre-hygiene job writes the cache
1621
+ prefetch-members:
1622
+ stage: pre-hygiene
1623
+ script:
1624
+ - ruby bin/prefetch_members
1625
+ artifacts:
1626
+ paths:
1627
+ - tmp/members_cache/
1628
+ expire_in: 1 hour
1629
+
1630
+ # triage jobs read from the cache
1631
+ triage-job:
1632
+ stage: hygiene
1633
+ script:
1634
+ - gitlab-triage --cache-dir tmp/members_cache --token $TOKEN --source groups --source-id 9970 -f policy.yml
1635
+ ```
1636
+
1595
1637
  ### Contributing
1596
1638
 
1597
1639
  Please refer to the [Contributing Guide](CONTRIBUTING.md).
@@ -44,7 +44,8 @@ module Gitlab
44
44
  return
45
45
  end
46
46
 
47
- policy.summary = network.post_api(post_issue_url, post_issue_body)
47
+ response = network.post_api(post_issue_url, post_issue_body)
48
+ policy.summary = response.merge('type' => SUMMARY_RESOURCE_TYPE)
48
49
  end
49
50
 
50
51
  def issue
@@ -65,6 +65,14 @@ module Gitlab
65
65
  options.debug = value
66
66
  end
67
67
 
68
+ opts.on('--cache-dir [string]', String,
69
+ 'Directory containing pre-fetched API responses. ' \
70
+ 'Files must follow the naming convention: <source>_<id>_<resource>.json ' \
71
+ '(e.g. groups_9970_members.json). ' \
72
+ 'Can also be set via the GITLAB_TRIAGE_CACHE_DIR environment variable.') do |value|
73
+ options.cache_dir = value
74
+ end
75
+
68
76
  opts.on('-h', '--help', 'Print help message') do
69
77
  $stdout.puts opts
70
78
  exit # rubocop:disable Rails/Exit
@@ -14,7 +14,8 @@ module Gitlab
14
14
  :debug,
15
15
  :host_url,
16
16
  :require_files,
17
- :api_version
17
+ :api_version,
18
+ :cache_dir
18
19
  ) do
19
20
  def initialize(*args)
20
21
  super
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'active_support/all'
4
+ require 'json'
4
5
  require 'net/protocol'
6
+ require 'uri'
5
7
 
6
8
  require_relative 'retryable'
7
9
  require_relative 'ui'
@@ -13,6 +15,7 @@ module Gitlab
13
15
  include Retryable
14
16
 
15
17
  MINIMUM_RATE_LIMIT = 25
18
+ CACHE_URL_PATTERN = %r{/api/v[^/]+/(groups|projects)/(.+?)/(members)(?:\z|\?)}
16
19
 
17
20
  attr_reader :options, :adapter
18
21
 
@@ -20,10 +23,11 @@ module Gitlab
20
23
  @adapter = adapter
21
24
  @options = adapter.options
22
25
  @cache = {}
26
+ @file_cache = {}
23
27
  end
24
28
 
25
29
  def query_api_cached(url)
26
- @cache[url] || @cache[url] = query_api(url)
30
+ @cache[url] || @cache[url] = load_from_file_cache(url) || query_api(url)
27
31
  end
28
32
 
29
33
  def query_api(url)
@@ -66,7 +70,7 @@ module Gitlab
66
70
 
67
71
  def post_api(url, body)
68
72
  response = execute_with_retry(
69
- exception_types: Net::ReadTimeout,
73
+ exception_types: [Net::ReadTimeout, Errors::Network::InternalServerError],
70
74
  backoff_exceptions: Errors::Network::TooManyRequests, debug: options.debug) do
71
75
  puts Gitlab::Triage::UI.debug "post_api: #{url}" if options.debug
72
76
 
@@ -88,7 +92,7 @@ module Gitlab
88
92
 
89
93
  def delete_api(url)
90
94
  response = execute_with_retry(
91
- exception_types: Net::ReadTimeout,
95
+ exception_types: [Net::ReadTimeout, Errors::Network::InternalServerError],
92
96
  backoff_exceptions: Errors::Network::TooManyRequests, debug: options.debug) do
93
97
  puts Gitlab::Triage::UI.debug "delete_api: #{url}" if options.debug
94
98
 
@@ -101,6 +105,53 @@ module Gitlab
101
105
 
102
106
  private
103
107
 
108
+ def cache_dir
109
+ options.cache_dir || ENV.fetch('GITLAB_TRIAGE_CACHE_DIR', nil)
110
+ end
111
+
112
+ def load_from_file_cache(url)
113
+ return nil unless cache_dir_valid?
114
+
115
+ cache_key = cache_key_for(url)
116
+ return nil unless cache_key
117
+
118
+ @file_cache[cache_key] || read_cache_file(cache_key)
119
+ end
120
+
121
+ def cache_dir_valid?
122
+ cache_dir && File.directory?(cache_dir)
123
+ end
124
+
125
+ def cache_key_for(url)
126
+ match = url.match(CACHE_URL_PATTERN)
127
+ return nil unless match
128
+
129
+ source_type = match[1]
130
+ source_id = URI.decode_www_form_component(match[2]).tr('/', '_')
131
+ resource = match[3]
132
+
133
+ "#{source_type}_#{source_id}_#{resource}"
134
+ end
135
+
136
+ def read_cache_file(cache_key)
137
+ data = parse_cache_file(cache_key)
138
+ return nil unless data
139
+
140
+ @file_cache[cache_key] = data
141
+ puts Gitlab::Triage::UI.debug "cache_dir: loaded #{data.size} records" if options.debug
142
+ data
143
+ end
144
+
145
+ def parse_cache_file(cache_key)
146
+ file = File.join(cache_dir, "#{cache_key}.json")
147
+ parsed = JSON.parse(File.read(file))
148
+ return nil unless parsed.is_a?(Array) && parsed.all?(Hash)
149
+
150
+ parsed.map(&:with_indifferent_access)
151
+ rescue JSON::ParserError, Errno::ENOENT, Errno::EACCES
152
+ nil
153
+ end
154
+
104
155
  def token
105
156
  options.token
106
157
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Gitlab
4
4
  module Triage
5
- VERSION = '1.49.0'
5
+ VERSION = '1.50.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-triage
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.49.0
4
+ version: 1.50.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitLab
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-02-12 00:00:00.000000000 Z
11
+ date: 2026-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport