Setting the file. One moment. Run Ownership Map · Security Ownership Map · openai/skills · Skills Docsscripts/run_ownership_map.py
scripts/run_ownership_map.py
Python·200 lines·6 KB
14 description="Run build_ownership_map.py with sensible defaults."
15 )
16 parser.add_argument("--repo", default=".", help="Path to the git repo (default: .)")
17 parser.add_argument(
18 "--out",
19 default="ownership-map-out",
20 help="Output directory for graph artifacts",
21 )
22 parser.add_argument("--since", default=None, help="Limit git log to commits since date")
23 parser.add_argument("--until", default=None, help="Limit git log to commits until date")
24 parser.add_argument(
25 "--identity",
26 choices=("author", "committer"),
27 default="author",
28 help="Identity to attribute touches to",
29 )
30 parser.add_argument(
31 "--date-field",
32 choices=("author", "committer"),
33 default="author",
34 help="Date field to use for recency and bucketing",
35 )
36 parser.add_argument(
37 "--include-merges",
38 action="store_true",
39 help="Include merge commits (excluded by default)",
40 )
41 parser.add_argument(
42 "--emit-commits",
43 action="store_true",
44 help="Write commit list to commits.jsonl",
45 )
46 parser.add_argument(
47 "--author-exclude-regex",
48 action="append",
49 default=[],
50 help="Regex for author name/email to exclude (repeatable)",
51 )
52 parser.add_argument(
53 "--no-default-author-excludes",
54 action="store_true",
55 help="Disable default author excludes (dependabot)",
56 )
57 parser.add_argument(
58 "--graphml",
59 action="store_true",
60 help="Emit GraphML outputs",
61 )
62 parser.add_argument(
63 "--sensitive-config",
64 default=None,
65 help="CSV file with pattern,tag,weight for sensitive paths",
66 )
67 parser.add_argument(
68 "--cochange-max-files",
69 type=int,
70 default=50,
71 help="Ignore commits touching more than this many files for co-change graph",
72 )
73 parser.add_argument(
74 "--cochange-min-count",
75 type=int,
76 default=2,
77 help="Minimum co-change count to keep file-file edge",
78 )
79 parser.add_argument(
80 "--cochange-min-jaccard",
81 type=float,
82 default=0.05,
83 help="Minimum Jaccard similarity to keep file-file edge",
84 )
85 parser.add_argument(
86 "--cochange-exclude",
87 action="append",
88 default=[],
89 help="Glob to exclude from co-change graph (repeatable)",
90 )
91 parser.add_argument(
92 "--no-default-cochange-excludes",
93 action="store_true",
94 help="Disable default co-change excludes (lockfiles, .github, editor config)",
95 )
96 parser.add_argument(
97 "--community-top-owners",
98 type=int,
99 default=5,
100 help="Top maintainers saved per community",
101 )
102 parser.add_argument(
103 "--bus-factor-threshold",
104 type=int,
105 default=1,
106 help="Bus factor threshold for hotspots",
107 )
108 parser.add_argument(
109 "--stale-days",
110 type=int,
111 default=365,
112 help="Days since last touch to consider stale",
113 )
114 parser.add_argument(
115 "--owner-threshold",
116 type=float,
117 default=0.5,
118 help="Share threshold for hidden owner detection",
119 )
120 parser.add_argument(
121 "--no-cochange",
122 action="store_true",
123 help="Disable co-change graph output",
124 )
125 parser.add_argument(
126 "--no-communities",
127 action="store_true",
128 help="Disable community detection (not recommended)",
129 )
130 return parser.parse_args()
131
132
133def main() -> int:
134 args = parse_args()
135
136 try:
137 import networkx # noqa: F401
138 except ImportError:
139 print("networkx is required. Install with: pip install networkx", file=sys.stderr)
140 return 2
141
142 script_path = Path(__file__).resolve().parent / "build_ownership_map.py"
143 cmd = [
144 sys.executable,
145 str(script_path),
146 "--repo",
147 args.repo,
148 "--out",
149 args.out,
150 "--identity",
151 args.identity,
152 "--date-field",
153 args.date_field,
154 "--cochange-max-files",
155 str(args.cochange_max_files),
156 "--cochange-min-count",
157 str(args.cochange_min_count),
158 "--cochange-min-jaccard",
159 str(args.cochange_min_jaccard),
160 "--community-top-owners",
161 str(args.community_top_owners),
162 "--bus-factor-threshold",
163 str(args.bus_factor_threshold),
164 "--stale-days",
165 str(args.stale_days),
166 "--owner-threshold",
167 str(args.owner_threshold),
168 ]
169
170 if args.since:
171 cmd.extend(["--since", args.since])
172 if args.until:
173 cmd.extend(["--until", args.until])
174 if args.include_merges:
175 cmd.append("--include-merges")
176 if args.emit_commits:
177 cmd.append("--emit-commits")
178 if args.graphml:
179 cmd.append("--graphml")
180 if args.sensitive_config:
181 cmd.extend(["--sensitive-config", args.sensitive_config])
182 if args.no_cochange:
183 cmd.append("--no-cochange")
184 if args.no_communities:
185 cmd.append("--no-communities")
186 if args.no_default_cochange_excludes:
187 cmd.append("--no-default-cochange-excludes")
188 for pattern in args.cochange_exclude:
189 cmd.extend(["--cochange-exclude", pattern])
190 if args.no_default_author_excludes:
191 cmd.append("--no-default-author-excludes")
192 for pattern in args.author_exclude_regex:
193 cmd.extend(["--author-exclude-regex", pattern])
194
195 result = subprocess.run(cmd, check=False)
196 return result.returncode
197
198
199if __name__ == "__main__":
200 raise SystemExit(main())