Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 25 additions & 20 deletions scripts/check_version_bump.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,20 +92,14 @@ def get_diff_stats(base_ref: str, dir_name: str) -> dict | None:
# --- file-level stats (added / deleted) ---
for diff_filter, key_suffix in [("A", "added"), ("D", "deleted")]:
result = subprocess.run(
[
"git", "diff", "--name-only", f"--diff-filter={diff_filter}",
base_ref, "HEAD", "--", f"{dir_name}/"
],
["git", "diff", "--name-only", f"--diff-filter={diff_filter}", base_ref, "HEAD", "--", f"{dir_name}/"],
capture_output=True,
text=True,
)
if result.returncode != 0:
return None
files = [f for f in result.stdout.splitlines() if f.strip()]
py_files = [
f for f in files
if f.endswith(".py") and "/tests/" not in f and not f.endswith("test_.py")
]
py_files = [f for f in files if f.endswith(".py") and "/tests/" not in f and not f.endswith("test_.py")]
if key_suffix == "added":
py_files_added = len(py_files)
else:
Expand Down Expand Up @@ -143,13 +137,9 @@ def get_diff_stats(base_ref: str, dir_name: str) -> dict | None:
# --- check if only tests / docs changed ---
all_changed = get_changed_files(base_ref, dir_name) or []
non_test_doc = [
f for f in all_changed
if not (
"/tests/" in f
or f.endswith("README.md")
or f.endswith(".md")
or f.endswith("requirements.txt")
)
f
for f in all_changed
if not ("/tests/" in f or f.endswith("README.md") or f.endswith(".md") or f.endswith("requirements.txt"))
]
# config.json is handled separately so exclude it here
non_test_doc = [f for f in non_test_doc if not f.endswith("config.json")]
Expand All @@ -167,8 +157,12 @@ def get_diff_stats(base_ref: str, dir_name: str) -> dict | None:


def recommend_bump(
base_config: dict, current_config: dict, changed_files: list[str], dir_name: str,
*, base_ref: str = "",
base_config: dict,
current_config: dict,
changed_files: list[str],
dir_name: str,
*,
base_ref: str = "",
) -> str:
"""Recommend major, minor, or patch based on what changed.

Expand Down Expand Up @@ -216,6 +210,10 @@ def recommend_bump(
if base_ref:
stats = get_diff_stats(base_ref, dir_name)
if stats:
# Only tests, docs, or requirements changed — always patch
if stats["only_tests_docs"]:
return "patch"

# Major: source files or public symbols removed
if stats["py_files_deleted"] > 0:
return "major"
Expand Down Expand Up @@ -294,6 +292,15 @@ def check_version_bump(base_ref: str, dirs: list[str]) -> int:
# No changes in this dir — nothing to check
continue

# If only tests, docs, or requirements changed, version bump is optional
diff_stats = get_diff_stats(base_ref, d)
if diff_stats and diff_stats["only_tests_docs"] and current_version_str == base_version_str:
actions_same = base_config.get("actions") == current_config.get("actions")
auth_same = base_config.get("auth") == current_config.get("auth")
if actions_same and auth_same:
print(f"✅ {d}: No version bump needed (only tests/docs changed)")
continue

# Only config.json changed with no version diff is still a problem,
# but if nothing meaningful changed we skip
if current_version_str == base_version_str:
Expand Down Expand Up @@ -348,9 +355,7 @@ def check_version_bump(base_ref: str, dirs: list[str]) -> int:
return 0


def _detect_bump_level(
base: tuple[int, ...], current: tuple[int, ...]
) -> str:
def _detect_bump_level(base: tuple[int, ...], current: tuple[int, ...]) -> str:
"""Detect whether the version change was major, minor, or patch."""
if current[0] > base[0]:
return "major"
Expand Down
20 changes: 18 additions & 2 deletions scripts/docs/check_version_bump.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ flowchart TD
E -->|Yes — existing integration| I[Compare versions]
I --> J{Files changed?}
J -->|No| G
J -->|Yes| K{Version incremented?}
J -->|Yes| TD{Only tests/docs?}
TD -->|Yes| G
TD -->|No| K{Version incremented?}
K -->|Same| L[Fail + recommend bump level]
K -->|Decreased| M[Fail]
K -->|Incremented| N{Bump level sufficient?}
Expand Down Expand Up @@ -118,6 +120,10 @@ The script recommends a bump level by inspecting both config.json changes and co
| New `.py` source files added (excluding tests) | **minor** |
| New `class` or `def` definitions added | **minor** |

### Test/doc-only changes

If every changed file is in `tests/`, a `.md` file, or `requirements.txt` (and the config is unchanged), the version check is **skipped entirely** — no bump is required. This allows adding or updating tests, docs, and dependencies without touching the version number.

### Fallback

If none of the above signals match, the recommendation defaults to **patch** (bug fixes, docs, dependency updates, test changes).
Expand Down Expand Up @@ -164,6 +170,16 @@ The recommendation is advisory — bumping at a lower level than recommended pro
========================================
```

### When only tests/docs changed (no bump needed):

```
✅ my-integration: No version bump needed (only tests/docs changed)

========================================
✅ VERSION CHECK PASSED
========================================
```

### New integration with valid version:

```
Expand Down Expand Up @@ -194,7 +210,7 @@ The recommendation is advisory — bumping at a lower level than recommended pro
| Files changed but version unchanged | ❌ Fails with recommendation |
| Version decreased | ❌ Fails |
| Bump level lower than recommended | ✅ Passes with ⚠️ warning |
| Only test/doc files changed, version unchanged | ❌ Fails (patch bump recommended) |
| Only test/doc files changed, version unchanged | ✅ Passes (no bump needed) |
| No files changed in directory | ✅ Passes (nothing to check) |
| Directory doesn't exist on disk | ⚠️ Skipped with warning |
| No `config.json` in directory | ⚠️ Skipped with warning |
Expand Down
Loading