Skip to content

Commit 2d0487a

Browse files
authored
Merge pull request #17 from github/finish-functionality
feat: Finish functionality
2 parents 543624f + 4e20401 commit 2d0487a

File tree

6 files changed

+456
-34
lines changed

6 files changed

+456
-34
lines changed

README.md

Lines changed: 151 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,87 @@
11
# Measure InnerSource tool
22

3-
This tool measures InnerSource collaboration in a given repository by analyzing issues, pull requests, and contributions.
3+
This tool measures InnerSource collaboration in a given repository by analyzing issues, pull requests, and code contributions. It helps organizations track and improve their InnerSource adoption by quantifying the collaboration between different teams and departments.
4+
5+
## What is InnerSource?
6+
7+
InnerSource applies open source principles and practices to internal development. It involves teams contributing to projects owned by other teams within the same organization, fostering collaboration, knowledge sharing, and code reuse across organizational boundaries. See [the InnerSource Commons Foundation's site](https://innersourcecommons.org) for more details.
8+
9+
## How This Tool Works
10+
11+
The measure-innersource tool:
12+
13+
1. Identifies the original repository owner(s) and their organizational structure
14+
2. Analyzes all contributors to the repository
15+
3. Classifies contributors as either team members or InnerSource contributors (from outside the team responsible for the repository)
16+
4. Counts contributions (commits, PRs, issues) from both groups
17+
5. Calculates an InnerSource collaboration ratio
18+
6. Generates a detailed Markdown report
19+
20+
### Organization Data
21+
22+
This tool requires an `org-data.json` file in the root of the repository that contains organizational hierarchy information. This file maps GitHub usernames to their managers, allowing the tool to determine team boundaries.
23+
24+
Example format of `org-data.json`:
25+
26+
```json
27+
{
28+
"username1": {
29+
"manager": "manager1"
30+
},
31+
"username2": {
32+
"manager": "manager1"
33+
},
34+
"username3": {
35+
"manager": "manager2"
36+
}
37+
}
38+
```
439

540
## Sample Report
641

42+
Below is an example of the generated InnerSource report:
43+
44+
```markdown
45+
# InnerSource Report
46+
47+
## Repository: octocat/hello-world
48+
49+
### InnerSource Ratio: 35.67%
50+
51+
### Original Commit Author: octocat (Manager: octoboss)
52+
53+
## Team Members that Own the Repo:
54+
55+
- octocat
56+
- octoboss
57+
- octodev1
58+
- octodev2
59+
60+
## All Contributors:
61+
62+
- octocat
63+
- octodev1
64+
- octodev2
65+
- contributor1
66+
- contributor2
67+
68+
## Innersource Contributors:
69+
70+
- contributor1
71+
- contributor2
72+
73+
## Innersource Contribution Counts:
74+
75+
- contributor1: 15 contributions
76+
- contributor2: 8 contributions
77+
78+
## Team Member Contribution Counts:
79+
80+
- octocat: 25 contributions
81+
- octodev1: 12 contributions
82+
- octodev2: 5 contributions
83+
```
84+
785
## Support
886

987
If you need support using this project or have questions about it, please [open up an issue in this repository](https://github.com/github/measure-innersource/issues). Requests made directly to GitHub staff or support team will be redirected here to open an issue. GitHub SLA's and support/services contracts do not apply to this repository.
@@ -15,12 +93,40 @@ All feedback regarding our GitHub Actions, as a whole, should be communicated th
1593
## Use as a GitHub Action
1694

1795
1. Create a repository to host this GitHub Action or select an existing repository. This is easiest with regards to permissions if it is the same repository as the one you want to measure innersource collaboration on.
18-
2. Select a best fit workflow file from the [examples directory](./docs/example-workflows.md) for your use case.
19-
3. Copy that example into your repository (from step 1) and into the proper directory for GitHub Actions: `.github/workflows/` directory with the file extension `.yml` (ie. `.github/workflows/measure-innersource.yml`)
96+
2. **Create an org-data.json file** in the root of your repository with your organization structure as described above.
97+
3. Copy the example below (in the next section) into your repository (from step 1) and into the proper directory for GitHub Actions: `.github/workflows/` directory with the file extension `.yml` (ie. `.github/workflows/measure-innersource.yml`)
2098
4. Update the workflow file with the appropriate configuration options as described below. The required configuration options are `REPOSITORY`, `GH_APP_ID`, `GH_APP_INSTALLATION_ID`, and `GH_APP_PRIVATE_KEY` for GitHub App Installation authentication, or `REPOSITORY` and `GH_TOKEN` for Personal Access Token (PAT) authentication. The other configuration options are optional.
2199
5. Commit the workflow file to the default branch (often `master` or `main`)
22100
6. Wait for the action to trigger based on the `schedule` entry or manually trigger the workflow as shown in the [documentation](https://docs.github.com/en/actions/using-workflows/manually-running-a-workflow).
23101

102+
### Basic Workflow Example
103+
104+
Here's a simple example workflow file to get you started:
105+
106+
```yaml
107+
name: Measure InnerSource Collaboration
108+
109+
on:
110+
schedule:
111+
- cron: "0 0 * * 0" # Run weekly on Sundays at midnight
112+
workflow_dispatch: # Allow manual triggers
113+
114+
jobs:
115+
measure-innersource:
116+
runs-on: ubuntu-latest
117+
steps:
118+
- name: Checkout code
119+
uses: actions/checkout@v4
120+
121+
- name: Measure InnerSource
122+
uses: github/measure-innersource@v1
123+
env:
124+
REPOSITORY: "owner/repo"
125+
GH_TOKEN: ${{ secrets.GH_TOKEN }}
126+
REPORT_TITLE: "Weekly InnerSource Report"
127+
OUTPUT_FILE: "innersource_report.md"
128+
```
129+
24130
### Configuration
25131
26132
Below are the allowed configuration options:
@@ -54,6 +160,48 @@ This action can be configured to authenticate with GitHub App Installation or Pe
54160
| `REPORT_TITLE` | False | `"InnerSource Report"` | Title to have on the report issue. |
55161
| `REPOSITORY` | True | `""` | The name of the repository you are trying to measure. Format `owner/repo` ie. `github/measure-innersource` |
56162

163+
## Understanding the Results
164+
165+
The generated report includes several key metrics:
166+
167+
### InnerSource Ratio
168+
169+
This is calculated as:
170+
171+
```markdown
172+
InnerSource Ratio = (Total InnerSource Contributions) / (Total Contributions)
173+
```
174+
175+
Where:
176+
177+
- Total InnerSource Contributions = Sum of all contributions from users outside the repository's owning team
178+
- Total Contributions = Sum of all contributions to the repository
179+
180+
A higher ratio indicates more cross-team collaboration.
181+
182+
### Team Ownership Determination
183+
184+
The tool determines team ownership by:
185+
186+
1. Identifying the original commit author
187+
2. Finding the original author's manager from org-data.json
188+
3. Including all users who report to the same manager in the team
189+
4. Including all users who report to anyone in the team
190+
191+
### Use Cases
192+
193+
- **Track InnerSource adoption over time**: Run this action on a schedule to see if your InnerSource initiative is gaining traction
194+
- **Compare InnerSource collaboration across repositories**: Run on multiple repositories to identify which ones have the most cross-team collaboration
195+
- **Identify key InnerSource contributors**: Recognize individuals who contribute across team boundaries
196+
- **Measure the impact of InnerSource initiatives**: Track the change in metrics before and after implementing InnerSource practices
197+
198+
## Limitations
199+
200+
- Requires accurate organization data in the org-data.json file
201+
- Cannot detect team relationships beyond what's specified in the org-data.json file
202+
- Historical team changes are not accounted for (uses current team structure only)
203+
- Bot accounts should have "[bot]" in their username to be excluded from calculations
204+
57205
## Contributions
58206

59207
We would ❤️ contributions to improve this action. Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for how to get involved.

config.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ def __repr__(self):
7171
f"{self.gh_app_enterprise_only},"
7272
f"{self.gh_token},"
7373
f"{self.ghe},"
74-
f"{self.report_title}"
74+
f"{self.report_title},"
7575
f"{self.owner},"
7676
f"{self.repo},"
77-
f"{self.output_file}"
77+
f"{self.output_file},"
7878
f"{self.rate_limit_bypass}"
7979
)
8080

@@ -154,7 +154,9 @@ def get_env_vars(test: bool = False) -> EnvVars:
154154
owner, repo = repository.split("/", 1)
155155

156156
report_title = os.getenv("REPORT_TITLE", "InnerSource Report")
157-
output_file = os.getenv("OUTPUT_FILE", "")
157+
output_file = os.getenv("OUTPUT_FILE")
158+
if not output_file:
159+
output_file = "innersource_report.md"
158160
rate_limit_bypass = get_bool_env_var("RATE_LIMIT_BYPASS", False)
159161

160162
return EnvVars(

markdown_writer.py

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,73 @@
66
def write_to_markdown(
77
report_title="",
88
output_file="",
9+
innersource_ratio=None,
10+
repo_data=None,
11+
original_commit_author="",
12+
original_commit_author_manager="",
13+
team_members_that_own_the_repo=None,
14+
all_contributors=None,
15+
innersource_contributors=None,
16+
innersource_contribution_counts=None,
17+
team_member_contribution_counts=None,
918
) -> None:
1019
"""
1120
Write an InnerSource Report to a markdown file.
1221
Args:
1322
report_title (str): The title of the report.
1423
output_file (str): The name of the output markdown file.
24+
innersource_ratio (float): The ratio of InnerSource contributions.
25+
repo_data (object): The repository data object.
26+
original_commit_author (str): The original commit author's name.
27+
original_commit_author_manager (str): The manager of the original commit author.
28+
team_members_that_own_the_repo (list): List of team members that own the repository.
29+
all_contributors (list): List of all contributors to the repository.
30+
innersource_contributors (list): List of InnerSource contributors.
31+
innersource_contribution_counts (dict): Dictionary of InnerSource contribution counts.
32+
team_member_contribution_counts (dict): Dictionary of team member contribution counts.
1533
1634
Returns:
1735
None
1836
"""
1937
output_file_name = output_file if output_file else "innersource_report.md"
20-
with open(output_file_name, "w", encoding="utf-8") as file:
21-
file.write(f"# {report_title}\n\n")
38+
with open(output_file_name, "w", encoding="utf-8") as report_file:
39+
report_file.write(f"# {report_title}\n\n")
40+
# Check if repo_data is None to handle test cases
41+
if repo_data is None:
42+
report_file.write("no op\n\n")
43+
return
44+
report_file.write(f"## Repository: {repo_data.full_name}\n\n")
45+
innersource_ratio = innersource_ratio if innersource_ratio is not None else 0.0
46+
report_file.write(f"### InnerSource Ratio: {innersource_ratio:.2%}\n\n")
47+
report_file.write(
48+
f"### Original Commit Author: {original_commit_author} (Manager: {original_commit_author_manager})\n\n"
49+
)
50+
report_file.write("## Team Members that Own the Repo:\n")
51+
if team_members_that_own_the_repo:
52+
for member in team_members_that_own_the_repo:
53+
report_file.write(f"- {member}\n")
54+
else:
55+
report_file.write("No team members available.\n")
2256

23-
file.write("no op\n\n")
57+
report_file.write("\n## All Contributors:\n")
58+
if all_contributors:
59+
for contributor in all_contributors:
60+
report_file.write(f"- {contributor}\n")
61+
62+
report_file.write("\n## Innersource Contributors:\n")
63+
if innersource_contributors:
64+
for contributor in innersource_contributors:
65+
report_file.write(f"- {contributor}\n")
66+
else:
67+
report_file.write("No InnerSource contributors found.\n")
68+
69+
report_file.write("\n## Innersource Contribution Counts:\n")
70+
if innersource_contribution_counts:
71+
for contributor, count in innersource_contribution_counts.items():
72+
report_file.write(f"- {contributor}: {count} contributions\n")
73+
74+
report_file.write("\n## Team Member Contribution Counts:\n")
75+
if team_member_contribution_counts is not None:
76+
for member, count in team_member_contribution_counts.items():
77+
if count > 0:
78+
report_file.write(f"- {member}: {count} contributions\n")

0 commit comments

Comments
 (0)