Skip to content

Commit 62efffc

Browse files
authored
Merge pull request #63 from github/copilot/fix-5a44b335-4f8a-4c35-b8fb-9f8941ab7116
2 parents 4eb2145 + 0bd5cc4 commit 62efffc

14 files changed

+639
-85
lines changed

.env-example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ GH_ENTERPRISE_URL = ""
66
GH_TOKEN = ""
77
OUTPUT_FILE = ""
88
REPORT_TITLE = ""
9+
OWNING_TEAM = ""

README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,17 @@ The tool determines team boundaries using this algorithm:
214214
- Are managers of anyone in the team
215215
4. **Classify Contributors**: Any contributor not in the team list is considered an InnerSource contributor
216216

217+
**Overriding Team Determination**: You can override this algorithm by setting the `OWNING_TEAM` environment variable with a comma-separated list of GitHub usernames. When set, these users will be considered the owning team, and the algorithm above will be bypassed. This is useful when:
218+
- The first commit author doesn't accurately represent the current owning team
219+
- The org chart doesn't align with actual repository ownership
220+
- You want to explicitly define team boundaries
221+
222+
Example:
223+
```yaml
224+
env:
225+
OWNING_TEAM: "alice,bob,charlie"
226+
```
227+
217228
#### Example Team Boundary Calculation
218229
219230
<details>
@@ -517,6 +528,40 @@ jobs:
517528
CHUNK_SIZE: "100"
518529
```
519530
531+
#### Using Custom Team Ownership
532+
533+
To override the automatic team determination and explicitly specify the owning team:
534+
535+
```yaml
536+
name: InnerSource with Custom Team
537+
538+
on:
539+
schedule:
540+
- cron: "0 0 * * 0"
541+
workflow_dispatch:
542+
543+
jobs:
544+
measure-innersource:
545+
runs-on: ubuntu-latest
546+
steps:
547+
- name: Checkout code
548+
uses: actions/checkout@v4
549+
550+
- name: Measure InnerSource
551+
uses: github/measure-innersource@v1
552+
env:
553+
REPOSITORY: "org/repository"
554+
GH_TOKEN: ${{ secrets.GH_TOKEN }}
555+
OWNING_TEAM: "alice,bob,charlie,david"
556+
REPORT_TITLE: "InnerSource Report with Custom Team"
557+
```
558+
559+
This is useful when:
560+
- The first commit author doesn't represent the current team
561+
- The org chart doesn't align with actual ownership
562+
- You want to explicitly define team boundaries
563+
564+
520565
### Configuration
521566
522567
Below are the allowed configuration options:
@@ -550,6 +595,7 @@ This action can be configured to authenticate with GitHub App Installation or Pe
550595
| `REPORT_TITLE` | False | `"InnerSource Report"` | Title to have on the report issue. |
551596
| `REPOSITORY` | True | `""` | The name of the repository you are trying to measure. Format `owner/repo` ie. `github/measure-innersource` |
552597
| `CHUNK_SIZE` | False | `100` | Number of items to process at once when fetching data. Increasing can improve performance but uses more memory. Minimum value is 10. |
598+
| `OWNING_TEAM` | False | `""` | Comma-separated list of GitHub usernames that own the repository. Overrides the built-in team determination algorithm. Example: `alice,bob,charlie` |
553599

554600
## Understanding the Results
555601

@@ -709,6 +755,7 @@ The tool automatically splits large files, but you can:
709755
- [ ] `OUTPUT_FILE` (default: "innersource_report.md")
710756
- [ ] `CHUNK_SIZE` (default: 100, minimum: 10)
711757
- [ ] `RATE_LIMIT_BYPASS` (default: false)
758+
- [ ] `OWNING_TEAM` (comma-separated usernames to override team determination)
712759

713760
#### File Requirements Checklist
714761

config.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class EnvVars:
3636
output_file (str): The name of the file to write the report to
3737
rate_limit_bypass (bool): If set to TRUE, bypass the rate limit for the GitHub API
3838
chunk_size (int): The number of items to process at once when fetching data (for memory efficiency)
39+
owning_team (list[str] | None): Optional list of usernames that comprise the owning team (overrides algorithm)
3940
"""
4041

4142
def __init__(
@@ -52,6 +53,7 @@ def __init__(
5253
output_file: str,
5354
rate_limit_bypass: bool = False,
5455
chunk_size: int = 100,
56+
owning_team: list[str] | None = None,
5557
):
5658
self.gh_app_id = gh_app_id
5759
self.gh_app_installation_id = gh_app_installation_id
@@ -65,6 +67,7 @@ def __init__(
6567
self.output_file = output_file
6668
self.rate_limit_bypass = rate_limit_bypass
6769
self.chunk_size = chunk_size
70+
self.owning_team = owning_team
6871

6972
def __repr__(self):
7073
return (
@@ -80,7 +83,8 @@ def __repr__(self):
8083
f"{self.repo},"
8184
f"{self.output_file},"
8285
f"{self.rate_limit_bypass},"
83-
f"{self.chunk_size}"
86+
f"{self.chunk_size},"
87+
f"{self.owning_team}"
8488
")"
8589
)
8690

@@ -183,6 +187,8 @@ def get_env_vars(test: bool = False) -> EnvVars:
183187
- OUTPUT_FILE: Output filename (default: "innersource_report.md")
184188
- RATE_LIMIT_BYPASS: Set to "true" to bypass rate limiting
185189
- CHUNK_SIZE: Number of items to process at once (default: 100, minimum: 10)
190+
- OWNING_TEAM: Comma-separated list of GitHub usernames that own the repository
191+
(overrides the built-in team determination algorithm)
186192
187193
Examples:
188194
>>> os.environ['GH_TOKEN'] = 'ghp_...'
@@ -243,6 +249,20 @@ def get_env_vars(test: bool = False) -> EnvVars:
243249
# Default to DEFAULT_CHUNK_SIZE if not a valid integer
244250
chunk_size = DEFAULT_CHUNK_SIZE
245251

252+
# Get optional owning team override (comma-separated list of usernames)
253+
owning_team_str = os.getenv("OWNING_TEAM", "").strip()
254+
owning_team = None
255+
if owning_team_str:
256+
# Parse comma-separated list and strip whitespace from each username
257+
owning_team = [
258+
username.strip()
259+
for username in owning_team_str.split(",")
260+
if username.strip()
261+
]
262+
# If the list is empty after stripping, set to None
263+
if not owning_team:
264+
owning_team = None
265+
246266
return EnvVars(
247267
gh_app_id,
248268
gh_app_installation_id,
@@ -256,4 +276,5 @@ def get_env_vars(test: bool = False) -> EnvVars:
256276
output_file,
257277
rate_limit_bypass,
258278
chunk_size,
279+
owning_team,
259280
)

markdown_writer.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def write_to_markdown(
4040
innersource_contributors=None,
4141
innersource_contribution_counts=None,
4242
team_member_contribution_counts=None,
43+
team_ownership_explicitly_specified=False,
4344
) -> None:
4445
"""
4546
Generate a comprehensive InnerSource collaboration report in markdown format.
@@ -84,6 +85,10 @@ def write_to_markdown(
8485
mapping team member
8586
usernames to their
8687
contribution counts.
88+
team_ownership_explicitly_specified (bool, optional): Flag indicating whether team
89+
ownership is explicitly specified
90+
rather than derived from commit history.
91+
Defaults to False.
8792
8893
Returns:
8994
None: This function creates a markdown file as a side effect.
@@ -126,7 +131,22 @@ def write_to_markdown(
126131
... all_contributors=["alice", "bob", "charlie", "dave", "eve"],
127132
... innersource_contributors=["dave", "eve"],
128133
... innersource_contribution_counts={"dave": 15, "eve": 8},
129-
... team_member_contribution_counts={"alice": 25, "bob": 12, "charlie": 5}
134+
... team_member_contribution_counts={"alice": 25, "bob": 12, "charlie": 5},
135+
... team_ownership_explicitly_specified=False
136+
... )
137+
138+
>>> # Generate a report with explicitly specified team ownership
139+
>>> write_to_markdown(
140+
... report_title="Team Ownership Report",
141+
... output_file="team_report.md",
142+
... innersource_ratio=0.38,
143+
... repo_data=repo_object,
144+
... team_members_that_own_the_repo=["david", "emily", "frank"],
145+
... all_contributors=["david", "emily", "frank", "greg", "hannah"],
146+
... innersource_contributors=["greg", "hannah"],
147+
... innersource_contribution_counts={"greg": 12, "hannah": 6},
148+
... team_member_contribution_counts={"david": 18, "emily": 9, "frank": 7},
149+
... team_ownership_explicitly_specified=True
130150
... )
131151
"""
132152
output_file_name = output_file if output_file else "innersource_report.md"
@@ -138,9 +158,20 @@ def write_to_markdown(
138158
return
139159
report_file.write(f"## Repository: {repo_data.full_name}\n\n")
140160
report_file.write(f"### InnerSource Ratio: {innersource_ratio:.2%}\n\n")
141-
report_file.write(
142-
f"### Original Commit Author: {original_commit_author} (Manager: {original_commit_author_manager})\n\n"
143-
)
161+
if team_ownership_explicitly_specified:
162+
report_file.write("### Team ownership is explicitly specified\n\n")
163+
elif original_commit_author and original_commit_author_manager:
164+
report_file.write(
165+
f"### Original Commit Author: {original_commit_author} (Manager: {original_commit_author_manager})\n\n"
166+
)
167+
elif original_commit_author:
168+
report_file.write(
169+
f"### Original Commit Author: {original_commit_author}\n\n"
170+
)
171+
else:
172+
report_file.write(
173+
"### Original commit author information not available\n\n"
174+
)
144175
report_file.write("## Team Members that Own the Repo:\n")
145176
if team_members_that_own_the_repo:
146177
for member in team_members_that_own_the_repo:

0 commit comments

Comments
 (0)