nomos 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b54115ded4fd9b060a08616a09c235b10fc9f061edcb9e3b6053f873c532b0fc
4
+ data.tar.gz: 5496082b49731cf351dc56f758889311cd252461da0cdfdf22a4a958aac3ca82
5
+ SHA512:
6
+ metadata.gz: 36368f5ef5a456e90711881f774a57cf4c3550524c7a3d3cb263aebbb235af0624bf7a3c68c19b21156ab37310cbd197bbf2b54b40d2901a70a4983e442b0468
7
+ data.tar.gz: 86312a088c48e3191d649388dbb6a6aa963ea4d64e23bfdd2edd5d47acb921cac080e5360108812cbac5558fd4d885f8a2eef15baa0a812e160672dee03cb030
data/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ## 0.1.0 - 2026-01-17
6
+
7
+ - Initial release.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Yudai Takada
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,346 @@
1
+ <p align="center">
2
+ <img src="docs/logo-header.svg" alt="nomos header logo">
3
+ <strong>Bring harmony to your pull requests.</strong>
4
+ </p>
5
+ <p align="center">
6
+ <img src="https://img.shields.io/badge/ruby-%3E%3D%203.2-ruby.svg" alt="Ruby Version">
7
+ <img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License">
8
+ <a href="https://github.com/ydah/nomos/actions/workflows/main.yml">
9
+ <img src="https://github.com/ydah/nomos/actions/workflows/main.yml/badge.svg" alt="CI Status">
10
+ </a>
11
+ </p>
12
+
13
+ <p align="center">
14
+ <a href="#features">Features</a> ·
15
+ <a href="#installation">Installation</a> ·
16
+ <a href="#quick-start">Quick Start</a> ·
17
+ <a href="#configuration">Configuration</a> ·
18
+ <a href="#rules">Rules</a> ·
19
+ <a href="#reporters">Reporters</a> ·
20
+ <a href="#how-it-works">How It Works</a>
21
+ </p>
22
+
23
+ ---
24
+
25
+ Nomos evaluates PR metadata and diffs, then reports findings as `message`, `warn`, or `fail`.
26
+ It is designed for fast startup, minimal API calls, and clear configuration.
27
+
28
+ ## Features
29
+
30
+ <a name="features"></a>
31
+
32
+ - Diff-driven by default with optional lazy diff fetching
33
+ - Built-in cache to avoid redundant GitHub API calls
34
+ - Parallel rule execution
35
+ - Built-in rules plus Ruby DSL for custom checks
36
+ - Multiple reporters: GitHub comment, console, JSON
37
+ - Strict mode for CI gating
38
+
39
+ ## Installation
40
+
41
+ <a name="installation"></a>
42
+
43
+ Add to your Gemfile:
44
+
45
+ ```ruby
46
+ gem "nomos"
47
+ ```
48
+
49
+ Then install:
50
+
51
+ ```bash
52
+ bundle install
53
+ ```
54
+
55
+ ## Quick Start
56
+
57
+ <a name="quick-start"></a>
58
+
59
+ Run in CI or locally:
60
+
61
+ ```bash
62
+ nomos run
63
+ ```
64
+
65
+ ### Required ENV
66
+
67
+ - `GITHUB_TOKEN` (GitHub API token)
68
+ - `GITHUB_REPOSITORY` (e.g. `owner/repo`)
69
+ - `GITHUB_EVENT_PATH` (path to GitHub event JSON)
70
+
71
+ Local override:
72
+
73
+ - `NOMOS_REPOSITORY` and `NOMOS_PR_NUMBER` if `GITHUB_EVENT_PATH` is not available
74
+
75
+ ### GitHub Actions
76
+
77
+ ```yaml
78
+ - name: Nomos
79
+ run: nomos run
80
+ env:
81
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
82
+ ```
83
+
84
+ ## Configuration
85
+
86
+ <a name="configuration"></a>
87
+
88
+ Create `nomos.yml`:
89
+
90
+ ```yml
91
+ version: 1
92
+
93
+ reporter:
94
+ github: true
95
+ console: true
96
+
97
+ performance:
98
+ concurrency: 4
99
+ cache: true
100
+ lazy_diff: true
101
+ timing: false
102
+
103
+ rules:
104
+ - name: no_large_pr
105
+ type: builtin.no_large_pr
106
+ params:
107
+ max_changed_lines: 800
108
+
109
+ - name: require_changelog
110
+ type: builtin.require_file_change
111
+ params:
112
+ patterns:
113
+ - CHANGELOG.md
114
+
115
+ - name: custom_rules
116
+ type: ruby.file
117
+ params:
118
+ path: .nomos/rules.rb
119
+ ```
120
+
121
+ Performance notes:
122
+
123
+ - Cache file defaults to `.nomos/cache.json` (override with `performance.cache_path`)
124
+ - Use `--no-cache` to disable cache and lazy diff for a single run
125
+
126
+ ### CLI
127
+
128
+ ```
129
+ nomos run [--config PATH] [--strict] [--debug] [--no-cache] [--reporter github,console,json]
130
+ nomos init
131
+ nomos doctor
132
+ ```
133
+
134
+ ## Rules
135
+
136
+ <a name="rules"></a>
137
+
138
+ ### Built-in rules
139
+
140
+ - `builtin.no_large_pr`
141
+ - `builtin.require_file_change`
142
+ - `builtin.forbid_paths`
143
+ - `builtin.require_labels`
144
+ - `builtin.todo_guard`
145
+
146
+ ### Ruby DSL (`.nomos/rules.rb`)
147
+
148
+ ```rb
149
+ rule "no_debugger" do
150
+ changed_files.grep(/\.rb$/).each do |file|
151
+ if diff(file).include?("binding.pry")
152
+ fail "binding.pry detected", file: file
153
+ end
154
+ end
155
+ end
156
+ ```
157
+
158
+ Available DSL API:
159
+
160
+ #### changed_files
161
+
162
+ Array of changed file paths.
163
+
164
+ ```rb
165
+ rule "example_changed_files" do
166
+ changed_files.grep(/\.md$/).each do |file|
167
+ message "Docs updated", file: file
168
+ end
169
+ end
170
+ ```
171
+
172
+ #### diff(file)
173
+
174
+ Unified diff for a file (string; empty if unavailable).
175
+
176
+ ```rb
177
+ rule "example_diff" do
178
+ if diff("lib/app.rb").include?("binding.pry")
179
+ fail "Debug hook found", file: "lib/app.rb"
180
+ end
181
+ end
182
+ ```
183
+
184
+ #### pr_title
185
+
186
+ PR title string.
187
+
188
+ ```rb
189
+ rule "example_pr_title" do
190
+ warn "Title should start with [chore]", file: "PR" unless pr_title.start_with?("[chore]")
191
+ end
192
+ ```
193
+
194
+ #### pr_body
195
+
196
+ PR body string.
197
+
198
+ ```rb
199
+ rule "example_pr_body" do
200
+ fail "PR body must include a checklist", file: "PR" unless pr_body.to_s.include?("- [ ]")
201
+ end
202
+ ```
203
+
204
+ #### pr_number
205
+
206
+ PR number.
207
+
208
+ ```rb
209
+ rule "example_pr_number" do
210
+ message "Reviewing PR ##{pr_number}"
211
+ end
212
+ ```
213
+
214
+ #### pr_author
215
+
216
+ PR author login.
217
+
218
+ ```rb
219
+ rule "example_pr_author" do
220
+ warn "First-time contributor", file: "PR" if pr_author == "new-contributor"
221
+ end
222
+ ```
223
+
224
+ #### pr_labels
225
+
226
+ Array of label names.
227
+
228
+ ```rb
229
+ rule "example_pr_labels" do
230
+ fail "Missing security label", file: "PR" unless pr_labels.include?("security")
231
+ end
232
+ ```
233
+
234
+ #### repo
235
+
236
+ Repository identifier (`owner/repo`).
237
+
238
+ ```rb
239
+ rule "example_repo" do
240
+ message "Running in #{repo}"
241
+ end
242
+ ```
243
+
244
+ #### base_branch
245
+
246
+ Base branch name.
247
+
248
+ ```rb
249
+ rule "example_base_branch" do
250
+ warn "Target branch should be main", file: "PR" unless base_branch == "main"
251
+ end
252
+ ```
253
+
254
+ #### ci
255
+
256
+ CI context hash.
257
+
258
+ ```rb
259
+ rule "example_ci" do
260
+ fail "Missing CI provider info", file: "CI" unless ci["provider"]
261
+ end
262
+ ```
263
+
264
+ #### message(text, **opts)
265
+
266
+ Add informational finding.
267
+
268
+ ```rb
269
+ rule "example_message" do
270
+ message "Heads up", file: "README.md", line: 1, code: "docs"
271
+ end
272
+ ```
273
+
274
+ #### warn(text, **opts)
275
+
276
+ Add warning finding.
277
+
278
+ ```rb
279
+ rule "example_warn" do
280
+ warn "Large change set", file: "PR", code: "size"
281
+ end
282
+ ```
283
+
284
+ #### fail(text, **opts)
285
+
286
+ Add failure finding.
287
+
288
+ ```rb
289
+ rule "example_fail" do
290
+ fail "Missing CHANGELOG entry", file: "CHANGELOG.md", code: "changelog"
291
+ end
292
+ ```
293
+
294
+ ### Adding custom rules
295
+
296
+ 1. Create `.nomos/rules.rb` and define one or more `rule "name"` blocks.
297
+ 2. Register the file in `nomos.yml` under `rules` with `type: ruby.file` and `params.path: .nomos/rules.rb`.
298
+ 3. Run `nomos run` (or your CI job) to verify the rule executes.
299
+
300
+ Example:
301
+
302
+ ```rb
303
+ # .nomos/rules.rb
304
+ rule "require_docs_change" do
305
+ unless changed_files.any? { |file| file.start_with?("docs/") }
306
+ fail "Docs must be updated for this change", file: "docs/"
307
+ end
308
+ end
309
+ ```
310
+
311
+ ```yml
312
+ # nomos.yml
313
+ rules:
314
+ - name: require_docs_change
315
+ type: ruby.file
316
+ params:
317
+ path: .nomos/rules.rb
318
+ ```
319
+
320
+ ## Reporters
321
+
322
+ <a name="reporters"></a>
323
+
324
+ - GitHub comment reporter
325
+ - Console reporter
326
+ - JSON reporter (for post-processing)
327
+
328
+ ## How It Works
329
+
330
+ <a name="how-it-works"></a>
331
+
332
+ 1. Load PR context from GitHub API or event payload
333
+ 2. Fetch changed files and patches (lazy diff optional)
334
+ 3. Run rules in parallel where safe
335
+ 4. Report findings to configured outputs
336
+ 5. Exit with CI-friendly status
337
+
338
+ ## Development
339
+
340
+ ```bash
341
+ bundle exec rspec
342
+ ```
343
+
344
+ ## License
345
+
346
+ MIT License. See `LICENSE` file for details.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec