split-by-codeowners 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.
- package/LICENSE +21 -0
- package/README.md +181 -0
- package/action.yml +109 -0
- package/dist/index.js +40807 -0
- package/dist/index.js.map +1 -0
- package/dist/sourcemap-register.js +1 -0
- package/dist-cli/index.js +13365 -0
- package/dist-cli/index.js.map +1 -0
- package/dist-cli/sourcemap-register.js +1 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Anatolii (Nate) Kurochkin
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# split-by-codeowners
|
|
2
|
+
|
|
3
|
+
Split a set of local changes into **CODEOWNERS buckets** and (optionally) create **one PR per bucket**.
|
|
4
|
+
|
|
5
|
+
Works in two modes sharing the same core logic:
|
|
6
|
+
|
|
7
|
+
- **GitHub Action**: run in CI after your codemod step; generates patches + can create/update PRs (no third-party PR actions).
|
|
8
|
+
- **CLI (`npx`)**: run locally to bucketize current working tree changes; can create/update PRs using `gh` for best dev UX.
|
|
9
|
+
|
|
10
|
+
## Why
|
|
11
|
+
|
|
12
|
+
If a codemod touches files owned by different teams, you often want:
|
|
13
|
+
|
|
14
|
+
- smaller PRs
|
|
15
|
+
- clearer ownership/review routing
|
|
16
|
+
- independent merge/rollback per owner group
|
|
17
|
+
|
|
18
|
+
This tool groups changed files by their **effective CODEOWNERS owner set** (last-match-wins semantics).
|
|
19
|
+
|
|
20
|
+
## Quickstart (GitHub Action)
|
|
21
|
+
|
|
22
|
+
```yaml
|
|
23
|
+
permissions:
|
|
24
|
+
contents: write
|
|
25
|
+
pull-requests: write
|
|
26
|
+
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v4
|
|
29
|
+
- name: Run codemods
|
|
30
|
+
run: ./run-codemods.sh
|
|
31
|
+
|
|
32
|
+
- name: Split into CODEOWNERS PRs
|
|
33
|
+
uses: anatoliisf/split-by-codeowners@v1
|
|
34
|
+
with:
|
|
35
|
+
create_prs: "true"
|
|
36
|
+
github_token: ${{ github.token }}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quickstart (CLI)
|
|
40
|
+
|
|
41
|
+
Bucketize + write patches:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx split-by-codeowners
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Create/update PRs locally (recommended: `gh` auth):
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
gh auth login -h github.com
|
|
51
|
+
npx split-by-codeowners --create-prs --base-branch main
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## GitHub Action
|
|
55
|
+
|
|
56
|
+
### Inputs
|
|
57
|
+
|
|
58
|
+
| Name | Required | Default | Description |
|
|
59
|
+
| --- | --- | --- | --- |
|
|
60
|
+
| `codeowners_path` | no | `CODEOWNERS` | Path to CODEOWNERS file |
|
|
61
|
+
| `base_ref` | no | `""` | Base ref for changed-files discovery (currently workspace-focused; see notes) |
|
|
62
|
+
| `include_unowned` | no | `"true"` | Include files with no owners in a special bucket |
|
|
63
|
+
| `unowned_bucket_key` | no | `__UNOWNED__` | Bucket key for unowned files |
|
|
64
|
+
| `max_buckets` | no | `"30"` | Fail if buckets exceed this number |
|
|
65
|
+
| `exclude_patterns` | no | `""` | Newline-separated glob patterns to exclude (minimatch) |
|
|
66
|
+
| `patch_dir` | no | `bucket-patches` | Directory to write per-bucket patch files |
|
|
67
|
+
| `bucket_prefix` | no | `bucket` | Patch file prefix |
|
|
68
|
+
| `dry_run` | no | `"false"` | Compute buckets but don’t write patches |
|
|
69
|
+
| `cleanup_patches` | no | `"false"` | Delete `patch_dir` after a successful run |
|
|
70
|
+
| `create_prs` | no | `"false"` | Create/update one PR per bucket |
|
|
71
|
+
| `github_token` | no | `""` | Token used for pushing branches + GitHub API (defaults to env `GITHUB_TOKEN`) |
|
|
72
|
+
| `base_branch` | no | `""` | Base branch for PRs (defaults to repo default branch) |
|
|
73
|
+
| `branch_prefix` | no | `codemods/` | Prefix for created branches |
|
|
74
|
+
| `commit_message` | no | `chore: automated changes` | Commit message for bucket PRs |
|
|
75
|
+
| `pr_title` | no | `chore: automated changes ({owners})` | PR title template (`{owners}`, `{bucket_key}`) |
|
|
76
|
+
| `pr_body` | no | *(see `action.yml`)* | PR body template (`{owners}`, `{bucket_key}`, `{files}`) |
|
|
77
|
+
| `draft` | no | `"false"` | Create PRs as drafts |
|
|
78
|
+
|
|
79
|
+
### Outputs
|
|
80
|
+
|
|
81
|
+
| Name | Description |
|
|
82
|
+
| --- | --- |
|
|
83
|
+
| `matrix_json` | JSON for `strategy.matrix` (`{ include: [...] }`) |
|
|
84
|
+
| `buckets_json` | Full buckets JSON (owners + files + matched rule) |
|
|
85
|
+
| `prs_json` | If `create_prs=true`, list of created/updated PRs |
|
|
86
|
+
|
|
87
|
+
### Example: bucketize only (matrix + patches)
|
|
88
|
+
|
|
89
|
+
```yaml
|
|
90
|
+
- name: Bucketize (patches + matrix)
|
|
91
|
+
id: split
|
|
92
|
+
uses: anatoliisf/split-by-codeowners@v1
|
|
93
|
+
with:
|
|
94
|
+
create_prs: "false"
|
|
95
|
+
|
|
96
|
+
- name: Use matrix
|
|
97
|
+
run: echo '${{ steps.split.outputs.matrix_json }}'
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Required permissions (when `create_prs=true`)
|
|
101
|
+
|
|
102
|
+
At minimum:
|
|
103
|
+
|
|
104
|
+
```yaml
|
|
105
|
+
permissions:
|
|
106
|
+
contents: write
|
|
107
|
+
pull-requests: write
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## CLI
|
|
111
|
+
|
|
112
|
+
The CLI operates on your **current working tree** (modified + untracked files) and groups them by CODEOWNERS.
|
|
113
|
+
|
|
114
|
+
### Usage
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
npx split-by-codeowners --help
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Common examples
|
|
121
|
+
|
|
122
|
+
Exclude some paths:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
npx split-by-codeowners --exclude - < excludes.txt
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Create/update PRs:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
npx split-by-codeowners --create-prs --base-branch main
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Force token auth locally (instead of `gh`):
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
export GH_TOKEN=...
|
|
138
|
+
npx split-by-codeowners --create-prs --token "$GH_TOKEN" --base-branch main
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Notes on local PR creation
|
|
142
|
+
|
|
143
|
+
- Locally (no `GITHUB_ACTIONS`), the tool **prefers `gh`** for PR creation.
|
|
144
|
+
- In GitHub Actions (`GITHUB_ACTIONS=true`), the tool **requires a token** and uses API auth.
|
|
145
|
+
|
|
146
|
+
## How it buckets files
|
|
147
|
+
|
|
148
|
+
- Uses CODEOWNERS **last matching rule wins** for each file.
|
|
149
|
+
- Bucket key is the sorted owners list (normalized) or `unowned_bucket_key`.
|
|
150
|
+
|
|
151
|
+
## Troubleshooting
|
|
152
|
+
|
|
153
|
+
### “Permission denied to github-actions[bot]”
|
|
154
|
+
|
|
155
|
+
Ensure workflow permissions include:
|
|
156
|
+
|
|
157
|
+
- `contents: write`
|
|
158
|
+
- `pull-requests: write`
|
|
159
|
+
|
|
160
|
+
### “Too many buckets”
|
|
161
|
+
|
|
162
|
+
Raise `max_buckets` or add `exclude_patterns` to avoid noisy files (lockfiles, snapshots, etc.).
|
|
163
|
+
|
|
164
|
+
## Development
|
|
165
|
+
|
|
166
|
+
Build bundles (committed `dist/` is required for Marketplace Actions):
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
npm ci
|
|
170
|
+
npm run build
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Maintainers
|
|
174
|
+
|
|
175
|
+
### Publish CLI to npm (manual)
|
|
176
|
+
|
|
177
|
+
This repo includes a manual workflow: `.github/workflows/publish-npm.yml`.
|
|
178
|
+
|
|
179
|
+
- Create an npm token with publish rights and add it as repo secret **`NPM_TOKEN`**.
|
|
180
|
+
- Bump `package.json` version and ensure `dist/` and `dist-cli/` are up to date.
|
|
181
|
+
- Run the workflow from the GitHub Actions UI (`workflow_dispatch`).
|
package/action.yml
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
name: "Split changes by CODEOWNERS (bucketize + patches)"
|
|
2
|
+
description: "Bucketizes local git changes by effective CODEOWNERS and can optionally create one PR per bucket (no third-party PR actions)."
|
|
3
|
+
author: "anatoliisf"
|
|
4
|
+
branding:
|
|
5
|
+
icon: "shuffle"
|
|
6
|
+
color: "blue"
|
|
7
|
+
|
|
8
|
+
inputs:
|
|
9
|
+
codeowners_path:
|
|
10
|
+
description: "Path to CODEOWNERS. Defaults to CODEOWNERS at repo root."
|
|
11
|
+
required: false
|
|
12
|
+
default: "CODEOWNERS"
|
|
13
|
+
|
|
14
|
+
base_ref:
|
|
15
|
+
description: "Optional base ref for changed files discovery. If empty, uses HEAD vs working tree."
|
|
16
|
+
required: false
|
|
17
|
+
default: ""
|
|
18
|
+
|
|
19
|
+
include_unowned:
|
|
20
|
+
description: "Include files with no owners in a special bucket"
|
|
21
|
+
required: false
|
|
22
|
+
default: "true"
|
|
23
|
+
|
|
24
|
+
unowned_bucket_key:
|
|
25
|
+
description: "Bucket key for unowned files"
|
|
26
|
+
required: false
|
|
27
|
+
default: "__UNOWNED__"
|
|
28
|
+
|
|
29
|
+
max_buckets:
|
|
30
|
+
description: "Fail if buckets exceed this number"
|
|
31
|
+
required: false
|
|
32
|
+
default: "30"
|
|
33
|
+
|
|
34
|
+
exclude_patterns:
|
|
35
|
+
description: "Newline-separated glob patterns to exclude"
|
|
36
|
+
required: false
|
|
37
|
+
default: ""
|
|
38
|
+
|
|
39
|
+
patch_dir:
|
|
40
|
+
description: "Directory to write patches"
|
|
41
|
+
required: false
|
|
42
|
+
default: "bucket-patches"
|
|
43
|
+
|
|
44
|
+
bucket_prefix:
|
|
45
|
+
description: "Patch file prefix"
|
|
46
|
+
required: false
|
|
47
|
+
default: "bucket"
|
|
48
|
+
|
|
49
|
+
dry_run:
|
|
50
|
+
description: "Compute buckets but don't write patches"
|
|
51
|
+
required: false
|
|
52
|
+
default: "false"
|
|
53
|
+
|
|
54
|
+
cleanup_patches:
|
|
55
|
+
description: "If true, delete patch_dir after successful run (useful when create_prs=true)."
|
|
56
|
+
required: false
|
|
57
|
+
default: "false"
|
|
58
|
+
|
|
59
|
+
create_prs:
|
|
60
|
+
description: "If true, create/update one PR per bucket by pushing branches and calling GitHub API."
|
|
61
|
+
required: false
|
|
62
|
+
default: "false"
|
|
63
|
+
|
|
64
|
+
github_token:
|
|
65
|
+
description: "GitHub token used for API + pushing branches. Defaults to GITHUB_TOKEN."
|
|
66
|
+
required: false
|
|
67
|
+
default: ""
|
|
68
|
+
|
|
69
|
+
base_branch:
|
|
70
|
+
description: "Base branch to open PRs against. If empty, uses repo default branch."
|
|
71
|
+
required: false
|
|
72
|
+
default: ""
|
|
73
|
+
|
|
74
|
+
branch_prefix:
|
|
75
|
+
description: "Prefix for created branches."
|
|
76
|
+
required: false
|
|
77
|
+
default: "codemods/"
|
|
78
|
+
|
|
79
|
+
commit_message:
|
|
80
|
+
description: "Commit message used in bucket PRs."
|
|
81
|
+
required: false
|
|
82
|
+
default: "chore: automated changes"
|
|
83
|
+
|
|
84
|
+
pr_title:
|
|
85
|
+
description: "PR title template. Supports {owners} and {bucket_key}."
|
|
86
|
+
required: false
|
|
87
|
+
default: "chore: automated changes ({owners})"
|
|
88
|
+
|
|
89
|
+
pr_body:
|
|
90
|
+
description: "PR body template. Supports {owners}, {bucket_key}, {files}."
|
|
91
|
+
required: false
|
|
92
|
+
default: "Automated changes bucketed by CODEOWNERS.\n\nOwners: {owners}\nBucket key: {bucket_key}\n\nFiles:\n{files}\n"
|
|
93
|
+
|
|
94
|
+
draft:
|
|
95
|
+
description: "Create PRs as drafts."
|
|
96
|
+
required: false
|
|
97
|
+
default: "false"
|
|
98
|
+
|
|
99
|
+
outputs:
|
|
100
|
+
matrix_json:
|
|
101
|
+
description: "JSON for strategy.matrix (one bucket per job)"
|
|
102
|
+
buckets_json:
|
|
103
|
+
description: "Full buckets JSON"
|
|
104
|
+
prs_json:
|
|
105
|
+
description: "If create_prs=true, JSON list of created/updated PRs (url + number + bucket_key)."
|
|
106
|
+
|
|
107
|
+
runs:
|
|
108
|
+
using: "node20"
|
|
109
|
+
main: "dist/index.js"
|