mirror of
https://github.com/github/awesome-copilot.git
synced 2026-03-12 04:05:12 +00:00
Adding the workflows after I broke #802
This commit is contained in:
@@ -34,3 +34,7 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-agentic-workflows) for guideline
|
|||||||
| Name | Description | Triggers |
|
| Name | Description | Triggers |
|
||||||
| ---- | ----------- | -------- |
|
| ---- | ----------- | -------- |
|
||||||
| [Daily Issues Report](../workflows/daily-issues-report.md) | Generates a daily summary of open issues and recent activity as a GitHub issue | schedule |
|
| [Daily Issues Report](../workflows/daily-issues-report.md) | Generates a daily summary of open issues and recent activity as a GitHub issue | schedule |
|
||||||
|
| [OSPO Contributors Report](../workflows/ospo-contributors-report.md) | Monthly contributor activity metrics across an organization's repositories. | schedule, workflow_dispatch |
|
||||||
|
| [OSPO Organization Health Report](../workflows/ospo-org-health.md) | Comprehensive weekly health report for a GitHub organization. Surfaces stale issues/PRs, merge time analysis, contributor leaderboards, and actionable items needing human attention. | schedule, workflow_dispatch |
|
||||||
|
| [OSPO Stale Repository Report](../workflows/ospo-stale-repos.md) | Identifies inactive repositories in your organization and generates an archival recommendation report. | schedule, workflow_dispatch |
|
||||||
|
| [OSS Release Compliance Checker](../workflows/ospo-release-compliance-checker.md) | Analyzes a target repository against open source release requirements and posts a detailed compliance report as an issue comment. | issues, workflow_dispatch |
|
||||||
|
|||||||
140
workflows/ospo-contributors-report.md
Normal file
140
workflows/ospo-contributors-report.md
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
---
|
||||||
|
name: 'OSPO Contributors Report'
|
||||||
|
description: 'Monthly contributor activity metrics across an organization''s repositories.'
|
||||||
|
labels: ['ospo', 'reporting', 'contributors']
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "3 2 1 * *"
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
organization:
|
||||||
|
description: "GitHub organization to analyze (e.g. github)"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
repositories:
|
||||||
|
description: "Comma-separated list of repos to analyze (e.g. owner/repo1,owner/repo2)"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
start_date:
|
||||||
|
description: "Start date for the report period (YYYY-MM-DD)"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
end_date:
|
||||||
|
description: "End date for the report period (YYYY-MM-DD)"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
sponsor_info:
|
||||||
|
description: "Include GitHub Sponsors information for contributors"
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: read
|
||||||
|
pull-requests: read
|
||||||
|
|
||||||
|
engine: copilot
|
||||||
|
|
||||||
|
tools:
|
||||||
|
github:
|
||||||
|
toolsets:
|
||||||
|
- repos
|
||||||
|
- issues
|
||||||
|
- pull_requests
|
||||||
|
- orgs
|
||||||
|
- users
|
||||||
|
bash: true
|
||||||
|
|
||||||
|
safe-outputs:
|
||||||
|
create-issue:
|
||||||
|
max: 1
|
||||||
|
title-prefix: "[Contributors Report] "
|
||||||
|
|
||||||
|
timeout-minutes: 60
|
||||||
|
---
|
||||||
|
|
||||||
|
# Contributors Report
|
||||||
|
|
||||||
|
Generate a contributors report for the specified organization or repositories.
|
||||||
|
|
||||||
|
## Step 1: Validate Configuration
|
||||||
|
|
||||||
|
Check the workflow inputs. Either `organization` or `repositories` must be provided.
|
||||||
|
|
||||||
|
- If **both** are empty and this is a **scheduled run**, default to analyzing all public repositories in the organization that owns the current repository. Determine the org from the `GITHUB_REPOSITORY` environment variable (the part before the `/`).
|
||||||
|
- If **both** are empty and this is a **manual dispatch**, fail with a clear error message: "You must provide either an organization or a comma-separated list of repositories."
|
||||||
|
- If **both** are provided, prefer `repositories` and ignore `organization`.
|
||||||
|
|
||||||
|
## Step 2: Determine Date Range
|
||||||
|
|
||||||
|
- If `start_date` and `end_date` are provided, use them.
|
||||||
|
- Otherwise, default to the **previous calendar month**. For example, if today is 2025-03-15, the range is 2025-02-01 to 2025-02-28.
|
||||||
|
- Use bash to compute the dates if needed. Store them as `START_DATE` and `END_DATE`.
|
||||||
|
|
||||||
|
## Step 3: Enumerate Repositories
|
||||||
|
|
||||||
|
- If `repositories` input was provided, split the comma-separated string into a list. Each entry should be in `owner/repo` format.
|
||||||
|
- If `organization` input was provided (or defaulted from Step 1), list all **public, non-archived, non-fork** repositories in the organization using the GitHub API. Collect their `owner/repo` identifiers.
|
||||||
|
|
||||||
|
## Step 4: Collect Contributors from Commit History
|
||||||
|
|
||||||
|
For each repository in scope:
|
||||||
|
|
||||||
|
1. Use the GitHub API to list commits between `START_DATE` and `END_DATE` (use the `since` and `until` parameters on the commits endpoint).
|
||||||
|
2. For each commit, extract the **author login** (from `author.login` on the commit object).
|
||||||
|
3. **Exclude bot accounts**: skip any contributor whose username contains `[bot]` or whose `type` field is `"Bot"`.
|
||||||
|
4. Track per-contributor:
|
||||||
|
- Total number of commits across all repos.
|
||||||
|
- The set of repos they contributed to.
|
||||||
|
|
||||||
|
Use bash to aggregate and deduplicate the contributor data across all repositories.
|
||||||
|
|
||||||
|
## Step 5: Determine New vs Returning Contributors
|
||||||
|
|
||||||
|
For each contributor found in Step 4, check whether they have **any commits before `START_DATE`** in any of the in-scope repositories.
|
||||||
|
|
||||||
|
- If a contributor has **no commits before `START_DATE`**, mark them as a **New Contributor**.
|
||||||
|
- Otherwise, mark them as a **Returning Contributor**.
|
||||||
|
|
||||||
|
## Step 6: Collect Sponsor Information (Optional)
|
||||||
|
|
||||||
|
If the `sponsor_info` input is `true`:
|
||||||
|
|
||||||
|
1. For each contributor, check whether they have a GitHub Sponsors profile by querying the user's profile via the GitHub API.
|
||||||
|
2. If the user has sponsorship enabled, record their sponsor URL as `https://github.com/sponsors/<username>`.
|
||||||
|
3. If not, leave the sponsor field empty.
|
||||||
|
|
||||||
|
## Step 7: Generate Markdown Report
|
||||||
|
|
||||||
|
Build a markdown report with the following structure:
|
||||||
|
|
||||||
|
### Summary Table
|
||||||
|
|
||||||
|
| Metric | Value |
|
||||||
|
|---|---|
|
||||||
|
| Total Contributors | count |
|
||||||
|
| Total Contributions (Commits) | count |
|
||||||
|
| New Contributors | count |
|
||||||
|
| Returning Contributors | count |
|
||||||
|
| % New Contributors | percentage |
|
||||||
|
|
||||||
|
### Contributors Detail Table
|
||||||
|
|
||||||
|
Sort contributors by commit count descending.
|
||||||
|
|
||||||
|
| # | Username | Contribution Count | New Contributor | Sponsor URL | Commits |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| 1 | @username | 42 | Yes | [Sponsor](url) | [View](commits-url) |
|
||||||
|
|
||||||
|
- The **Username** column should link to the contributor's GitHub profile.
|
||||||
|
- The **Sponsor URL** column should show "N/A" if `sponsor_info` is false or the user has no Sponsors page.
|
||||||
|
- The **Commits** column should link to a filtered commits view.
|
||||||
|
|
||||||
|
## Step 8: Create Issue with Report
|
||||||
|
|
||||||
|
Create an issue in the **current repository** with:
|
||||||
|
|
||||||
|
- **Title:** `[Contributors Report] <ORG_OR_REPO_SCOPE> — START_DATE to END_DATE`
|
||||||
|
- **Body:** The full markdown report from Step 7.
|
||||||
|
- **Labels:** Add the label `contributors-report` if it exists; do not fail if it does not.
|
||||||
216
workflows/ospo-org-health.md
Normal file
216
workflows/ospo-org-health.md
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
---
|
||||||
|
name: 'OSPO Organization Health Report'
|
||||||
|
description: 'Comprehensive weekly health report for a GitHub organization. Surfaces stale issues/PRs, merge time analysis, contributor leaderboards, and actionable items needing human attention.'
|
||||||
|
labels: ['ospo', 'reporting', 'org-health']
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 10 * * 1"
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
organization:
|
||||||
|
description: "GitHub organization to report on"
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: read
|
||||||
|
pull-requests: read
|
||||||
|
actions: read
|
||||||
|
|
||||||
|
engine: copilot
|
||||||
|
|
||||||
|
tools:
|
||||||
|
github:
|
||||||
|
toolsets:
|
||||||
|
- repos
|
||||||
|
- issues
|
||||||
|
- pull_requests
|
||||||
|
- orgs
|
||||||
|
bash: true
|
||||||
|
|
||||||
|
safe-outputs:
|
||||||
|
create-issue:
|
||||||
|
max: 1
|
||||||
|
title-prefix: "[Org Health] "
|
||||||
|
|
||||||
|
timeout-minutes: 60
|
||||||
|
|
||||||
|
network:
|
||||||
|
allowed:
|
||||||
|
- defaults
|
||||||
|
- python
|
||||||
|
---
|
||||||
|
|
||||||
|
You are an expert GitHub organization analyst. Your job is to produce a
|
||||||
|
comprehensive weekly health report for your GitHub organization
|
||||||
|
(provided via workflow input).
|
||||||
|
|
||||||
|
## Primary Goal
|
||||||
|
|
||||||
|
**Surface issues and PRs that need human attention**, celebrate wins, and
|
||||||
|
provide actionable metrics so maintainers can prioritize their time.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 1 — Determine the Organization
|
||||||
|
|
||||||
|
```
|
||||||
|
ORG = inputs.organization OR "my-org"
|
||||||
|
PERIOD_DAYS = 30
|
||||||
|
SINCE = date 30 days ago (ISO 8601)
|
||||||
|
STALE_ISSUE_DAYS = 60
|
||||||
|
STALE_PR_DAYS = 30
|
||||||
|
60_DAYS_AGO = date 60 days ago (ISO 8601)
|
||||||
|
30_DAYS_AGO = date 30 days ago (ISO 8601, same as SINCE)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 2 — Gather Organization-Wide Aggregates (Search API)
|
||||||
|
|
||||||
|
Use GitHub search APIs for fast org-wide counts. These are efficient and
|
||||||
|
avoid per-repo iteration for basic aggregates.
|
||||||
|
|
||||||
|
Collect the following using search queries:
|
||||||
|
|
||||||
|
| Metric | Search Query |
|
||||||
|
|--------|-------------|
|
||||||
|
| Total open issues | `org:<ORG> is:issue is:open` |
|
||||||
|
| Total open PRs | `org:<ORG> is:pr is:open` |
|
||||||
|
| Issues opened (last 30d) | `org:<ORG> is:issue created:>={SINCE}` |
|
||||||
|
| Issues closed (last 30d) | `org:<ORG> is:issue is:closed closed:>={SINCE}` |
|
||||||
|
| PRs opened (last 30d) | `org:<ORG> is:pr created:>={SINCE}` |
|
||||||
|
| PRs merged (last 30d) | `org:<ORG> is:pr is:merged merged:>={SINCE}` |
|
||||||
|
| PRs closed unmerged (last 30d) | `org:<ORG> is:pr is:closed is:unmerged closed:>={SINCE}` |
|
||||||
|
| Stale issues (60+ days) | `org:<ORG> is:issue is:open updated:<={60_DAYS_AGO}` |
|
||||||
|
| Stale PRs (30+ days) | `org:<ORG> is:pr is:open updated:<={30_DAYS_AGO}` |
|
||||||
|
|
||||||
|
**Performance tip:** Add 1–2 second delays between search API calls to
|
||||||
|
stay well within rate limits.
|
||||||
|
|
||||||
|
## Step 3 — Stale Issues & PRs (Heat Scores)
|
||||||
|
|
||||||
|
For stale issues and stale PRs found above, retrieve the top results and
|
||||||
|
sort them by **heat score** (comment count). The heat score helps
|
||||||
|
maintainers prioritize: a stale issue with many comments signals community
|
||||||
|
interest that is going unaddressed.
|
||||||
|
|
||||||
|
- **Stale issues**: Retrieve up to 50, sort by `comments` descending,
|
||||||
|
keep top 10. For each, record: repo, number, title, days since last
|
||||||
|
update, comment count (heat score), author, labels.
|
||||||
|
- **Stale PRs**: Same approach — retrieve up to 50, sort by `comments`
|
||||||
|
descending, keep top 10.
|
||||||
|
|
||||||
|
## Step 4 — PR Merge Time Analysis
|
||||||
|
|
||||||
|
From the PRs merged in the last 30 days (Step 2), retrieve a sample of
|
||||||
|
recently merged PRs (up to 100). For each, calculate:
|
||||||
|
|
||||||
|
```
|
||||||
|
merge_time = merged_at - created_at (in hours)
|
||||||
|
```
|
||||||
|
|
||||||
|
Then compute percentiles:
|
||||||
|
- **p50** (median merge time)
|
||||||
|
- **p75**
|
||||||
|
- **p95**
|
||||||
|
|
||||||
|
Use bash with Python for percentile calculations:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -c "
|
||||||
|
import json, sys
|
||||||
|
times = json.loads(sys.stdin.read())
|
||||||
|
times.sort()
|
||||||
|
n = len(times)
|
||||||
|
if n == 0:
|
||||||
|
print('No data')
|
||||||
|
else:
|
||||||
|
p50 = times[int(n * 0.50)]
|
||||||
|
p75 = times[int(n * 0.75)]
|
||||||
|
p95 = times[int(n * 0.95)] if n >= 20 else times[-1]
|
||||||
|
print(f'p50={p50:.1f}h, p75={p75:.1f}h, p95={p95:.1f}h')
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 5 — First Response Time
|
||||||
|
|
||||||
|
For issues and PRs opened in the last 30 days, sample up to 50 of each.
|
||||||
|
For each item, find the first comment (excluding the author). Calculate:
|
||||||
|
|
||||||
|
```
|
||||||
|
first_response_time = first_comment.created_at - item.created_at (in hours)
|
||||||
|
```
|
||||||
|
|
||||||
|
Report median first response time for issues and PRs separately.
|
||||||
|
|
||||||
|
## Step 6 — Repository Activity & Contributor Leaderboard
|
||||||
|
|
||||||
|
### Top 10 Active Repos
|
||||||
|
List all non-archived repos in the org. For each, count pushes / commits /
|
||||||
|
issues+PRs opened in the last 30 days. Sort by total activity, keep top 10.
|
||||||
|
|
||||||
|
### Contributor Leaderboard
|
||||||
|
From the top 10 active repos, aggregate commit authors over the last 30
|
||||||
|
days. Rank by commit count, keep top 10. Award:
|
||||||
|
- 🥇 for #1
|
||||||
|
- 🥈 for #2
|
||||||
|
- 🥉 for #3
|
||||||
|
|
||||||
|
### Inactive Repos
|
||||||
|
Repos with 0 pushes, 0 issues, 0 PRs in the last 30 days. List them
|
||||||
|
(name + last push date) so the org can decide whether to archive.
|
||||||
|
|
||||||
|
## Step 7 — Health Alerts & Trends
|
||||||
|
|
||||||
|
Compute velocity indicators and assign status:
|
||||||
|
|
||||||
|
| Indicator | 🟢 Green | 🟡 Yellow | 🔴 Red |
|
||||||
|
|-----------|----------|-----------|--------|
|
||||||
|
| Issue close rate | closed ≥ opened | closed ≥ 70% opened | closed < 70% opened |
|
||||||
|
| PR merge rate | merged ≥ opened | merged ≥ 60% opened | merged < 60% opened |
|
||||||
|
| Median merge time | < 24h | 24–72h | > 72h |
|
||||||
|
| Median first response | < 24h | 24–72h | > 72h |
|
||||||
|
| Stale issue count | < 10 | 10–50 | > 50 |
|
||||||
|
| Stale PR count | < 5 | 5–20 | > 20 |
|
||||||
|
|
||||||
|
## Step 8 — Wins & Shoutouts
|
||||||
|
|
||||||
|
Celebrate positive signals:
|
||||||
|
- PRs merged with fast turnaround (< 4 hours)
|
||||||
|
- Issues closed quickly (< 24 hours from open to close)
|
||||||
|
- Top contributors (from leaderboard)
|
||||||
|
- Repos with zero stale items
|
||||||
|
|
||||||
|
## Step 9 — Compose the Report
|
||||||
|
|
||||||
|
Create a single issue in the org's `.github` repository (or the most
|
||||||
|
appropriate central repo) with the title:
|
||||||
|
|
||||||
|
```
|
||||||
|
[Org Health] Weekly Report — <DATE>
|
||||||
|
```
|
||||||
|
|
||||||
|
The issue body should include these sections in order:
|
||||||
|
|
||||||
|
1. **Header** — org name, period, generation date
|
||||||
|
2. **🚨 Health Alerts** — table of indicators with 🟢/🟡/🔴 status and values
|
||||||
|
3. **🏆 Wins & Shoutouts** — fast merges, quick closes, top contributors
|
||||||
|
4. **📋 Stale Issues** — top 10 by heat score (repo, issue, days stale, comment count, labels)
|
||||||
|
5. **📋 Stale PRs** — top 10 by heat score (repo, PR, days stale, comment count, author)
|
||||||
|
6. **⏱️ PR Merge Time** — p50, p75, p95 percentiles
|
||||||
|
7. **⚡ First Response Time** — median for issues and PRs
|
||||||
|
8. **📊 Top 10 Active Repos** — sorted by total activity (issues + PRs + commits)
|
||||||
|
9. **👥 Contributor Leaderboard** — top 10 by commits with 🥇🥈🥉
|
||||||
|
10. **😴 Inactive Repos** — repos with 0 activity in 30 days
|
||||||
|
|
||||||
|
Use markdown tables for all data sections.
|
||||||
|
|
||||||
|
## Important Notes
|
||||||
|
|
||||||
|
- **Update the organization name** in the frontmatter before use.
|
||||||
|
- If any API call fails, note it in the report and continue with available
|
||||||
|
data. Do not let a single failure block the entire report.
|
||||||
|
- Keep the issue body under 65,000 characters (GitHub issue body limit).
|
||||||
|
- All times should be reported in hours. Convert to days only if > 72 hours.
|
||||||
|
- Use the `safe-outputs` constraint: only create 1 issue, with title
|
||||||
|
prefixed `[Org Health] `.
|
||||||
124
workflows/ospo-release-compliance-checker.md
Normal file
124
workflows/ospo-release-compliance-checker.md
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
---
|
||||||
|
name: 'OSS Release Compliance Checker'
|
||||||
|
description: 'Analyzes a target repository against open source release requirements and posts a detailed compliance report as an issue comment.'
|
||||||
|
labels: ['ospo', 'compliance', 'release']
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [opened, labeled]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: read
|
||||||
|
pull-requests: read
|
||||||
|
actions: read
|
||||||
|
|
||||||
|
engine: copilot
|
||||||
|
|
||||||
|
tools:
|
||||||
|
github:
|
||||||
|
toolsets:
|
||||||
|
- repos
|
||||||
|
- issues
|
||||||
|
bash: true
|
||||||
|
|
||||||
|
safe-outputs:
|
||||||
|
add-comment:
|
||||||
|
max: 1
|
||||||
|
|
||||||
|
timeout-minutes: 20
|
||||||
|
---
|
||||||
|
|
||||||
|
You are an open source release compliance checker. Your job is to analyze a
|
||||||
|
repository that has been proposed for open source release and post a thorough,
|
||||||
|
constructive compliance report as a comment on the triggering issue.
|
||||||
|
|
||||||
|
## 1. Trigger Guard
|
||||||
|
|
||||||
|
First, determine whether this workflow should proceed:
|
||||||
|
|
||||||
|
- If the event is `workflow_dispatch`, proceed.
|
||||||
|
- If the event is `issues` with type `opened`, proceed.
|
||||||
|
- If the event is `issues` with type `labeled`, only proceed if the label that
|
||||||
|
was just added is **`ospo-release-check`**.
|
||||||
|
- Otherwise, stop and do nothing.
|
||||||
|
|
||||||
|
## 2. Extract Target Repository
|
||||||
|
|
||||||
|
Read the body of the triggering issue. Look for the repository that is being
|
||||||
|
proposed for release. It may appear as:
|
||||||
|
|
||||||
|
- A full GitHub URL such as `https://github.com/org/repo-name`
|
||||||
|
- An `owner/repo` shorthand such as `org/repo-name`
|
||||||
|
|
||||||
|
Extract the **owner** and **repo name**. If you cannot find a repository
|
||||||
|
reference, post a comment asking the issue author to include one and stop.
|
||||||
|
|
||||||
|
## 3. File Compliance Check
|
||||||
|
|
||||||
|
For the target repository, check whether each of the following files exists at
|
||||||
|
the repository root (or in `.github/` where conventional). For each file that
|
||||||
|
exists, also assess whether it has meaningful content.
|
||||||
|
|
||||||
|
| File | What to look for |
|
||||||
|
|------|-----------------|
|
||||||
|
| `LICENSE` | Must be present. Contents must match the license declared in the repo metadata. |
|
||||||
|
| `README.md` | Must be present and substantial (>100 lines recommended). Should contain sections for usage, install, and contributing. |
|
||||||
|
| `CODEOWNERS` | Must list at least one maintainer or team. |
|
||||||
|
| `CONTRIBUTING.md` | Must describe how to contribute (issues, PRs, CLA/DCO, code style). |
|
||||||
|
| `SUPPORT.md` | Must explain how users can get help. |
|
||||||
|
| `CODE_OF_CONDUCT.md` | Must adopt a recognized code of conduct. |
|
||||||
|
| `SECURITY.md` | Must describe the security vulnerability disclosure process. |
|
||||||
|
|
||||||
|
## 4. Security Configuration Check
|
||||||
|
|
||||||
|
Using the GitHub API, check the following security settings on the target
|
||||||
|
repository:
|
||||||
|
|
||||||
|
- **Secret scanning** — Is secret scanning enabled?
|
||||||
|
- **Dependabot** — Are Dependabot alerts and/or security updates enabled?
|
||||||
|
- **Code scanning (CodeQL)** — Are any code scanning analyses present?
|
||||||
|
- **Branch protection** — Is the default branch protected? Are required reviews,
|
||||||
|
status checks, or signed commits configured?
|
||||||
|
|
||||||
|
Handle `404` or `403` responses gracefully — they typically mean the feature is
|
||||||
|
not enabled or you lack permission to check it.
|
||||||
|
|
||||||
|
## 5. License & Legal Analysis
|
||||||
|
|
||||||
|
- Compare the contents of the `LICENSE` file against the license declared in
|
||||||
|
the repository metadata (`license.spdx_id` from the repo API response).
|
||||||
|
Flag any mismatch.
|
||||||
|
- Look for dependency manifests (`package.json`, `requirements.txt`, `go.mod`,
|
||||||
|
`Cargo.toml`, `pom.xml`, `Gemfile`, `*.csproj`, etc.) in the repository.
|
||||||
|
- For each manifest found, attempt to identify declared dependency licenses.
|
||||||
|
Specifically flag any **GPL**, **AGPL**, **LGPL**, or other strong-copyleft
|
||||||
|
licenses that would require legal review before an open source release.
|
||||||
|
|
||||||
|
## 6. Risk Assessment
|
||||||
|
|
||||||
|
Based on your findings, assign a risk level (**Low**, **Medium**, or **High**)
|
||||||
|
to each of the following categories:
|
||||||
|
|
||||||
|
| Category | Low 🟢 | Medium 🟡 | High 🔴 |
|
||||||
|
|----------|--------|-----------|---------|
|
||||||
|
| **Business Risk** | No secrets, no proprietary code patterns | Some internal references found | Secrets detected, proprietary code |
|
||||||
|
| **Legal Risk** | Permissive license, no copyleft deps | Minor license inconsistencies | GPL/AGPL deps, license mismatch |
|
||||||
|
| **Open Source Risk** | All files present, active maintainers | Some files missing or thin | No README, no CODEOWNERS |
|
||||||
|
|
||||||
|
## 7. Generate Compliance Report
|
||||||
|
|
||||||
|
Post **one** comment on the triggering issue with these sections:
|
||||||
|
|
||||||
|
1. **Header** — repo name, timestamp, overall status (PASS ✅ / NEEDS WORK ⚠️ / BLOCKED 🚫)
|
||||||
|
2. **📄 File Compliance** — table of 7 files with ✅/❌ status and notes
|
||||||
|
3. **🔒 Security Configuration** — table of 4 settings with status
|
||||||
|
4. **⚖️ License Analysis** — declared license, LICENSE file match, copyleft flags
|
||||||
|
5. **📊 Risk Assessment** — Business/Legal/Open Source risk levels (🟢/🟡/🔴) with details
|
||||||
|
6. **📋 Recommendations** — prioritized as Must Fix (blocking), Should Address, Nice to Have
|
||||||
|
|
||||||
|
### Tone Guidelines
|
||||||
|
|
||||||
|
- Be **constructive** — help teams succeed, don't gatekeep.
|
||||||
|
- Explain *why* missing items matter and link to guidance.
|
||||||
|
- Celebrate what the team has already done well.
|
||||||
119
workflows/ospo-stale-repos.md
Normal file
119
workflows/ospo-stale-repos.md
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
---
|
||||||
|
name: 'OSPO Stale Repository Report'
|
||||||
|
description: 'Identifies inactive repositories in your organization and generates an archival recommendation report.'
|
||||||
|
labels: ['ospo', 'maintenance', 'stale-repos']
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "3 2 1 * *"
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
organization:
|
||||||
|
description: "GitHub organization to scan"
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
default: "my-org"
|
||||||
|
inactive_days:
|
||||||
|
description: "Number of days of inactivity before a repo is considered stale"
|
||||||
|
required: false
|
||||||
|
type: number
|
||||||
|
default: 365
|
||||||
|
exempt_repos:
|
||||||
|
description: "Comma-separated list of repos to exempt from the report"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
default: ""
|
||||||
|
exempt_topics:
|
||||||
|
description: "Comma-separated list of topics — repos with any of these topics are exempt"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
default: ""
|
||||||
|
activity_method:
|
||||||
|
description: "Method to determine last activity"
|
||||||
|
required: false
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- pushed
|
||||||
|
- default_branch_updated
|
||||||
|
default: pushed
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: read
|
||||||
|
|
||||||
|
engine: copilot
|
||||||
|
tools:
|
||||||
|
github:
|
||||||
|
toolsets:
|
||||||
|
- repos
|
||||||
|
- issues
|
||||||
|
bash: true
|
||||||
|
|
||||||
|
safe-outputs:
|
||||||
|
create-issue:
|
||||||
|
max: 1
|
||||||
|
title-prefix: "[Stale Repos] "
|
||||||
|
labels:
|
||||||
|
- stale-repos
|
||||||
|
|
||||||
|
timeout-minutes: 30
|
||||||
|
---
|
||||||
|
|
||||||
|
You are an assistant that audits GitHub repositories for staleness.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
| Input | Default |
|
||||||
|
|---|---|
|
||||||
|
| `organization` | `my-org` |
|
||||||
|
| `inactive_days` | `365` |
|
||||||
|
| `exempt_repos` | _(none)_ |
|
||||||
|
| `exempt_topics` | _(none)_ |
|
||||||
|
| `activity_method` | `pushed` |
|
||||||
|
|
||||||
|
Use the workflow dispatch inputs if provided; otherwise fall back to the defaults above.
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
### 1. Enumerate repositories
|
||||||
|
|
||||||
|
List **all** repositories in the `organization`. Exclude any repo that is:
|
||||||
|
|
||||||
|
- **Archived** — skip it entirely.
|
||||||
|
- **Listed in `exempt_repos`** — compare repo names (case-insensitive) against the comma-separated list.
|
||||||
|
- **Tagged with an exempt topic** — if the repo has any topic that appears in the comma-separated `exempt_topics` list, skip it.
|
||||||
|
|
||||||
|
### 2. Determine last activity date
|
||||||
|
|
||||||
|
For each remaining repo, determine the **last activity date** based on `activity_method`:
|
||||||
|
|
||||||
|
- **`pushed`** — use the repository's `pushed_at` timestamp (this is the default and most efficient method).
|
||||||
|
- **`default_branch_updated`** — fetch the most recent commit on the repo's default branch and use that commit's `committer.date`.
|
||||||
|
|
||||||
|
### 3. Identify stale repos
|
||||||
|
|
||||||
|
Calculate the number of days between the last activity date and **today**. If the number of days exceeds `inactive_days`, mark the repo as **stale**.
|
||||||
|
|
||||||
|
### 4. Generate report
|
||||||
|
|
||||||
|
Build a **Markdown report** with a summary and a table:
|
||||||
|
|
||||||
|
> **Stale Repository Report — \<date\>**
|
||||||
|
> Found **N** repositories with no activity in the last **inactive_days** days.
|
||||||
|
|
||||||
|
| Repository | Days Inactive | Last Push Date | Visibility |
|
||||||
|
|---|---|---|---|
|
||||||
|
| [owner/repo](https://github.com/owner/repo) | 420 | 2024-01-15 | public |
|
||||||
|
|
||||||
|
Sort the table by **Days Inactive** descending (most stale first).
|
||||||
|
|
||||||
|
If there are **no stale repos**, still create the issue but note that all repositories are active.
|
||||||
|
|
||||||
|
### 5. Create or update issue
|
||||||
|
|
||||||
|
Search for an existing **open** issue in the `organization/.github` repo (or the repo this workflow runs in) with the label `stale-repos` and a title starting with `[Stale Repos]`.
|
||||||
|
|
||||||
|
- If an **existing open issue** is found, **update its body** with the new report.
|
||||||
|
- If **no open issue** exists, **create a new issue** with:
|
||||||
|
- Title: `[Stale Repos] Inactive Repository Report — <date>`
|
||||||
|
- Label: `stale-repos`
|
||||||
|
- Body: the full Markdown report from step 4.
|
||||||
Reference in New Issue
Block a user