carson 2.18.0 → 2.19.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 +4 -4
- data/API.md +14 -1
- data/MANUAL.md +25 -8
- data/RELEASE.md +24 -0
- data/VERSION +1 -1
- data/lib/carson/config.rb +29 -3
- data/lib/carson/runtime/local.rb +26 -10
- metadata +1 -3
- data/templates/.github/.mega-linter.yml +0 -29
- data/templates/.github/workflows/carson-lint.yml +0 -23
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b6b2ecf51c931d6c85244d96e294ce87a86583e3a807782ddd74c9058c647563
|
|
4
|
+
data.tar.gz: 19b49e67b2bdefe3443aa00500394cc479951eb074498d82b69ff3f776b42b15
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: acc11f185996f6e424b18bbc55ed6194ae87d31db6de09b9b34fc50237c87ada00ab8c1c3809cf9d0b3654353e24cf1a2fb1b9fd6134610a57ded49d4fbe1a5c
|
|
7
|
+
data.tar.gz: c27ac61fba18b5cf449a33b8703337282b5a30f0cf87568e24320acd56b030b57093ba8d24466c92450745dc61f0eaa83f2c5db603cd242e0e6b2413233331d0
|
data/API.md
CHANGED
|
@@ -79,7 +79,7 @@ Allowed Carson-managed persistence in host repositories:
|
|
|
79
79
|
- `.github/CLAUDE.md` — agent discovery pointer for Claude Code
|
|
80
80
|
- `.github/AGENTS.md` — agent discovery pointer for Codex
|
|
81
81
|
- `.github/pull_request_template.md` — PR template
|
|
82
|
-
-
|
|
82
|
+
- Any file discovered from `template.canonical` — user's canonical `.github/` files
|
|
83
83
|
|
|
84
84
|
## Configuration interface
|
|
85
85
|
|
|
@@ -134,6 +134,19 @@ Environment overrides:
|
|
|
134
134
|
- `merge.authority`: `true` (default) — Carson may merge autonomously. Set to `false` to require explicit enablement.
|
|
135
135
|
- `merge.method`: `"squash"` (default), `"merge"`, or `"rebase"`.
|
|
136
136
|
|
|
137
|
+
`template` schema:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"template": {
|
|
142
|
+
"canonical": "~/AI/LINT"
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`template` semantics:
|
|
148
|
+
- `canonical`: path to a directory of canonical `.github/` files. Carson discovers files in this directory and syncs them to governed repos alongside its own governance files. The directory mirrors `.github/` structure — `workflows/lint.yml` deploys to `.github/workflows/lint.yml`. Default: `nil` (no canonical files).
|
|
149
|
+
|
|
137
150
|
`lint` schema:
|
|
138
151
|
|
|
139
152
|
```json
|
data/MANUAL.md
CHANGED
|
@@ -99,16 +99,33 @@ Notes:
|
|
|
99
99
|
- `CARSON_READ_TOKEN` must have read access to your policy source repository so CI can run `carson lint policy`.
|
|
100
100
|
- The reusable workflow installs a pinned RuboCop gem before `carson audit`; mirror the same pin in host governance workflows for deterministic checks.
|
|
101
101
|
|
|
102
|
-
###
|
|
102
|
+
### Canonical Templates
|
|
103
103
|
|
|
104
|
-
Carson manages
|
|
104
|
+
Carson manages 5 governance files (carson.md, CLAUDE.md, AGENTS.md, copilot-instructions.md, pull_request_template.md). Beyond those, you can tell Carson about your own canonical `.github/` files — CI workflows, linter configs, dependabot settings, anything that belongs in `.github/`.
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
- **`carson lint policy`** distributes the rules into each repo.
|
|
108
|
-
- **MegaLinter** (in GitHub Actions) enforces the rules.
|
|
109
|
-
- **`carson govern`** reads CI check status (including MegaLinter results) and acts on it.
|
|
106
|
+
Set `template.canonical` in `~/.carson/config.json`:
|
|
110
107
|
|
|
111
|
-
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"template": {
|
|
111
|
+
"canonical": "~/AI/LINT"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
That directory mirrors the `.github/` structure:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
~/AI/LINT/
|
|
120
|
+
├── workflows/
|
|
121
|
+
│ └── lint.yml → deployed to .github/workflows/lint.yml
|
|
122
|
+
├── .mega-linter.yml → deployed to .github/.mega-linter.yml
|
|
123
|
+
└── dependabot.yml → deployed to .github/dependabot.yml
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Carson discovers files in this directory and syncs them to governed repos alongside its own governance files. `carson template check` detects drift, `carson template apply` writes them, and `carson refresh` propagates them to the remote.
|
|
127
|
+
|
|
128
|
+
**Why this design.** Lint, CI, and tooling config are personal decisions — not governance decisions. Carson's job is to deliver your canonical files reliably, not to decide what they should contain.
|
|
112
129
|
|
|
113
130
|
## Daily Operations
|
|
114
131
|
|
|
@@ -200,7 +217,7 @@ Carson's `govern.merge.method` controls how `carson govern` merges ready PRs. Th
|
|
|
200
217
|
These define what Carson *is*. They are not configurable.
|
|
201
218
|
|
|
202
219
|
- **Outsider boundary** — Carson never places its own artefacts inside a governed repository.
|
|
203
|
-
- **
|
|
220
|
+
- **Canonical delivery** — your canonical `.github/` files distributed into each governed repo, zero per-repo drift. What those files contain is your call.
|
|
204
221
|
- **Active review** — undisposed reviewer findings block merge; feedback must be acknowledged.
|
|
205
222
|
- **Self-diagnosing output** — every warning and error names what went wrong, why, and what to do next.
|
|
206
223
|
- **Transparent governance** — Carson prepares everything for merge but never makes decisions without telling you.
|
data/RELEASE.md
CHANGED
|
@@ -5,6 +5,30 @@ Release-note scope rule:
|
|
|
5
5
|
- `RELEASE.md` records only version deltas, breaking changes, and migration actions.
|
|
6
6
|
- Operational usage guides live in `MANUAL.md` and `API.md`.
|
|
7
7
|
|
|
8
|
+
## 2.19.0 — Canonical Templates, Lint Removed
|
|
9
|
+
|
|
10
|
+
### What changed
|
|
11
|
+
|
|
12
|
+
- **Lint templates removed from Carson.** `carson-lint.yml` and `.mega-linter.yml` are no longer managed by Carson. Both are now superseded — `carson refresh` will delete them from governed repos automatically. Lint is a personal decision, not a governance decision.
|
|
13
|
+
- **New `template.canonical` config key.** Point Carson at a directory of your canonical `.github/` files and Carson syncs them to all governed repos alongside its own governance files. You control the content; Carson handles the delivery.
|
|
14
|
+
|
|
15
|
+
### Migration
|
|
16
|
+
|
|
17
|
+
1. Run `carson refresh` in each governed repo. Carson will remove the old lint files automatically.
|
|
18
|
+
2. If you want lint, create your own workflow files and set `template.canonical` in `~/.carson/config.json`:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"template": {
|
|
23
|
+
"canonical": "~/AI/LINT"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
That directory mirrors `.github/` structure — for example, `workflows/lint.yml` deploys to `.github/workflows/lint.yml`.
|
|
29
|
+
|
|
30
|
+
3. Run `carson refresh` again to deploy your canonical files.
|
|
31
|
+
|
|
8
32
|
## 2.18.0 — Audit Attention Detail
|
|
9
33
|
|
|
10
34
|
### What changed
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.
|
|
1
|
+
2.19.0
|
data/lib/carson/config.rb
CHANGED
|
@@ -8,7 +8,7 @@ module Carson
|
|
|
8
8
|
class Config
|
|
9
9
|
attr_accessor :git_remote
|
|
10
10
|
attr_reader :main_branch, :protected_branches, :hooks_base_path, :required_hooks,
|
|
11
|
-
:path_groups, :template_managed_files, :template_superseded_files,
|
|
11
|
+
:path_groups, :template_managed_files, :template_superseded_files, :template_canonical,
|
|
12
12
|
:lint_policy_source,
|
|
13
13
|
:review_wait_seconds, :review_poll_seconds, :review_max_polls, :review_sweep_window_days,
|
|
14
14
|
:review_sweep_states, :review_disposition_prefix, :review_risk_keywords,
|
|
@@ -48,8 +48,9 @@ module Carson
|
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
"template" => {
|
|
51
|
-
"managed_files" => [ ".github/carson.md", ".github/copilot-instructions.md", ".github/CLAUDE.md", ".github/AGENTS.md", ".github/pull_request_template.md"
|
|
52
|
-
"superseded_files" => [ ".github/carson-instructions.md" ]
|
|
51
|
+
"managed_files" => [ ".github/carson.md", ".github/copilot-instructions.md", ".github/CLAUDE.md", ".github/AGENTS.md", ".github/pull_request_template.md" ],
|
|
52
|
+
"superseded_files" => [ ".github/carson-instructions.md", ".github/workflows/carson-lint.yml", ".github/.mega-linter.yml" ],
|
|
53
|
+
"canonical" => nil
|
|
53
54
|
},
|
|
54
55
|
"lint" => {
|
|
55
56
|
"policy_source" => "wanghailei/lint.git"
|
|
@@ -218,6 +219,8 @@ module Carson
|
|
|
218
219
|
|
|
219
220
|
@template_managed_files = fetch_string_array( hash: fetch_hash( hash: data, key: "template" ), key: "managed_files" )
|
|
220
221
|
@template_superseded_files = fetch_optional_string_array( hash: fetch_hash( hash: data, key: "template" ), key: "superseded_files" )
|
|
222
|
+
@template_canonical = fetch_optional_path( hash: fetch_hash( hash: data, key: "template" ), key: "canonical" )
|
|
223
|
+
resolve_canonical_files!
|
|
221
224
|
lint_hash = fetch_hash( hash: data, key: "lint" )
|
|
222
225
|
@lint_policy_source = lint_hash.fetch( "policy_source", "" ).to_s.strip
|
|
223
226
|
|
|
@@ -347,5 +350,28 @@ module Carson
|
|
|
347
350
|
rescue ArgumentError
|
|
348
351
|
path
|
|
349
352
|
end
|
|
353
|
+
|
|
354
|
+
# Returns an expanded path string, or nil when the value is absent/blank.
|
|
355
|
+
def fetch_optional_path( hash:, key: )
|
|
356
|
+
value = hash[ key ]
|
|
357
|
+
return nil if value.nil?
|
|
358
|
+
text = value.to_s.strip
|
|
359
|
+
return nil if text.empty?
|
|
360
|
+
safe_expand_path( text )
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
# Discovers files in the canonical directory and appends them to managed_files.
|
|
364
|
+
# Canonical files mirror the .github/ structure and are synced alongside Carson's own governance files.
|
|
365
|
+
def resolve_canonical_files!
|
|
366
|
+
return if @template_canonical.nil? || @template_canonical.empty?
|
|
367
|
+
return unless Dir.exist?( @template_canonical )
|
|
368
|
+
|
|
369
|
+
Dir.glob( File.join( @template_canonical, "**", "*" ) ).sort.each do |absolute_path|
|
|
370
|
+
next unless File.file?( absolute_path )
|
|
371
|
+
relative = absolute_path.delete_prefix( "#{@template_canonical}/" )
|
|
372
|
+
managed_path = ".github/#{relative}"
|
|
373
|
+
@template_managed_files << managed_path unless @template_managed_files.include?( managed_path )
|
|
374
|
+
end
|
|
375
|
+
end
|
|
350
376
|
end
|
|
351
377
|
end
|
data/lib/carson/runtime/local.rb
CHANGED
|
@@ -483,10 +483,8 @@ module Carson
|
|
|
483
483
|
# Also removes superseded files present in the worktree.
|
|
484
484
|
def template_propagate_write_files!( worktree_dir: )
|
|
485
485
|
config.template_managed_files.each do |managed_file|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
template_path = File.join( github_templates_dir, File.basename( managed_file ) ) unless File.file?( template_path )
|
|
489
|
-
next unless File.file?( template_path )
|
|
486
|
+
template_path = template_source_path( managed_file: managed_file )
|
|
487
|
+
next if template_path.nil?
|
|
490
488
|
|
|
491
489
|
target_path = File.join( worktree_dir, managed_file )
|
|
492
490
|
FileUtils.mkdir_p( File.dirname( target_path ) )
|
|
@@ -665,12 +663,8 @@ module Carson
|
|
|
665
663
|
|
|
666
664
|
# Calculates whole-file expected content and returns sync status plus apply payload.
|
|
667
665
|
def template_result_for_file( managed_file: )
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
relative_within_github = managed_file.delete_prefix( ".github/" )
|
|
671
|
-
template_path = File.join( github_templates_dir, relative_within_github )
|
|
672
|
-
template_path = File.join( github_templates_dir, File.basename( managed_file ) ) unless File.file?( template_path )
|
|
673
|
-
return { file: managed_file, status: "error", reason: "missing template #{File.basename( managed_file )}", applied_content: nil } unless File.file?( template_path )
|
|
666
|
+
template_path = template_source_path( managed_file: managed_file )
|
|
667
|
+
return { file: managed_file, status: "error", reason: "missing template #{File.basename( managed_file )}", applied_content: nil } if template_path.nil?
|
|
674
668
|
|
|
675
669
|
expected_content = normalize_text( text: File.read( template_path ) )
|
|
676
670
|
file_path = resolve_repo_path!( relative_path: managed_file, label: "template.managed_files entry #{managed_file}" )
|
|
@@ -692,6 +686,28 @@ module Carson
|
|
|
692
686
|
File.join( tool_root, "templates", ".github" )
|
|
693
687
|
end
|
|
694
688
|
|
|
689
|
+
# Resolves the source file path for a managed template.
|
|
690
|
+
# Checks the user's canonical directory first, then falls back to Carson's built-in templates.
|
|
691
|
+
def template_source_path( managed_file: )
|
|
692
|
+
relative_within_github = managed_file.delete_prefix( ".github/" )
|
|
693
|
+
|
|
694
|
+
# Canonical source: the user's canonical .github/ files.
|
|
695
|
+
canonical = config.template_canonical
|
|
696
|
+
if canonical && !canonical.empty?
|
|
697
|
+
canonical_path = File.join( canonical, relative_within_github )
|
|
698
|
+
return canonical_path if File.file?( canonical_path )
|
|
699
|
+
end
|
|
700
|
+
|
|
701
|
+
# Carson built-in templates: subdirectory-aware path first, then flat basename fallback.
|
|
702
|
+
template_path = File.join( github_templates_dir, relative_within_github )
|
|
703
|
+
return template_path if File.file?( template_path )
|
|
704
|
+
|
|
705
|
+
basename_path = File.join( github_templates_dir, File.basename( managed_file ) )
|
|
706
|
+
return basename_path if File.file?( basename_path )
|
|
707
|
+
|
|
708
|
+
nil
|
|
709
|
+
end
|
|
710
|
+
|
|
695
711
|
# Canonical hook template location inside Carson repository.
|
|
696
712
|
def hook_template_path( hook_name: )
|
|
697
713
|
File.join( tool_root, "hooks", hook_name )
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: carson
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.19.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Hailei Wang
|
|
@@ -63,13 +63,11 @@ files:
|
|
|
63
63
|
- lib/carson/runtime/review/utility.rb
|
|
64
64
|
- lib/carson/runtime/setup.rb
|
|
65
65
|
- lib/carson/version.rb
|
|
66
|
-
- templates/.github/.mega-linter.yml
|
|
67
66
|
- templates/.github/AGENTS.md
|
|
68
67
|
- templates/.github/CLAUDE.md
|
|
69
68
|
- templates/.github/carson.md
|
|
70
69
|
- templates/.github/copilot-instructions.md
|
|
71
70
|
- templates/.github/pull_request_template.md
|
|
72
|
-
- templates/.github/workflows/carson-lint.yml
|
|
73
71
|
homepage: https://github.com/wanghailei/carson
|
|
74
72
|
licenses:
|
|
75
73
|
- MIT
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# Carson-managed MegaLinter configuration.
|
|
2
|
-
# Pushed to governed repositories by `carson template apply`.
|
|
3
|
-
# To override, add entries to a local .mega-linter.yml — MegaLinter merges both.
|
|
4
|
-
|
|
5
|
-
# Use project-root linter configs (.rubocop.yml, .eslintrc, etc.)
|
|
6
|
-
# instead of MegaLinter's built-in defaults.
|
|
7
|
-
LINTER_RULES_PATH: "."
|
|
8
|
-
|
|
9
|
-
# Only lint changed files on PRs, not the entire codebase.
|
|
10
|
-
VALIDATE_ALL_CODEBASE: false
|
|
11
|
-
|
|
12
|
-
# Exclude vendored, generated, and dependency directories.
|
|
13
|
-
FILTER_REGEX_EXCLUDE: "(vendor/|node_modules/|public/packs|public/assets|tmp/|log/|coverage/)"
|
|
14
|
-
|
|
15
|
-
# Lint code, not prose. Disable documentation-oriented descriptors.
|
|
16
|
-
DISABLE:
|
|
17
|
-
- MARKDOWN
|
|
18
|
-
- RST
|
|
19
|
-
- SPELL
|
|
20
|
-
|
|
21
|
-
# Disable linters that are too noisy without per-project configuration.
|
|
22
|
-
# checkov/kics flag Carson workflow permissions as overly permissive.
|
|
23
|
-
# devskim floods Rails apps with false-positive security warnings.
|
|
24
|
-
DISABLE_LINTERS:
|
|
25
|
-
- COPYPASTE_JSCPD
|
|
26
|
-
- HTML_DJLINT
|
|
27
|
-
- REPOSITORY_CHECKOV
|
|
28
|
-
- REPOSITORY_DEVSKIM
|
|
29
|
-
- REPOSITORY_KICS
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
name: Carson Lint
|
|
2
|
-
on:
|
|
3
|
-
pull_request:
|
|
4
|
-
branches: [main, master]
|
|
5
|
-
push:
|
|
6
|
-
branches: [main, master]
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
lint:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
permissions:
|
|
12
|
-
contents: read
|
|
13
|
-
issues: write
|
|
14
|
-
pull-requests: write
|
|
15
|
-
steps:
|
|
16
|
-
- uses: actions/checkout@v4
|
|
17
|
-
with:
|
|
18
|
-
fetch-depth: 0
|
|
19
|
-
- uses: oxsecurity/megalinter@v8
|
|
20
|
-
env:
|
|
21
|
-
MEGALINTER_CONFIG: .github/.mega-linter.yml
|
|
22
|
-
VALIDATE_ALL_CODEBASE: false
|
|
23
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|