gitlab-branch-triage 1.0.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.
Files changed (32) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +38 -0
  3. data/LICENSE +21 -0
  4. data/README.md +269 -0
  5. data/bin/gitlab-branch-triage +488 -0
  6. data/gitlab-branch-triage.gemspec +38 -0
  7. data/lib/gitlab/branch_triage/actions/base.rb +44 -0
  8. data/lib/gitlab/branch_triage/actions/comment.rb +5 -0
  9. data/lib/gitlab/branch_triage/actions/delete.rb +32 -0
  10. data/lib/gitlab/branch_triage/actions/executor.rb +44 -0
  11. data/lib/gitlab/branch_triage/actions/mr_actions.rb +187 -0
  12. data/lib/gitlab/branch_triage/actions/notify.rb +145 -0
  13. data/lib/gitlab/branch_triage/actions/print.rb +40 -0
  14. data/lib/gitlab/branch_triage/client.rb +177 -0
  15. data/lib/gitlab/branch_triage/conditions/author_condition.rb +40 -0
  16. data/lib/gitlab/branch_triage/conditions/base.rb +21 -0
  17. data/lib/gitlab/branch_triage/conditions/date_condition.rb +34 -0
  18. data/lib/gitlab/branch_triage/conditions/evaluator.rb +52 -0
  19. data/lib/gitlab/branch_triage/conditions/inactive_days.rb +14 -0
  20. data/lib/gitlab/branch_triage/conditions/mr_conditions.rb +141 -0
  21. data/lib/gitlab/branch_triage/conditions/name_condition.rb +35 -0
  22. data/lib/gitlab/branch_triage/conditions/state_condition.rb +29 -0
  23. data/lib/gitlab/branch_triage/group_resolver.rb +47 -0
  24. data/lib/gitlab/branch_triage/policy_loader.rb +35 -0
  25. data/lib/gitlab/branch_triage/resource/branch.rb +89 -0
  26. data/lib/gitlab/branch_triage/resource/merge_request.rb +150 -0
  27. data/lib/gitlab/branch_triage/runner.rb +247 -0
  28. data/lib/gitlab/branch_triage/user_resolver.rb +103 -0
  29. data/lib/gitlab/branch_triage/version.rb +7 -0
  30. data/lib/gitlab-branch-triage.rb +60 -0
  31. data/logo.svg +87 -0
  32. metadata +111 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6f0c6207b42ee32ebdee0043b2bc42fa281174887aa4e0e7983d8ec730212635
4
+ data.tar.gz: 740c0de7ba602b533247202bdb9f8e2c4ef34fc29eac5ccbb130c87b6ccc19ed
5
+ SHA512:
6
+ metadata.gz: 9b9e817f6c1b37d237ee74b08b23a0ac684de7cdbc20cffc0704e7699b465cf2f636ed19014f6583a3f76e1c98378dd4d93d3585ecc6a251d2c4d7ec9735dfbe
7
+ data.tar.gz: fd595edf5634bab0e9ea7b0030869d2d79630c6cd7262cfe1472240158b7f9511b07f20ae8da7045e3a3c9697150fb8873e7f1f9747ea725819429b9d73fd5d3
data/CHANGELOG.md ADDED
@@ -0,0 +1,38 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.0.0] - 2026-03-11
9
+
10
+ ### Added
11
+
12
+ - initial commit and push beta version v1.0.0 (bfba928)
13
+
14
+ ### Other
15
+
16
+ - Initial commit (123cd8b)
17
+
18
+ ## [1.0.0] - 2026-03-11
19
+
20
+ ### Added
21
+
22
+ - YAML-driven policy engine for branch and merge request triage
23
+ - Branch conditions: `inactive_days`, `merged`, `protected`, `has_open_mr`, `name`, `forbidden_name`, `author`, `forbidden_author`, `date`
24
+ - Branch actions: `notify`, `delete`, `print`, `comment`
25
+ - MR conditions: `date`, `draft`, `assigned`, `has_reviewer`, `pipeline_status`, `labels`, `forbidden_labels`, `target_branch`, `title`
26
+ - MR actions: `comment_mr`, `close_mr`, `label_mr`, `notify_mr`, `print`
27
+ - Inactive author detection with automatic branch deletion and owner notification
28
+ - Group-wide triage with recursive subgroup support
29
+ - Dry-run mode enabled by default
30
+ - `--init` helper to generate example policy file
31
+ - `--init-ci` helper to generate GitLab CI snippet
32
+ - Template variable system for notification messages
33
+ - Rate-limit handling with configurable max retries
34
+ - CLI with comprehensive options for token, source, host, policies, and filters
35
+
36
+ [1.0.0]: https://github.com/solucteam/gitlab-branch-triage/releases/tag/v1.0.0
37
+
38
+ [1.0.0]: https://github.com/solucteam/gitlab-branch-triage/releases/tag/v1.0.0
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SolucTeam
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,269 @@
1
+ <p align="center">
2
+ <img src="logo.svg" alt="gitlab-branch-triage" width="560"/>
3
+ </p>
4
+
5
+ <p align="center">
6
+ <a href="https://rubygems.org/gems/gitlab-branch-triage"><img src="https://img.shields.io/gem/v/gitlab-branch-triage?color=E24329&style=for-the-badge&logo=rubygems&logoColor=white" alt="Gem Version"/></a>
7
+ <a href="https://rubygems.org/gems/gitlab-branch-triage"><img src="https://img.shields.io/gem/dt/gitlab-branch-triage?color=6B4FBB&style=for-the-badge&logo=rubygems&logoColor=white" alt="Downloads"/></a>
8
+ <a href="https://github.com/solucteam/gitlab-branch-triage/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/solucteam/gitlab-branch-triage/ci.yml?style=for-the-badge&logo=github&label=CI" alt="CI"/></a>
9
+ <img src="https://img.shields.io/badge/ruby-%3E%3D%203.0-CC342D?style=for-the-badge&logo=ruby&logoColor=white" alt="Ruby >= 3.0"/>
10
+ <a href="LICENSE"><img src="https://img.shields.io/github/license/solucteam/gitlab-branch-triage?color=FCA326&style=for-the-badge" alt="License"/></a>
11
+ </p>
12
+
13
+ ---
14
+
15
+ **gitlab-branch-triage** automates branch and merge request cleanup on GitLab using YAML-driven policies. Notify stale branch authors, auto-delete merged branches, close abandoned MRs, detect inactive authors, and keep your repositories clean — all from a single configuration file.
16
+
17
+ ## Features
18
+
19
+ - **Policy-driven** — define triage rules in a simple YAML file
20
+ - **Branch triage** — detect stale, merged, or abandoned branches and act on them
21
+ - **MR triage** — warn about abandoned MRs, close stale ones, flag failing pipelines
22
+ - **Inactive author detection** — automatically handles branches from blocked/deleted users
23
+ - **Group-wide** — triage all projects in a GitLab group (subgroups included recursively)
24
+ - **Dry-run by default** — safe to test before executing real actions
25
+ - **GitLab CI ready** — ship as a scheduled pipeline job
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ gem install gitlab-branch-triage
31
+ ```
32
+
33
+ Or add to your `Gemfile`:
34
+
35
+ ```ruby
36
+ gem "gitlab-branch-triage"
37
+ ```
38
+
39
+ ## Quick Start
40
+
41
+ **1. Generate an example policy file:**
42
+
43
+ ```bash
44
+ gitlab-branch-triage --init
45
+ ```
46
+
47
+ This creates `.branch-triage-policies.yml` with sensible defaults.
48
+
49
+ **2. Run a dry-run against a project:**
50
+
51
+ ```bash
52
+ export GITLAB_TOKEN="glpat-xxxxx" # needs api scope
53
+
54
+ # Single project
55
+ gitlab-branch-triage --source-id my-group/my-project
56
+
57
+ # Entire group (all subgroups included)
58
+ gitlab-branch-triage --source groups --source-id my-group
59
+ ```
60
+
61
+ **3. Execute real actions:**
62
+
63
+ ```bash
64
+ gitlab-branch-triage --source-id my-group/my-project --no-dry-run
65
+ ```
66
+
67
+ ## Configuration
68
+
69
+ Policies are defined in `.branch-triage-policies.yml`. The file has two main sections: `branches` rules and `merge_requests` rules.
70
+
71
+ ### Branch Rules
72
+
73
+ ```yaml
74
+ resource_rules:
75
+ branches:
76
+ rules:
77
+ - name: Notify stale branches (60+ days)
78
+ conditions:
79
+ inactive_days: 60
80
+ merged: false
81
+ protected: false
82
+ has_open_mr: false
83
+ forbidden_name:
84
+ matches: "^(main|master|develop)$"
85
+ limits:
86
+ most_recent: 50
87
+ actions:
88
+ notify:
89
+ title: "Stale branch: `{{name}}` in {{project_path}}"
90
+ body: |
91
+ @{{author_username}}, branch `{{name}}` has been inactive
92
+ for **{{days_inactive}} days**. It will be deleted on **{{delete_date}}**.
93
+ labels:
94
+ - branch-cleanup
95
+
96
+ - name: Delete abandoned branches (90+ days)
97
+ conditions:
98
+ inactive_days: 90
99
+ merged: false
100
+ protected: false
101
+ actions:
102
+ delete: true
103
+ ```
104
+
105
+ ### Branch Conditions
106
+
107
+ | Condition | Example | Description |
108
+ |-----------|---------|-------------|
109
+ | `inactive_days` | `60` | Days since last commit |
110
+ | `merged` | `true` / `false` | Branch merge status |
111
+ | `protected` | `true` / `false` | Branch protection status |
112
+ | `has_open_mr` | `true` / `false` | Has an open merge request |
113
+ | `name` | `{matches: "^feature/.*"}` | Branch name pattern (`matches`, `contains`, `starts_with`, `ends_with`) |
114
+ | `forbidden_name` | `{matches: "^main$"}` | Exclude branches by name |
115
+ | `author` | `{email_domain: "company.com"}` | Filter by author (`email_domain`, `name_matches`, `username`) |
116
+ | `forbidden_author` | `{email_domain: "bot.com"}` | Exclude by author |
117
+ | `date` | see below | Flexible date matching |
118
+
119
+ **Date condition:**
120
+
121
+ ```yaml
122
+ date:
123
+ attribute: committed_date
124
+ condition: older_than # or more_recent_than
125
+ interval_type: days # days | weeks | months | years
126
+ interval: 60
127
+ ```
128
+
129
+ ### Branch Actions
130
+
131
+ | Action | Config | Description |
132
+ |--------|--------|-------------|
133
+ | `notify` | `{title, body, labels}` | Create an issue to notify the author |
134
+ | `delete` | `true` | Delete the branch |
135
+ | `print` | `"template string"` | Log a message |
136
+ | `comment` | `{issue_iid, body}` | Comment on an existing issue |
137
+
138
+ ### Merge Request Rules
139
+
140
+ ```yaml
141
+ resource_rules:
142
+ merge_requests:
143
+ rules:
144
+ - name: Warn abandoned MRs (30+ days)
145
+ conditions:
146
+ date:
147
+ attribute: updated_at
148
+ condition: older_than
149
+ interval_type: days
150
+ interval: 30
151
+ forbidden_labels:
152
+ - do-not-close
153
+ actions:
154
+ label_mr:
155
+ - stale
156
+ comment_mr: |
157
+ @{{author_username}}, this MR has had no activity for **{{days_since_update}} days**.
158
+
159
+ - name: Close abandoned MRs (60+ days)
160
+ conditions:
161
+ date:
162
+ attribute: updated_at
163
+ condition: older_than
164
+ interval_type: days
165
+ interval: 60
166
+ actions:
167
+ close_mr: true
168
+ ```
169
+
170
+ ### MR Conditions
171
+
172
+ | Condition | Example | Description |
173
+ |-----------|---------|-------------|
174
+ | `date` | `{attribute: updated_at, ...}` | Filter by `updated_at` or `created_at` |
175
+ | `draft` | `true` / `false` | Draft/WIP status |
176
+ | `assigned` | `true` / `false` | Has assignees |
177
+ | `has_reviewer` | `true` / `false` | Has reviewers |
178
+ | `pipeline_status` | `"failed"` | Pipeline state (`success`, `failed`, `running`, `pending`) |
179
+ | `labels` | `["label1"]` | All labels must match (AND) |
180
+ | `forbidden_labels` | `["on-hold"]` | None must match |
181
+ | `target_branch` | `"main"` or `{matches: "regex"}` | Target branch filter |
182
+ | `title` | `{contains: "hotfix"}` | Title pattern matching |
183
+
184
+ ### MR Actions
185
+
186
+ | Action | Config | Description |
187
+ |--------|--------|-------------|
188
+ | `comment_mr` | `"template"` | Post a comment on the MR |
189
+ | `close_mr` | `true` | Close the MR |
190
+ | `label_mr` | `["stale"]` | Add labels |
191
+ | `notify_mr` | `{title, body, labels}` | Create a notification issue |
192
+ | `print` | `"template"` | Log a message |
193
+
194
+ ### Template Variables
195
+
196
+ **Branches:** `{{name}}`, `{{author_name}}`, `{{author_email}}`, `{{author_username}}`, `{{committed_date}}`, `{{days_inactive}}`, `{{delete_date}}`, `{{commit_title}}`, `{{short_sha}}`, `{{project_path}}`, `{{today}}`
197
+
198
+ **Merge Requests:** `{{iid}}`, `{{title}}`, `{{web_url}}`, `{{source_branch}}`, `{{target_branch}}`, `{{author_username}}`, `{{author_name}}`, `{{labels}}`, `{{state}}`, `{{draft}}`, `{{days_since_update}}`, `{{days_since_creation}}`, `{{updated_at}}`, `{{pipeline_status}}`, `{{close_date}}`, `{{project_path}}`, `{{today}}`
199
+
200
+ ## CLI Options
201
+
202
+ ```
203
+ Usage: gitlab-branch-triage [options]
204
+
205
+ Connection:
206
+ -t, --token TOKEN GitLab API token (or GITLAB_TOKEN env var)
207
+ -H, --host-url URL GitLab host (default: https://gitlab.com)
208
+
209
+ Source:
210
+ -s, --source TYPE 'projects' (default) or 'groups'
211
+ -i, --source-id ID Project or group path/ID
212
+
213
+ Group filters:
214
+ --[no-]exclude-archived Exclude archived projects (default: true)
215
+ --[no-]exclude-forks Exclude forked projects (default: true)
216
+
217
+ Policies:
218
+ -f, --policies-file FILE YAML file (default: .branch-triage-policies.yml)
219
+
220
+ Behaviour:
221
+ -n, --dry-run Don't perform real actions (default: on)
222
+ --no-dry-run Execute real actions
223
+ -d, --debug Print extra debug information
224
+
225
+ Helpers:
226
+ --init Create example policy file
227
+ --init-ci Print example .gitlab-ci.yml snippet
228
+ -v, --version Print version
229
+ -h, --help Print help
230
+ ```
231
+
232
+ ## GitLab CI Integration
233
+
234
+ Run as a scheduled pipeline job:
235
+
236
+ ```yaml
237
+ branch-triage:
238
+ stage: triage
239
+ image: ruby:3.2-slim
240
+ before_script:
241
+ - gem install gitlab-branch-triage --no-document
242
+ script:
243
+ - gitlab-branch-triage --token $GITLAB_TOKEN --source-id $CI_PROJECT_PATH --no-dry-run
244
+ rules:
245
+ - if: $CI_PIPELINE_SOURCE == "schedule"
246
+ - if: $CI_PIPELINE_SOURCE == "web"
247
+ when: manual
248
+ allow_failure: true
249
+ ```
250
+
251
+ Generate the snippet with `gitlab-branch-triage --init-ci`.
252
+
253
+ ## Inactive Author Detection
254
+
255
+ When the `notify` action detects that a branch author is inactive (blocked, deactivated, or deleted from GitLab), it automatically deletes the branch and creates a cleanup issue assigned to a project maintainer. This prevents stale notifications to users who can no longer act on them.
256
+
257
+ ## Contributing
258
+
259
+ Bug reports and pull requests are welcome on [GitHub](https://github.com/solucteam/gitlab-branch-triage).
260
+
261
+ 1. Fork it
262
+ 2. Create your feature branch (`git checkout -b feature/my-feature`)
263
+ 3. Commit your changes (`git commit -am 'Add my feature'`)
264
+ 4. Push to the branch (`git push origin feature/my-feature`)
265
+ 5. Open a Pull Request
266
+
267
+ ## License
268
+
269
+ Released under the [MIT License](LICENSE). Copyright (c) 2026 SolucTeam.