github-overlord 0.8.0__tar.gz → 0.9.1__tar.gz

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.
@@ -0,0 +1,138 @@
1
+ Metadata-Version: 2.3
2
+ Name: github-overlord
3
+ Version: 0.9.1
4
+ Summary: Automatically merge Dependabot PRs in public repositories
5
+ Keywords: github,dependabot,automation
6
+ Author: Michael Bianco
7
+ Author-email: Michael Bianco <mike@mikebian.co>
8
+ License: MIT
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3 :: Only
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Programming Language :: Python :: 3.14
14
+ Requires-Dist: pygithub>=2.4.0
15
+ Requires-Dist: click>=8.1.7
16
+ Requires-Dist: python-decouple-typed>=3.11.0
17
+ Requires-Dist: funcy-pipe>=0.11.1,<0.15.0
18
+ Requires-Dist: structlog>=24.4,<27.0
19
+ Requires-Dist: apscheduler>=3.10.4
20
+ Requires-Dist: openai>=1.52.2,<4.0.0
21
+ Requires-Dist: pydantic-ai-slim[google]>=0.0.18
22
+ Requires-Dist: jinja2>=3.1.0
23
+ Requires-Python: >=3.12
24
+ Project-URL: Homepage, https://github.com/iloveitaly/github-overlord
25
+ Project-URL: Repository, https://github.com/iloveitaly/github-overlord
26
+ Description-Content-Type: text/markdown
27
+
28
+ [![Release Notes](https://img.shields.io/github/release/iloveitaly/github-overlord)](https://github.com/iloveitaly/github-overlord/releases)
29
+ [![Downloads](https://static.pepy.tech/badge/github-overlord/month)](https://pepy.tech/project/github-overlord)
30
+ [![Python Versions](https://img.shields.io/pypi/pyversions/github-overlord)](https://pypi.org/project/github-overlord)
31
+ ![GitHub CI Status](https://github.com/iloveitaly/github-overlord/actions/workflows/build_and_publish.yml/badge.svg)
32
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
33
+
34
+ # GitHub Overlord
35
+
36
+ GitHub Overlord is a Python script that does a couple things to help manage open source projects on GitHub:
37
+
38
+ * Automatically merges Dependabot PRs in public repositories that have passed CI checks.
39
+ * Comment on PRs that are going to automatically be marked as stale
40
+ * Removes notifications from bot-authored PRs, Release Please PRs, self-authored PR creations without external activity, PRs merged by you, PRs closed by you, PRs approved by you that are now merged, notifications older than two months, and releases on repos you control
41
+ * Automatically creates releases for repositories based on LLM analysis of recent commits
42
+
43
+ This simple project has also given me the chance to iterate on my [nixpacks github actions project](https://github.com/iloveitaly/github-action-nixpacks).
44
+
45
+ ## Installation
46
+
47
+ ```shell
48
+ pip install github-overlord
49
+ ```
50
+
51
+ ## Usage
52
+
53
+ ```shell
54
+ Usage: github-overlord [OPTIONS] COMMAND [ARGS]...
55
+
56
+ Options:
57
+ --help Show this message and exit.
58
+
59
+ Commands:
60
+ generate-releases Check repositories for release readiness using LLM analysis
61
+ dependabot Automatically merge dependabot PRs in public repos that...
62
+ keep-alive-prs Detect when a bot is about to close a PR for no good reason
63
+ notifications Look at notifications and mark them as read
64
+ ```
65
+
66
+ ### Automatic Release Creation
67
+
68
+ The `generate-releases` command uses LLM analysis (via [Pydantic AI](https://ai.pydantic.dev/)) to determine when repositories are ready for a new release. Both `generate-releases` and `keep-alive-prs` share the same unified AI model configuration (defaulting to Google Gemini `gemini-3.8-flash`).
69
+
70
+ This is particularly useful for template repositories, starter projects, etc that don't have automated release workflows and aren't versioned for whatever reason.
71
+
72
+ I have a bunch of these and I wanted an easy way to let the world know when I build something interesting in them.
73
+
74
+ **Usage:**
75
+
76
+ ```shell
77
+ # Check all repos with a specific topic
78
+ github-overlord generate-releases --topic auto-release
79
+
80
+ # Check a single repository
81
+ github-overlord generate-releases --repo owner/repo-name
82
+
83
+ # Dry run (see what would happen without creating releases)
84
+ github-overlord generate-releases --topic auto-release --dry-run
85
+ ```
86
+
87
+ **Requirements & Configuration:**
88
+
89
+ * `GITHUB_TOKEN` - GitHub token with repo write permissions
90
+ * `GITHUB_OVERLORD_AI_KEY` - API key for the AI provider (or provider-specific `GOOGLE_API_KEY`, `OPENAI_API_KEY`, etc.)
91
+ * `GITHUB_OVERLORD_MODEL` - (Optional) AI model override (e.g. `gemini-3.8-flash`, `openai:gpt-4o`). Defaults to `gemini-3.8-flash`.
92
+ * `--topic` flag or `RELEASE_CHECKER_TOPIC` - Topic to filter repositories (required unless using `--repo`)
93
+ * `--repo` flag or `RELEASE_CHECKER_REPO` - Single repository to process (useful for testing)
94
+ * `RELEASE_CHECKER_MIN_GAP` - Minimum time between releases for the same repo (defaults to `2w`, e.g. `14d`, `48h`)
95
+
96
+ **How it works:**
97
+
98
+ 1. Finds repositories matching the specified topic
99
+ 2. For each repo, gets commits since the last release (or since repo creation if no releases)
100
+ 3. Analyzes up to the last 50 commits using the configured AI model (defaulting to `gemini-3.8-flash`) to determine if a release is warranted
101
+ 4. If the LLM recommends a release, automatically creates one with:
102
+
103
+ * Auto-incremented semantic version (patch/minor/major based on changes)
104
+ * AI-generated release notes highlighting key changes
105
+ * Link to full changelog
106
+
107
+ **Scheduling:**
108
+ To run this weekly, set the `SCHEDULE` environment variable:
109
+
110
+ ```bash
111
+ # Run every Monday at 9 AM
112
+ export SCHEDULE="0 9 * * 1"
113
+ export RELEASE_CHECKER_TOPIC="template"
114
+ # Or, to test a single repo on the schedule:
115
+ # export RELEASE_CHECKER_REPO="owner/repo-name"
116
+ export GITHUB_TOKEN="your-token"
117
+ export GITHUB_OVERLORD_AI_KEY="your-api-key"
118
+
119
+ # All CLI commands will run on this schedule
120
+ python main.py
121
+ ```
122
+
123
+ **Troubleshooting:**
124
+
125
+ * **"No repositories found with topic"**: Make sure your repos have the correct topic tag in GitHub settings
126
+ * **"API key environment variable is required"**: Set `GITHUB_OVERLORD_AI_KEY` (or `GOOGLE_API_KEY` for the default Gemini model). Get a free Gemini API key from [ai.google.dev](https://ai.google.dev/)
127
+ * **Rate limiting**: The free tier has limits (15-60 requests/minute). Consider adding delays between repos if needed
128
+ * **"Failed to create release"**: Ensure `GITHUB_TOKEN` has `repo` scope permissions
129
+
130
+ ### Docker Cron
131
+
132
+ There's a docker container you can use to run this on a cron. [Fits nicely into a orange pi.](https://mikebian.co/pi-hole-tailscale-and-docker-on-an-orange-pi/)
133
+
134
+ Check out [docker-compose.yml](./docker-compose.yml) for an example, or `git pull ghcr.io/iloveitaly/github-overlord:latest`.
135
+
136
+ ---
137
+
138
+ *This project was created from [iloveitaly/python-package-template](https://github.com/iloveitaly/python-package-template)*
@@ -0,0 +1,111 @@
1
+ [![Release Notes](https://img.shields.io/github/release/iloveitaly/github-overlord)](https://github.com/iloveitaly/github-overlord/releases)
2
+ [![Downloads](https://static.pepy.tech/badge/github-overlord/month)](https://pepy.tech/project/github-overlord)
3
+ [![Python Versions](https://img.shields.io/pypi/pyversions/github-overlord)](https://pypi.org/project/github-overlord)
4
+ ![GitHub CI Status](https://github.com/iloveitaly/github-overlord/actions/workflows/build_and_publish.yml/badge.svg)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ # GitHub Overlord
8
+
9
+ GitHub Overlord is a Python script that does a couple things to help manage open source projects on GitHub:
10
+
11
+ * Automatically merges Dependabot PRs in public repositories that have passed CI checks.
12
+ * Comment on PRs that are going to automatically be marked as stale
13
+ * Removes notifications from bot-authored PRs, Release Please PRs, self-authored PR creations without external activity, PRs merged by you, PRs closed by you, PRs approved by you that are now merged, notifications older than two months, and releases on repos you control
14
+ * Automatically creates releases for repositories based on LLM analysis of recent commits
15
+
16
+ This simple project has also given me the chance to iterate on my [nixpacks github actions project](https://github.com/iloveitaly/github-action-nixpacks).
17
+
18
+ ## Installation
19
+
20
+ ```shell
21
+ pip install github-overlord
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ```shell
27
+ Usage: github-overlord [OPTIONS] COMMAND [ARGS]...
28
+
29
+ Options:
30
+ --help Show this message and exit.
31
+
32
+ Commands:
33
+ generate-releases Check repositories for release readiness using LLM analysis
34
+ dependabot Automatically merge dependabot PRs in public repos that...
35
+ keep-alive-prs Detect when a bot is about to close a PR for no good reason
36
+ notifications Look at notifications and mark them as read
37
+ ```
38
+
39
+ ### Automatic Release Creation
40
+
41
+ The `generate-releases` command uses LLM analysis (via [Pydantic AI](https://ai.pydantic.dev/)) to determine when repositories are ready for a new release. Both `generate-releases` and `keep-alive-prs` share the same unified AI model configuration (defaulting to Google Gemini `gemini-3.8-flash`).
42
+
43
+ This is particularly useful for template repositories, starter projects, etc that don't have automated release workflows and aren't versioned for whatever reason.
44
+
45
+ I have a bunch of these and I wanted an easy way to let the world know when I build something interesting in them.
46
+
47
+ **Usage:**
48
+
49
+ ```shell
50
+ # Check all repos with a specific topic
51
+ github-overlord generate-releases --topic auto-release
52
+
53
+ # Check a single repository
54
+ github-overlord generate-releases --repo owner/repo-name
55
+
56
+ # Dry run (see what would happen without creating releases)
57
+ github-overlord generate-releases --topic auto-release --dry-run
58
+ ```
59
+
60
+ **Requirements & Configuration:**
61
+
62
+ * `GITHUB_TOKEN` - GitHub token with repo write permissions
63
+ * `GITHUB_OVERLORD_AI_KEY` - API key for the AI provider (or provider-specific `GOOGLE_API_KEY`, `OPENAI_API_KEY`, etc.)
64
+ * `GITHUB_OVERLORD_MODEL` - (Optional) AI model override (e.g. `gemini-3.8-flash`, `openai:gpt-4o`). Defaults to `gemini-3.8-flash`.
65
+ * `--topic` flag or `RELEASE_CHECKER_TOPIC` - Topic to filter repositories (required unless using `--repo`)
66
+ * `--repo` flag or `RELEASE_CHECKER_REPO` - Single repository to process (useful for testing)
67
+ * `RELEASE_CHECKER_MIN_GAP` - Minimum time between releases for the same repo (defaults to `2w`, e.g. `14d`, `48h`)
68
+
69
+ **How it works:**
70
+
71
+ 1. Finds repositories matching the specified topic
72
+ 2. For each repo, gets commits since the last release (or since repo creation if no releases)
73
+ 3. Analyzes up to the last 50 commits using the configured AI model (defaulting to `gemini-3.8-flash`) to determine if a release is warranted
74
+ 4. If the LLM recommends a release, automatically creates one with:
75
+
76
+ * Auto-incremented semantic version (patch/minor/major based on changes)
77
+ * AI-generated release notes highlighting key changes
78
+ * Link to full changelog
79
+
80
+ **Scheduling:**
81
+ To run this weekly, set the `SCHEDULE` environment variable:
82
+
83
+ ```bash
84
+ # Run every Monday at 9 AM
85
+ export SCHEDULE="0 9 * * 1"
86
+ export RELEASE_CHECKER_TOPIC="template"
87
+ # Or, to test a single repo on the schedule:
88
+ # export RELEASE_CHECKER_REPO="owner/repo-name"
89
+ export GITHUB_TOKEN="your-token"
90
+ export GITHUB_OVERLORD_AI_KEY="your-api-key"
91
+
92
+ # All CLI commands will run on this schedule
93
+ python main.py
94
+ ```
95
+
96
+ **Troubleshooting:**
97
+
98
+ * **"No repositories found with topic"**: Make sure your repos have the correct topic tag in GitHub settings
99
+ * **"API key environment variable is required"**: Set `GITHUB_OVERLORD_AI_KEY` (or `GOOGLE_API_KEY` for the default Gemini model). Get a free Gemini API key from [ai.google.dev](https://ai.google.dev/)
100
+ * **Rate limiting**: The free tier has limits (15-60 requests/minute). Consider adding delays between repos if needed
101
+ * **"Failed to create release"**: Ensure `GITHUB_TOKEN` has `repo` scope permissions
102
+
103
+ ### Docker Cron
104
+
105
+ There's a docker container you can use to run this on a cron. [Fits nicely into a orange pi.](https://mikebian.co/pi-hole-tailscale-and-docker-on-an-orange-pi/)
106
+
107
+ Check out [docker-compose.yml](./docker-compose.yml) for an example, or `git pull ghcr.io/iloveitaly/github-overlord:latest`.
108
+
109
+ ---
110
+
111
+ *This project was created from [iloveitaly/python-package-template](https://github.com/iloveitaly/python-package-template)*
@@ -0,0 +1,211 @@
1
+ import os
2
+
3
+ import click
4
+ from github import Github
5
+
6
+ import github_overlord.patch # noqa: F401
7
+
8
+ from .ai import get_expected_ai_key_var, is_ai_key_configured
9
+ from .dependabot import dependabot
10
+ from .notifications import notifications
11
+ from .release_checker import check_repo_for_release
12
+ from .stale_commenter import inspect_stale_prs
13
+ from .utils import extract_repo_reference_from_github_url, log
14
+ from .version import __version__
15
+
16
+
17
+ def _ensure_ai_key_configured(command_action: str) -> None:
18
+ if not is_ai_key_configured():
19
+ expected_var = get_expected_ai_key_var()
20
+ raise click.ClickException(
21
+ click.style(
22
+ f"{expected_var} (or GITHUB_OVERLORD_AI_KEY) environment variable is required to {command_action}",
23
+ fg="red",
24
+ )
25
+ )
26
+
27
+
28
+ @click.group()
29
+ @click.version_option(version=__version__)
30
+ def cli():
31
+ """
32
+ GitHub Overlord is a tool to help manage annoying tasks across your GitHub repositories. Some of this could be done
33
+ by GitHub Actions, but this eliminates the need to carefully configure GH actions for each repo.
34
+ """
35
+
36
+
37
+ @click.command()
38
+ @click.option(
39
+ "--token",
40
+ help="GitHub token, can also be set via GITHUB_TOKEN",
41
+ default=os.getenv("GITHUB_TOKEN"),
42
+ )
43
+ @click.option("--dry-run", is_flag=True, help="Run script without creating comments")
44
+ @click.option("--repo", help="Only process a single repository")
45
+ def keep_alive_prs(token, dry_run, repo):
46
+ """
47
+ Detect when a bot is about to close a PR for no good reason and make a comment to keep it alive
48
+ """
49
+
50
+ if not token:
51
+ raise click.ClickException(
52
+ click.style("GITHUB_TOKEN environment variable is required", fg="red")
53
+ )
54
+
55
+ _ensure_ai_key_configured("run keep-alive-prs")
56
+
57
+ log.info("checking for stale PRs")
58
+
59
+ github = Github(token)
60
+ user = github.get_user()
61
+ login = user.login
62
+
63
+ repo = extract_repo_reference_from_github_url(repo)
64
+
65
+ result = inspect_stale_prs(github, login, dry_run, repo)
66
+ if dry_run:
67
+ log.info(
68
+ "stale PR check complete",
69
+ dry_run=True,
70
+ prs_inspected=result.inspected,
71
+ would_keep_alive=result.kept_alive,
72
+ skipped=result.skipped,
73
+ failed=result.failed,
74
+ )
75
+ return
76
+
77
+ log.info(
78
+ "stale PR check complete",
79
+ prs_inspected=result.inspected,
80
+ kept_alive=result.kept_alive,
81
+ skipped=result.skipped,
82
+ failed=result.failed,
83
+ )
84
+
85
+
86
+ @click.command(name="generate-releases")
87
+ @click.option("--dry-run", is_flag=True, help="Run script without creating releases")
88
+ @click.option(
89
+ "--topic",
90
+ help="Only process repos with this topic (can also be set via RELEASE_CHECKER_TOPIC)",
91
+ default=os.getenv("RELEASE_CHECKER_TOPIC"),
92
+ )
93
+ @click.option(
94
+ "--repo",
95
+ help="Only process a single repository (can also be set via RELEASE_CHECKER_REPO)",
96
+ default=os.getenv("RELEASE_CHECKER_REPO"),
97
+ )
98
+ @click.option(
99
+ "--max-releases",
100
+ "-m",
101
+ type=int,
102
+ default=lambda: int(os.getenv("RELEASE_CHECKER_MAX_RELEASES", "1")),
103
+ show_default="1",
104
+ help="Maximum number of releases to create in a single run (0 for unlimited)",
105
+ )
106
+ def generate_releases(dry_run, topic, repo, max_releases):
107
+ """
108
+ Check repositories for release readiness using LLM analysis and create releases when appropriate
109
+ """
110
+
111
+ token = os.getenv("GITHUB_TOKEN")
112
+ if not token:
113
+ raise click.ClickException(
114
+ click.style("GITHUB_TOKEN environment variable is required", fg="red")
115
+ )
116
+
117
+ _ensure_ai_key_configured("use generate-releases")
118
+
119
+ log.info("checking repositories for release readiness")
120
+
121
+ repo = extract_repo_reference_from_github_url(repo)
122
+
123
+ if repo:
124
+ g = Github(token)
125
+ result = check_repo_for_release(g.get_repo(repo), dry_run)
126
+ if result["created"]:
127
+ log.info("release check complete - created 1 release", dry_run=dry_run)
128
+ elif result["failed"]:
129
+ log.info(
130
+ "release check complete - failed to create release", dry_run=dry_run
131
+ )
132
+ else:
133
+ log.info("release check complete - no release needed", dry_run=dry_run)
134
+ return
135
+
136
+ # Topic is required when not specifying a single repo
137
+ if not topic:
138
+ raise click.UsageError(
139
+ "Topic is required when not specifying a single repository (use --topic or set RELEASE_CHECKER_TOPIC)"
140
+ )
141
+
142
+ g = Github(token)
143
+ user = g.get_user()
144
+
145
+ log.info("filtering by topic", topic=topic)
146
+
147
+ # Get all public repos owned by user with the specified topic
148
+ repos = g.search_repositories(
149
+ f"user:{user.login} topic:{topic} fork:false is:public",
150
+ sort="updated",
151
+ order="desc",
152
+ )
153
+
154
+ def _check_repo_with_log(r):
155
+ log.info("checking repo for release", repo=r.full_name, dry_run=dry_run)
156
+ return check_repo_for_release(r, dry_run=dry_run)
157
+
158
+ results = []
159
+ created_count = 0
160
+
161
+ for r in repos:
162
+ if max_releases > 0 and created_count >= max_releases:
163
+ log.info(
164
+ "reached max releases limit for this run",
165
+ max_releases=max_releases,
166
+ )
167
+ break
168
+
169
+ res = _check_repo_with_log(r)
170
+ results.append(res)
171
+ if res["created"]:
172
+ created_count += 1
173
+
174
+ # Check if any repos were found
175
+ if not results:
176
+ log.warning("no repositories found with topic", topic=topic)
177
+ return
178
+
179
+ # Calculate statistics
180
+ total_checked = sum(1 for r in results if r["checked"])
181
+ total_skipped = sum(1 for r in results if r["skipped"])
182
+ total_created = sum(1 for r in results if r["created"])
183
+ total_failed = sum(1 for r in results if r["failed"])
184
+
185
+ # Log summary
186
+ if dry_run:
187
+ log.info(
188
+ "release check complete",
189
+ dry_run=True,
190
+ checked=total_checked,
191
+ would_create=total_created,
192
+ skipped=total_skipped,
193
+ errors=total_failed,
194
+ )
195
+ else:
196
+ log.info(
197
+ "release check complete",
198
+ checked=total_checked,
199
+ created=total_created,
200
+ skipped=total_skipped,
201
+ failed=total_failed,
202
+ )
203
+
204
+
205
+ cli.add_command(dependabot)
206
+ cli.add_command(keep_alive_prs)
207
+ cli.add_command(notifications)
208
+ cli.add_command(generate_releases)
209
+
210
+ if __name__ == "__main__":
211
+ cli()
@@ -0,0 +1,69 @@
1
+ """AI agent configuration for github-overlord."""
2
+
3
+ import os
4
+ from typing import Any
5
+
6
+ from pydantic_ai import Agent, ModelSettings
7
+
8
+ DEFAULT_MODEL = "google:gemini-3.8-flash"
9
+
10
+
11
+ def normalize_model_name(model_name: str) -> str:
12
+ """Ensure provider prefix is present for shorthand model names."""
13
+ cleaned = model_name.strip()
14
+ if ":" in cleaned or "/" in cleaned:
15
+ return cleaned
16
+ if cleaned.startswith("gemini"):
17
+ return f"google:{cleaned}"
18
+ if cleaned.startswith(("gpt", "o1", "o3")):
19
+ return f"openai:{cleaned}"
20
+ if cleaned.startswith("claude"):
21
+ return f"anthropic:{cleaned}"
22
+ return cleaned
23
+
24
+
25
+ def resolve_model_name(model: str | None = None) -> str:
26
+ """Resolve and normalize active model name from argument, env vars, or default."""
27
+ raw_model = model or os.getenv("GITHUB_OVERLORD_MODEL") or DEFAULT_MODEL
28
+ return normalize_model_name(raw_model)
29
+
30
+
31
+ def get_expected_ai_key_var(model: str | None = None) -> str:
32
+ """Return the expected environment variable name for the active model provider."""
33
+ selected_model = resolve_model_name(model)
34
+ provider = selected_model.split(":")[0] if ":" in selected_model else "google"
35
+ return (
36
+ "GOOGLE_API_KEY"
37
+ if provider in ("google", "gemini")
38
+ else f"{provider.upper()}_API_KEY"
39
+ )
40
+
41
+
42
+ def is_ai_key_configured(model: str | None = None) -> bool:
43
+ """Check if an API key is configured for the active model provider."""
44
+ if os.getenv("GITHUB_OVERLORD_AI_KEY"):
45
+ return True
46
+ return bool(os.getenv(get_expected_ai_key_var(model)))
47
+
48
+
49
+ def get_agent(
50
+ model: str | None = None,
51
+ output_type: Any = None,
52
+ system_prompt: str | None = None,
53
+ ) -> Agent[Any, Any]:
54
+ """Create a configured Pydantic AI Agent."""
55
+ selected_model = resolve_model_name(model)
56
+
57
+ # Map generic GITHUB_OVERLORD_AI_KEY to provider-specific env var if not already set
58
+ if generic_key := os.getenv("GITHUB_OVERLORD_AI_KEY"):
59
+ os.environ.setdefault(get_expected_ai_key_var(selected_model), generic_key)
60
+
61
+ kwargs: dict[str, Any] = {}
62
+ if output_type is not None:
63
+ kwargs["output_type"] = output_type
64
+ if system_prompt is not None:
65
+ kwargs["system_prompt"] = system_prompt
66
+ if selected_model.startswith("google:"):
67
+ kwargs["model_settings"] = ModelSettings(thinking="low")
68
+
69
+ return Agent(selected_model, **kwargs)
@@ -1,11 +1,15 @@
1
1
  """Configuration for github-overlord."""
2
+
2
3
  from pathlib import Path
3
4
 
4
5
  import jinja2
5
6
 
6
7
  # Set up paths
7
- ROOT_DIRECTORY = Path(__file__).parent.parent.resolve()
8
- DATA_DIRECTORY = ROOT_DIRECTORY / "data"
8
+ PACKAGE_DIRECTORY = Path(__file__).parent.resolve()
9
+ DATA_DIRECTORY = PACKAGE_DIRECTORY / "data"
10
+ if not DATA_DIRECTORY.exists():
11
+ DATA_DIRECTORY = PACKAGE_DIRECTORY.parent / "data"
12
+
9
13
  RELEASE_ANALYSIS_PROMPT_TEMPLATE = DATA_DIRECTORY / "release_analysis_prompt.j2"
10
14
 
11
15
  # Jinja2 environment for templates
@@ -13,5 +17,5 @@ JINJA_ENV = jinja2.Environment(
13
17
  loader=jinja2.FileSystemLoader(searchpath=str(DATA_DIRECTORY)),
14
18
  autoescape=False, # No HTML escaping needed for prompts
15
19
  trim_blocks=True,
16
- lstrip_blocks=True
20
+ lstrip_blocks=True,
17
21
  )
@@ -0,0 +1,50 @@
1
+ You are analyzing commits for an open-source project to determine if a new release should be created.
2
+
3
+ Consider these factors, in order of importance:
4
+
5
+ 1. Number of commits (more commits = more likely to release, but even 1-2 significant commits may warrant a release)
6
+ 2. Type of changes (features, bug fixes, refactoring, docs, tests, dependencies; new features and bug fixes are more likely to warrant a release)
7
+ 3. Impact of changes (major features vs minor tweaks)
8
+ 4. Time since last release (longer time = more likely, but do not weight this heavily)
9
+
10
+ Guidelines for `decision`:
11
+
12
+ - "yes" = clear value in creating a release (new features, important fixes, meaningful updates)
13
+ - "no" = minimal changes (typos, minor docs, CI tweaks only)
14
+ - "maybe" = borderline case (some value but not urgent)
15
+ - For dependency updates: patch bump
16
+ - For bug fixes: patch bump
17
+ - For new features: minor bump
18
+ - For breaking changes: major bump
19
+
20
+ Guidelines for `release_notes`:
21
+
22
+ - Write a markdown changelog suitable for a GitHub release
23
+ - Use markdown headers, lists, and formatting
24
+ - Be concise and avoid adjectives
25
+ - Focus on user-facing changes and impacts. Do not include internal dev tooling, documentation, build system, package/dependency updates, etc updates.
26
+ - Organize by type of change (Features, Bug Fixes, etc.) when there are more than a handful of changes.
27
+
28
+ Example format:
29
+
30
+ ```markdown
31
+ ## What's Changed
32
+
33
+ ### Features
34
+ - Added support for Python 3.12
35
+ - New configuration option for custom timeouts
36
+
37
+ ### Bug Fixes
38
+ - Fixed authentication bug when using OAuth tokens
39
+ - Resolved memory leak in background worker
40
+
41
+ ### Performance
42
+ - Improved commit analysis by 40%
43
+ ```
44
+
45
+ Repository: {{ repo_name }}
46
+ {{ last_release_info }}
47
+ Number of commits: {{ commit_count }}
48
+
49
+ Commits:
50
+ {{ commit_summary }}